separate frame specific data
This commit is contained in:
parent
4283dd9926
commit
acaf58cf3c
@ -1,4 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const build_options = @import("build_options");
|
||||||
|
const log = std.log.scoped(.engine);
|
||||||
|
|
||||||
const InputSystem = @import("./input.zig");
|
const InputSystem = @import("./input.zig");
|
||||||
const KeyCode = InputSystem.KeyCode;
|
const KeyCode = InputSystem.KeyCode;
|
||||||
@ -8,6 +10,16 @@ const AudioSystem = @import("./audio/root.zig");
|
|||||||
const AudioData = AudioSystem.Data;
|
const AudioData = AudioSystem.Data;
|
||||||
const AudioCommand = AudioSystem.Command;
|
const AudioCommand = AudioSystem.Command;
|
||||||
|
|
||||||
|
const GraphicsSystem = @import("./graphics.zig");
|
||||||
|
const GraphicsCommand = GraphicsSystem.Command;
|
||||||
|
const Font = GraphicsSystem.Font;
|
||||||
|
|
||||||
|
const Math = @import("./math.zig");
|
||||||
|
const Rect = Math.Rect;
|
||||||
|
const Vec4 = Math.Vec4;
|
||||||
|
const Vec2 = Math.Vec2;
|
||||||
|
const rgb = Math.rgb;
|
||||||
|
|
||||||
pub const Nanoseconds = u64;
|
pub const Nanoseconds = u64;
|
||||||
|
|
||||||
const Frame = @This();
|
const Frame = @This();
|
||||||
@ -71,20 +83,42 @@ pub const Audio = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Graphics = struct {
|
||||||
|
clear_color: Vec4,
|
||||||
|
screen_size: Vec2,
|
||||||
|
canvas_size: ?Vec2,
|
||||||
|
|
||||||
|
scissor_stack: std.ArrayList(Rect),
|
||||||
|
commands: std.ArrayList(GraphicsCommand),
|
||||||
|
|
||||||
|
pub const empty = Graphics{
|
||||||
|
.clear_color = rgb(0, 0, 0),
|
||||||
|
.screen_size = .init(0, 0),
|
||||||
|
.canvas_size = null,
|
||||||
|
.scissor_stack = .empty,
|
||||||
|
.commands = .empty
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
arena: std.heap.ArenaAllocator,
|
arena: std.heap.ArenaAllocator,
|
||||||
|
|
||||||
time_ns: Nanoseconds,
|
time_ns: Nanoseconds,
|
||||||
dt_ns: Nanoseconds,
|
dt_ns: Nanoseconds,
|
||||||
input: Input,
|
input: Input,
|
||||||
audio: Audio,
|
audio: Audio,
|
||||||
|
graphics: Graphics,
|
||||||
|
|
||||||
pub fn init(gpa: std.mem.Allocator) Frame {
|
show_debug: bool,
|
||||||
return Frame{
|
|
||||||
|
pub fn init(self: *Frame, gpa: std.mem.Allocator) void {
|
||||||
|
self.* = Frame{
|
||||||
.arena = std.heap.ArenaAllocator.init(gpa),
|
.arena = std.heap.ArenaAllocator.init(gpa),
|
||||||
.time_ns = 0,
|
.time_ns = 0,
|
||||||
.dt_ns = 0,
|
.dt_ns = 0,
|
||||||
.input = .empty,
|
.input = .empty,
|
||||||
.audio = .empty
|
.audio = .empty,
|
||||||
|
.graphics = .empty,
|
||||||
|
.show_debug = false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,10 +166,115 @@ pub const PlayAudioOptions = struct {
|
|||||||
id: AudioData.Id,
|
id: AudioData.Id,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn pushAudioCommand(self: *Frame, command: AudioCommand) void {
|
||||||
|
const arena = self.arena.allocator();
|
||||||
|
|
||||||
|
self.audio.commands.append(arena, command) catch |e| {
|
||||||
|
log.warn("Failed to play audio: {}", .{e});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pushGraphicsCommand(self: *Frame, command: GraphicsCommand) void {
|
||||||
|
const arena = self.arena.allocator();
|
||||||
|
|
||||||
|
self.graphics.commands.append(arena, command) catch |e|{
|
||||||
|
log.warn("Failed to push graphics command: {}", .{e});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn playAudio(self: *Frame, options: PlayAudioOptions) !void {
|
pub fn playAudio(self: *Frame, options: PlayAudioOptions) !void {
|
||||||
try self.audio.commands.append(self.arena.allocator(), .{
|
self.pushAudioCommand(.{
|
||||||
.play = .{
|
.play = .{
|
||||||
.data_id = options.id
|
.data_id = options.id
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pushScissor(self: *Frame, rect: Rect) void {
|
||||||
|
const arena = self.arena.allocator();
|
||||||
|
self.graphics.scissor_stack.append(arena, rect) catch |e| {
|
||||||
|
log.warn("Failed to push scissor region: {}", .{e});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.pushGraphicsCommand(.{
|
||||||
|
.set_scissor = rect
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn popScissor(self: *Frame) void {
|
||||||
|
_ = self.graphics.scissor_stack.pop().?;
|
||||||
|
const rect = self.graphics.scissor_stack.getLast();
|
||||||
|
|
||||||
|
self.pushGraphicsCommand(.{
|
||||||
|
.set_scissor = rect
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawRectangle(self: *Frame, pos: Vec2, size: Vec2, color: Vec4) void {
|
||||||
|
self.pushGraphicsCommand(.{
|
||||||
|
.draw_rectangle = .{
|
||||||
|
.pos = pos,
|
||||||
|
.size = size,
|
||||||
|
.color = color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawLine(self: *Frame, pos1: Vec2, pos2: Vec2, color: Vec4, width: f32) void {
|
||||||
|
self.pushGraphicsCommand(.{
|
||||||
|
.draw_line = .{
|
||||||
|
.pos1 = pos1,
|
||||||
|
.pos2 = pos2,
|
||||||
|
.width = width,
|
||||||
|
.color = color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawRectanglOutline(self: *Frame, pos: Vec2, size: Vec2, color: Vec4, width: f32) void {
|
||||||
|
// TODO: Don't use line segments
|
||||||
|
self.drawLine(pos, pos.add(.{ .x = size.x, .y = 0 }), color, width);
|
||||||
|
self.drawLine(pos, pos.add(.{ .x = 0, .y = size.y }), color, width);
|
||||||
|
self.drawLine(pos.add(.{ .x = 0, .y = size.y }), pos.add(size), color, width);
|
||||||
|
self.drawLine(pos.add(.{ .x = size.x, .y = 0 }), pos.add(size), color, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const DrawTextOptions = struct {
|
||||||
|
font: Font.Id,
|
||||||
|
size: f32 = 16,
|
||||||
|
color: Vec4 = rgb(255, 255, 255),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn drawText(self: *Frame, position: Vec2, text: []const u8, opts: DrawTextOptions) void {
|
||||||
|
const arena = self.arena.allocator();
|
||||||
|
const text_dupe = arena.dupe(u8, text) catch |e| {
|
||||||
|
log.warn("Failed to draw text: {}", .{e});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.pushGraphicsCommand(.{
|
||||||
|
.draw_text = .{
|
||||||
|
.pos = position,
|
||||||
|
.text = text_dupe,
|
||||||
|
.size = opts.size,
|
||||||
|
.font = opts.font,
|
||||||
|
.color = opts.color,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pushTransform(self: *Frame, translation: Vec2, scale: Vec2) void {
|
||||||
|
self.pushGraphicsCommand(.{
|
||||||
|
.push_transformation = .{
|
||||||
|
.translation = translation,
|
||||||
|
.scale = scale
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn popTransform(self: *Frame) void {
|
||||||
|
self.pushGraphicsCommand(.{
|
||||||
|
.pop_transformation = {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@ -21,6 +21,8 @@ const tracy = @import("tracy");
|
|||||||
const fontstash = @import("./fontstash/root.zig");
|
const fontstash = @import("./fontstash/root.zig");
|
||||||
pub const Font = fontstash.Font;
|
pub const Font = fontstash.Font;
|
||||||
|
|
||||||
|
const GraphicsFrame = @import("./frame.zig").Graphics;
|
||||||
|
|
||||||
// TODO: Seems that there is a vertical jitter bug when resizing a window in OpenGL. Seems like a driver bug.
|
// TODO: Seems that there is a vertical jitter bug when resizing a window in OpenGL. Seems like a driver bug.
|
||||||
// From other peoples research it seems that disabling vsync when a resize event occurs fixes it.
|
// From other peoples research it seems that disabling vsync when a resize event occurs fixes it.
|
||||||
// Maybe a patch for sokol could be made?
|
// Maybe a patch for sokol could be made?
|
||||||
@ -39,30 +41,42 @@ const Options = struct {
|
|||||||
imgui_font: ?ImguiFont = null
|
imgui_font: ?ImguiFont = null
|
||||||
};
|
};
|
||||||
|
|
||||||
const DrawFrame = struct {
|
pub const Command = union(enum) {
|
||||||
screen_size: Vec2 = Vec2.zero,
|
set_scissor: Rect,
|
||||||
bg_color: Vec4 = rgb(0, 0, 0),
|
draw_rectangle: struct {
|
||||||
|
pos: Vec2,
|
||||||
scissor_stack_buffer: [32]Rect = undefined,
|
size: Vec2,
|
||||||
scissor_stack: std.ArrayListUnmanaged(Rect) = .empty,
|
color: Vec4
|
||||||
|
},
|
||||||
fn init(self: *DrawFrame) void {
|
draw_line: struct {
|
||||||
self.* = DrawFrame{
|
pos1: Vec2,
|
||||||
.scissor_stack = .initBuffer(&self.scissor_stack_buffer)
|
pos2: Vec2,
|
||||||
};
|
color: Vec4,
|
||||||
}
|
width: f32
|
||||||
|
},
|
||||||
|
draw_text: struct {
|
||||||
|
pos: Vec2,
|
||||||
|
text: []const u8,
|
||||||
|
font: Font.Id,
|
||||||
|
size: f32,
|
||||||
|
color: Vec4,
|
||||||
|
},
|
||||||
|
push_transformation: struct {
|
||||||
|
translation: Vec2,
|
||||||
|
scale: Vec2
|
||||||
|
},
|
||||||
|
pop_transformation: void
|
||||||
};
|
};
|
||||||
|
|
||||||
var draw_frame: DrawFrame = undefined;
|
|
||||||
var main_pipeline: sgl.Pipeline = .{};
|
var main_pipeline: sgl.Pipeline = .{};
|
||||||
var linear_sampler: sg.Sampler = .{};
|
var linear_sampler: sg.Sampler = .{};
|
||||||
var nearest_sampler: sg.Sampler = .{};
|
var nearest_sampler: sg.Sampler = .{};
|
||||||
var font_context: fontstash.Context = undefined;
|
var font_context: fontstash.Context = undefined;
|
||||||
pub var font_resolution_scale: f32 = 1;
|
|
||||||
|
var scale_stack_buffer: [32]Vec2 = undefined;
|
||||||
|
var scale_stack: std.ArrayList(Vec2) = .empty;
|
||||||
|
|
||||||
pub fn init(options: Options) !void {
|
pub fn init(options: Options) !void {
|
||||||
draw_frame.init();
|
|
||||||
|
|
||||||
sg.setup(.{
|
sg.setup(.{
|
||||||
.logger = options.logger,
|
.logger = options.logger,
|
||||||
.environment = sglue.environment(),
|
.environment = sglue.environment(),
|
||||||
@ -140,43 +154,103 @@ pub fn deinit() void {
|
|||||||
sg.shutdown();
|
sg.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn drawCommand(command: Command) void {
|
||||||
|
switch(command) {
|
||||||
|
.push_transformation => |opts| {
|
||||||
|
pushTransform(opts.translation, opts.scale);
|
||||||
|
// font_resolution_scale = font_resolution_scale.multiply(opts.scale);
|
||||||
|
},
|
||||||
|
.pop_transformation => {
|
||||||
|
popTransform();
|
||||||
|
},
|
||||||
|
.draw_rectangle => |opts| {
|
||||||
|
drawRectangle(opts.pos, opts.size, opts.color);
|
||||||
|
},
|
||||||
|
.set_scissor => |opts| {
|
||||||
|
sgl.scissorRectf(
|
||||||
|
opts.pos.x,
|
||||||
|
opts.pos.y,
|
||||||
|
opts.size.x,
|
||||||
|
opts.size.y,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
},
|
||||||
|
.draw_line => |opts| {
|
||||||
|
drawLine(
|
||||||
|
opts.pos1,
|
||||||
|
opts.pos2,
|
||||||
|
opts.color,
|
||||||
|
opts.width
|
||||||
|
);
|
||||||
|
},
|
||||||
|
.draw_text => |opts| {
|
||||||
|
const font_resolution_scale = scale_stack.getLast();
|
||||||
|
|
||||||
|
sgl.pushMatrix();
|
||||||
|
defer sgl.popMatrix();
|
||||||
|
|
||||||
|
sgl.scale(1/font_resolution_scale.x, 1/font_resolution_scale.y, 1);
|
||||||
|
|
||||||
|
font_context.setFont(opts.font);
|
||||||
|
font_context.setSize(opts.size * font_resolution_scale.y);
|
||||||
|
font_context.setAlign(.{ .x = .left, .y = .top });
|
||||||
|
font_context.setSpacing(0);
|
||||||
|
|
||||||
|
const r: u8 = @intFromFloat(opts.color.x * 255);
|
||||||
|
const g: u8 = @intFromFloat(opts.color.y * 255);
|
||||||
|
const b: u8 = @intFromFloat(opts.color.z * 255);
|
||||||
|
const a: u8 = @intFromFloat(opts.color.w * 255);
|
||||||
|
const color: u32 = r | (@as(u32, g) << 8) | (@as(u32, b) << 16) | (@as(u32, a) << 24);
|
||||||
|
font_context.setColor(color);
|
||||||
|
font_context.drawText(
|
||||||
|
opts.pos.x * font_resolution_scale.x,
|
||||||
|
opts.pos.y * font_resolution_scale.y,
|
||||||
|
opts.text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawCommands(commands: []const Command) void {
|
||||||
|
for (commands) |command| {
|
||||||
|
drawCommand(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn beginFrame() void {
|
pub fn beginFrame() void {
|
||||||
const zone = tracy.initZone(@src(), .{ });
|
const zone = tracy.initZone(@src(), .{ });
|
||||||
defer zone.deinit();
|
defer zone.deinit();
|
||||||
|
|
||||||
draw_frame.init();
|
|
||||||
draw_frame.screen_size = Vec2.init(sapp.widthf(), sapp.heightf());
|
|
||||||
draw_frame.scissor_stack.appendAssumeCapacity(Rect.init(0, 0, sapp.widthf(), sapp.heightf()));
|
|
||||||
|
|
||||||
imgui.newFrame(.{
|
imgui.newFrame(.{
|
||||||
.width = @intFromFloat(draw_frame.screen_size.x),
|
.width = sapp.width(),
|
||||||
.height = @intFromFloat(draw_frame.screen_size.y),
|
.height = sapp.height(),
|
||||||
.delta_time = sapp.frameDuration(),
|
.delta_time = sapp.frameDuration(),
|
||||||
.dpi_scale = sapp.dpiScale()
|
.dpi_scale = sapp.dpiScale()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
scale_stack = .initBuffer(&scale_stack_buffer);
|
||||||
|
scale_stack.appendAssumeCapacity(.init(1, 1));
|
||||||
|
|
||||||
font_context.clearState();
|
font_context.clearState();
|
||||||
sgl.defaults();
|
sgl.defaults();
|
||||||
sgl.matrixModeProjection();
|
sgl.matrixModeProjection();
|
||||||
sgl.ortho(0, draw_frame.screen_size.x, draw_frame.screen_size.y, 0, -1, 1);
|
sgl.ortho(0, sapp.widthf(), sapp.heightf(), 0, -1, 1);
|
||||||
sgl.loadPipeline(main_pipeline);
|
sgl.loadPipeline(main_pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn endFrame() void {
|
pub fn endFrame(clear_color: Vec4) void {
|
||||||
const zone = tracy.initZone(@src(), .{ });
|
const zone = tracy.initZone(@src(), .{ });
|
||||||
defer zone.deinit();
|
defer zone.deinit();
|
||||||
|
|
||||||
assert(draw_frame.scissor_stack.items.len == 1);
|
|
||||||
|
|
||||||
var pass_action: sg.PassAction = .{};
|
var pass_action: sg.PassAction = .{};
|
||||||
|
|
||||||
pass_action.colors[0] = sg.ColorAttachmentAction{
|
pass_action.colors[0] = sg.ColorAttachmentAction{
|
||||||
.load_action = .CLEAR,
|
.load_action = .CLEAR,
|
||||||
.clear_value = .{
|
.clear_value = .{
|
||||||
.r = draw_frame.bg_color.x,
|
.r = clear_color.x,
|
||||||
.g = draw_frame.bg_color.y,
|
.g = clear_color.y,
|
||||||
.b = draw_frame.bg_color.z,
|
.b = clear_color.z,
|
||||||
.a = draw_frame.bg_color.w
|
.a = clear_color.w
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -196,17 +270,20 @@ pub fn endFrame() void {
|
|||||||
sg.commit();
|
sg.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pushTransform(translation: Vec2, scale: f32) void {
|
pub fn pushTransform(translation: Vec2, scale: Vec2) void {
|
||||||
sgl.pushMatrix();
|
sgl.pushMatrix();
|
||||||
sgl.translate(translation.x, translation.y, 0);
|
sgl.translate(translation.x, translation.y, 0);
|
||||||
sgl.scale(scale, scale, 1);
|
sgl.scale(scale.x, scale.y, 1);
|
||||||
|
|
||||||
|
scale_stack.appendAssumeCapacity(scale_stack.getLast().multiply(scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn popTransform() void {
|
pub fn popTransform() void {
|
||||||
sgl.popMatrix();
|
sgl.popMatrix();
|
||||||
|
_ = scale_stack.pop().?;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawQuad(quad: [4]Vec2, color: Vec4) void {
|
fn drawQuad(quad: [4]Vec2, color: Vec4) void {
|
||||||
sgl.beginQuads();
|
sgl.beginQuads();
|
||||||
defer sgl.end();
|
defer sgl.end();
|
||||||
|
|
||||||
@ -232,17 +309,7 @@ pub fn drawRectangle(pos: Vec2, size: Vec2, color: Vec4) void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawTriangle(tri: [3]Vec2, color: Vec4) void {
|
fn drawLine(from: Vec2, to: Vec2, color: Vec4, width: f32) void {
|
||||||
sgl.beginTriangles();
|
|
||||||
defer sgl.end();
|
|
||||||
|
|
||||||
sgl.c4f(color.x, color.y, color.z, color.w);
|
|
||||||
for (tri) |position| {
|
|
||||||
sgl.v2f(position.x, position.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn drawLine(from: Vec2, to: Vec2, color: Vec4, width: f32) void {
|
|
||||||
const step = to.sub(from).normalized().multiplyScalar(width/2);
|
const step = to.sub(from).normalized().multiplyScalar(width/2);
|
||||||
|
|
||||||
const top_left = from.add(step.rotateLeft90());
|
const top_left = from.add(step.rotateLeft90());
|
||||||
@ -256,55 +323,6 @@ pub fn drawLine(from: Vec2, to: Vec2, color: Vec4, width: f32) void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawRectanglOutline(pos: Vec2, size: Vec2, color: Vec4, width: f32) void {
|
|
||||||
// TODO: Don't use line segments
|
|
||||||
drawLine(pos, pos.add(.{ .x = size.x, .y = 0 }), color, width);
|
|
||||||
drawLine(pos, pos.add(.{ .x = 0, .y = size.y }), color, width);
|
|
||||||
drawLine(pos.add(.{ .x = 0, .y = size.y }), pos.add(size), color, width);
|
|
||||||
drawLine(pos.add(.{ .x = size.x, .y = 0 }), pos.add(size), color, width);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pushScissor(rect: Rect) void {
|
|
||||||
draw_frame.scissor_stack.appendAssumeCapacity(rect);
|
|
||||||
|
|
||||||
sgl.scissorRectf(rect.pos.x, rect.pos.y, rect.size.x, rect.size.y, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn popScissor() void {
|
|
||||||
_ = draw_frame.scissor_stack.pop().?;
|
|
||||||
const rect = draw_frame.scissor_stack.getLast();
|
|
||||||
|
|
||||||
sgl.scissorRectf(rect.pos.x, rect.pos.y, rect.size.x, rect.size.y, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn addFont(name: [*c]const u8, data: []const u8) !Font.Id {
|
pub fn addFont(name: [*c]const u8, data: []const u8) !Font.Id {
|
||||||
return try font_context.addFont(name, data);
|
return try font_context.addFont(name, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const DrawTextOptions = struct {
|
|
||||||
font: Font.Id,
|
|
||||||
size: f32 = 16,
|
|
||||||
color: Vec4 = rgb(255, 255, 255),
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn drawText(position: Vec2, text: []const u8, opts: DrawTextOptions) void {
|
|
||||||
pushTransform(.{ .x = 0, .y = 0}, 1/font_resolution_scale);
|
|
||||||
defer popTransform();
|
|
||||||
|
|
||||||
font_context.setFont(opts.font);
|
|
||||||
font_context.setSize(opts.size * font_resolution_scale);
|
|
||||||
font_context.setAlign(.{ .x = .left, .y = .top });
|
|
||||||
font_context.setSpacing(0);
|
|
||||||
|
|
||||||
const r: u8 = @intFromFloat(opts.color.x * 255);
|
|
||||||
const g: u8 = @intFromFloat(opts.color.y * 255);
|
|
||||||
const b: u8 = @intFromFloat(opts.color.z * 255);
|
|
||||||
const a: u8 = @intFromFloat(opts.color.w * 255);
|
|
||||||
const color: u32 = r | (@as(u32, g) << 8) | (@as(u32, b) << 16) | (@as(u32, a) << 24);
|
|
||||||
font_context.setColor(color);
|
|
||||||
font_context.drawText(
|
|
||||||
position.x * font_resolution_scale,
|
|
||||||
position.y * font_resolution_scale,
|
|
||||||
text
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -109,8 +109,3 @@ pub fn processEvent(frame: *Frame, event: Event) void {
|
|||||||
else => {}
|
else => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn beginFrame(frame: *Frame) void {
|
|
||||||
frame.input.pressed_keys = .initEmpty();
|
|
||||||
frame.input.released_keys = .initEmpty();
|
|
||||||
}
|
|
||||||
|
|||||||
@ -67,7 +67,7 @@ pub fn run(self: *Engine, opts: RunOptions) !void {
|
|||||||
self.allocator = std.heap.smp_allocator;
|
self.allocator = std.heap.smp_allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.frame = .init(self.allocator);
|
self.frame.init(self.allocator);
|
||||||
|
|
||||||
tracy.setThreadName("Main");
|
tracy.setThreadName("Main");
|
||||||
|
|
||||||
@ -147,36 +147,79 @@ fn sokolCleanup(self: *Engine) void {
|
|||||||
fn sokolFrame(self: *Engine) !void {
|
fn sokolFrame(self: *Engine) !void {
|
||||||
tracy.frameMark();
|
tracy.frameMark();
|
||||||
|
|
||||||
const time_passed = self.timePassed();
|
|
||||||
defer self.last_frame_at = time_passed;
|
|
||||||
const dt_ns = time_passed - self.last_frame_at;
|
|
||||||
|
|
||||||
const zone = tracy.initZone(@src(), .{ });
|
const zone = tracy.initZone(@src(), .{ });
|
||||||
defer zone.deinit();
|
defer zone.deinit();
|
||||||
|
|
||||||
Gfx.beginFrame();
|
const now = std.time.Instant.now() catch @panic("Instant.now() unsupported");
|
||||||
defer Gfx.endFrame();
|
const time_passed = now.since(self.started_at);
|
||||||
|
defer self.last_frame_at = time_passed;
|
||||||
|
|
||||||
|
const frame = &self.frame;
|
||||||
|
|
||||||
{
|
{
|
||||||
const window_size: Vec2 = .init(sapp.widthf(), sapp.heightf());
|
_ = frame.arena.reset(.retain_capacity);
|
||||||
const ctx = ScreenScalar.push(window_size, self.game.canvas_size);
|
|
||||||
defer ctx.pop();
|
|
||||||
|
|
||||||
Graphics.font_resolution_scale = ctx.scale;
|
const audio_commands_capacity = frame.audio.commands.capacity;
|
||||||
|
frame.audio = .empty;
|
||||||
|
try frame.audio.commands.ensureTotalCapacity(frame.arena.allocator(), audio_commands_capacity);
|
||||||
|
|
||||||
|
const graphics_commands_capacity = frame.graphics.commands.capacity;
|
||||||
|
const scissor_stack_capacity = frame.graphics.scissor_stack.capacity;
|
||||||
|
frame.graphics = .empty;
|
||||||
|
frame.graphics.screen_size = .init(sapp.widthf(), sapp.heightf());
|
||||||
|
try frame.graphics.commands.ensureTotalCapacity(frame.arena.allocator(), graphics_commands_capacity);
|
||||||
|
try frame.graphics.scissor_stack.ensureTotalCapacity(frame.arena.allocator(), scissor_stack_capacity);
|
||||||
|
frame.pushScissor(.init(0, 0, sapp.widthf(), sapp.heightf()));
|
||||||
|
|
||||||
|
frame.time_ns = time_passed;
|
||||||
|
frame.dt_ns = time_passed - self.last_frame_at;
|
||||||
|
|
||||||
self.frame.time_ns = time_passed;
|
|
||||||
self.frame.dt_ns = dt_ns;
|
|
||||||
try self.game.tick(&self.frame);
|
try self.game.tick(&self.frame);
|
||||||
|
|
||||||
|
frame.input.pressed_keys = .initEmpty();
|
||||||
|
frame.input.released_keys = .initEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.game.debug();
|
{
|
||||||
|
Gfx.beginFrame();
|
||||||
|
defer Gfx.endFrame(frame.graphics.clear_color);
|
||||||
|
|
||||||
Input.beginFrame(&self.frame);
|
{
|
||||||
|
var screen_scaler: ?ScreenScalar = null;
|
||||||
|
if (self.frame.graphics.canvas_size) |canvas_size| {
|
||||||
|
screen_scaler = ScreenScalar.push(self.frame.graphics.screen_size, canvas_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx.drawCommands(frame.graphics.commands.items);
|
||||||
|
|
||||||
|
if (screen_scaler) |ctx| ctx.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame.show_debug) {
|
||||||
|
try self.game.debug();
|
||||||
|
try showDebugWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (frame.audio.commands.items) |command| {
|
||||||
|
try Audio.mixer.commands.push(command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timePassed(self: *Engine) Nanoseconds {
|
fn showDebugWindow() !void {
|
||||||
const now = std.time.Instant.now() catch @panic("Instant.now() unsupported");
|
if (!imgui.beginWindow(.{
|
||||||
return now.since(self.started_at);
|
.name = "Engine",
|
||||||
|
.pos = Vec2.init(240, 20),
|
||||||
|
.size = Vec2.init(200, 200),
|
||||||
|
})) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
defer imgui.endWindow();
|
||||||
|
|
||||||
|
imgui.textFmt("Audio instances: {}/{}\n", .{
|
||||||
|
Audio.mixer.instances.items.len,
|
||||||
|
Audio.mixer.instances.capacity
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sokolEvent(self: *Engine, e_ptr: [*c]const sapp.Event) !bool {
|
fn sokolEvent(self: *Engine, e_ptr: [*c]const sapp.Event) !bool {
|
||||||
|
|||||||
@ -26,7 +26,7 @@ pub fn push(window_size: Vec2, canvas_size: Vec2) ScreenScalar {
|
|||||||
translation.x = @round(translation.x);
|
translation.x = @round(translation.x);
|
||||||
translation.y = @round(translation.y);
|
translation.y = @round(translation.y);
|
||||||
|
|
||||||
Gfx.pushTransform(translation, scale);
|
Gfx.pushTransform(translation, .init(scale, scale));
|
||||||
|
|
||||||
return ScreenScalar{
|
return ScreenScalar{
|
||||||
.window_size = window_size,
|
.window_size = window_size,
|
||||||
|
|||||||
27
src/game.zig
27
src/game.zig
@ -8,14 +8,11 @@ const Engine = @import("./engine/root.zig");
|
|||||||
const imgui = Engine.imgui;
|
const imgui = Engine.imgui;
|
||||||
const Vec2 = Engine.Vec2;
|
const Vec2 = Engine.Vec2;
|
||||||
const rgb = Engine.Math.rgb;
|
const rgb = Engine.Math.rgb;
|
||||||
const Gfx = Engine.Graphics;
|
|
||||||
const Audio = Engine.Audio;
|
|
||||||
|
|
||||||
const Game = @This();
|
const Game = @This();
|
||||||
|
|
||||||
gpa: Allocator,
|
gpa: Allocator,
|
||||||
assets: *Assets,
|
assets: *Assets,
|
||||||
canvas_size: Vec2,
|
|
||||||
|
|
||||||
player: Vec2,
|
player: Vec2,
|
||||||
|
|
||||||
@ -23,7 +20,6 @@ pub fn init(gpa: Allocator, assets: *Assets) !Game {
|
|||||||
return Game{
|
return Game{
|
||||||
.gpa = gpa,
|
.gpa = gpa,
|
||||||
.assets = assets,
|
.assets = assets,
|
||||||
.canvas_size = Vec2.init(100, 100),
|
|
||||||
.player = .init(50, 50)
|
.player = .init(50, 50)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -35,6 +31,13 @@ pub fn deinit(self: *Game) void {
|
|||||||
pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
||||||
const dt = frame.deltaTime();
|
const dt = frame.deltaTime();
|
||||||
|
|
||||||
|
const canvas_size = Vec2.init(100, 100);
|
||||||
|
frame.graphics.canvas_size = canvas_size;
|
||||||
|
|
||||||
|
if (frame.isKeyPressed(.F3)) {
|
||||||
|
frame.show_debug = !frame.show_debug;
|
||||||
|
}
|
||||||
|
|
||||||
var dir = Vec2.init(0, 0);
|
var dir = Vec2.init(0, 0);
|
||||||
if (frame.isKeyDown(.W)) {
|
if (frame.isKeyDown(.W)) {
|
||||||
dir.y -= 1;
|
dir.y -= 1;
|
||||||
@ -60,14 +63,14 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
|||||||
|
|
||||||
const regular_font = self.assets.font_id.get(.regular);
|
const regular_font = self.assets.font_id.get(.regular);
|
||||||
|
|
||||||
Gfx.drawRectangle(.init(0, 0), self.canvas_size, rgb(20, 20, 20));
|
frame.drawRectangle(.init(0, 0), canvas_size, rgb(20, 20, 20));
|
||||||
const size = Vec2.init(20, 20);
|
const size = Vec2.init(20, 20);
|
||||||
Gfx.drawRectangle(self.player.sub(size.divideScalar(2)), size, rgb(200, 20, 20));
|
frame.drawRectangle(self.player.sub(size.divideScalar(2)), size, rgb(200, 20, 20));
|
||||||
if (dir.x != 0 or dir.y != 0) {
|
if (dir.x != 0 or dir.y != 0) {
|
||||||
Gfx.drawRectanglOutline(self.player.sub(size.divideScalar(2)), size, rgb(20, 200, 20), 3);
|
frame.drawRectanglOutline(self.player.sub(size.divideScalar(2)), size, rgb(20, 200, 20), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
Gfx.drawText(self.player, "Player", .{
|
frame.drawText(self.player, "Player", .{
|
||||||
.font = regular_font,
|
.font = regular_font,
|
||||||
.size = 10
|
.size = 10
|
||||||
});
|
});
|
||||||
@ -76,17 +79,13 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
|||||||
pub fn debug(self: *Game) !void {
|
pub fn debug(self: *Game) !void {
|
||||||
_ = self; // autofix
|
_ = self; // autofix
|
||||||
if (!imgui.beginWindow(.{
|
if (!imgui.beginWindow(.{
|
||||||
.name = "Debug",
|
.name = "Game",
|
||||||
.pos = Vec2.init(20, 20),
|
.pos = Vec2.init(20, 20),
|
||||||
.size = Vec2.init(400, 200),
|
.size = Vec2.init(200, 200),
|
||||||
})) {
|
})) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
defer imgui.endWindow();
|
defer imgui.endWindow();
|
||||||
|
|
||||||
imgui.text("Hello World!\n");
|
imgui.text("Hello World!\n");
|
||||||
imgui.textFmt("Audio: {}/{}\n", .{
|
|
||||||
Audio.mixer.instances.items.len,
|
|
||||||
Audio.mixer.instances.capacity
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user