split engine into lib and runtime
This commit is contained in:
parent
e5fccc21f2
commit
6407263540
@ -23,13 +23,6 @@ const InitOptions = struct {
|
|||||||
pub fn init(outer_builder: *std.Build, opts: InitOptions) void {
|
pub fn init(outer_builder: *std.Build, opts: InitOptions) void {
|
||||||
const b = opts.dep_engine.builder;
|
const b = opts.dep_engine.builder;
|
||||||
|
|
||||||
const engine_module = createEngineModule(b, .{
|
|
||||||
.target = opts.target,
|
|
||||||
.optimize = opts.optimize,
|
|
||||||
.has_tracy = opts.has_tracy,
|
|
||||||
.has_imgui = opts.has_imgui
|
|
||||||
});
|
|
||||||
|
|
||||||
opts.root_module.resolved_target = opts.target;
|
opts.root_module.resolved_target = opts.target;
|
||||||
opts.root_module.optimize = opts.optimize;
|
opts.root_module.optimize = opts.optimize;
|
||||||
const game_lib = b.addLibrary(.{
|
const game_lib = b.addLibrary(.{
|
||||||
@ -37,14 +30,25 @@ pub fn init(outer_builder: *std.Build, opts: InitOptions) void {
|
|||||||
.root_module = opts.root_module,
|
.root_module = opts.root_module,
|
||||||
.linkage = .static,
|
.linkage = .static,
|
||||||
});
|
});
|
||||||
opts.root_module.addImport("engine", engine_module.root_module);
|
const engine_lib = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/lib/root.zig")
|
||||||
|
});
|
||||||
|
opts.root_module.addImport("engine", engine_lib);
|
||||||
|
|
||||||
|
const engine_module = createEngineModule(b, .{
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.has_tracy = opts.has_tracy,
|
||||||
|
.has_imgui = opts.has_imgui
|
||||||
|
});
|
||||||
|
|
||||||
const mod_main = b.createModule(.{
|
const mod_main = b.createModule(.{
|
||||||
.root_source_file = b.path("src/main.zig"),
|
.root_source_file = b.path("src/runtime/main.zig"),
|
||||||
.target = opts.target,
|
.target = opts.target,
|
||||||
.optimize = opts.optimize,
|
.optimize = opts.optimize,
|
||||||
.link_libc = true
|
.link_libc = true
|
||||||
});
|
});
|
||||||
|
mod_main.addImport("lib", engine_lib);
|
||||||
mod_main.addImport("engine", engine_module.root_module);
|
mod_main.addImport("engine", engine_module.root_module);
|
||||||
mod_main.linkLibrary(game_lib);
|
mod_main.linkLibrary(game_lib);
|
||||||
|
|
||||||
@ -110,11 +114,15 @@ fn createEngineModule(b: *std.Build, opts: EngineModule.Options) EngineModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mod = b.createModule(.{
|
const mod = b.createModule(.{
|
||||||
.root_source_file = b.path("src/root.zig"),
|
.root_source_file = b.path("src/runtime/root.zig"),
|
||||||
.target = opts.target,
|
.target = opts.target,
|
||||||
.optimize = opts.optimize,
|
.optimize = opts.optimize,
|
||||||
.link_libc = true
|
.link_libc = true
|
||||||
});
|
});
|
||||||
|
const lib = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/lib/root.zig")
|
||||||
|
});
|
||||||
|
mod.addImport("lib", lib);
|
||||||
|
|
||||||
const dep_sokol = b.dependency("sokol", .{
|
const dep_sokol = b.dependency("sokol", .{
|
||||||
.target = opts.target,
|
.target = opts.target,
|
||||||
@ -169,7 +177,7 @@ fn createEngineModule(b: *std.Build, opts: EngineModule.Options) EngineModule {
|
|||||||
|
|
||||||
mod.addIncludePath(dep_sokol_c.path("util"));
|
mod.addIncludePath(dep_sokol_c.path("util"));
|
||||||
mod.addCSourceFile(.{
|
mod.addCSourceFile(.{
|
||||||
.file = b.path("src/fontstash/sokol_fontstash_impl.c"),
|
.file = b.path("src/runtime/fontstash/sokol_fontstash_impl.c"),
|
||||||
.flags = cflags.items
|
.flags = cflags.items
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,291 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
const build_options = @import("build_options");
|
|
||||||
const log = std.log.scoped(.engine);
|
|
||||||
|
|
||||||
const InputSystem = @import("./input.zig");
|
|
||||||
const KeyCode = InputSystem.KeyCode;
|
|
||||||
const MouseButton = InputSystem.MouseButton;
|
|
||||||
|
|
||||||
const AudioSystem = @import("./audio/root.zig");
|
|
||||||
const AudioData = AudioSystem.Data;
|
|
||||||
const AudioCommand = AudioSystem.Command;
|
|
||||||
|
|
||||||
const GraphicsSystem = @import("./graphics.zig");
|
|
||||||
const TextureId = GraphicsSystem.TextureId;
|
|
||||||
const GraphicsCommand = GraphicsSystem.Command;
|
|
||||||
const Font = GraphicsSystem.Font;
|
|
||||||
const Sprite = GraphicsSystem.Sprite;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
const Frame = @This();
|
|
||||||
|
|
||||||
pub const Input = struct {
|
|
||||||
keyboard: InputSystem.ButtonStateSet(KeyCode),
|
|
||||||
mouse_button: InputSystem.ButtonStateSet(MouseButton),
|
|
||||||
mouse_position: ?Vec2,
|
|
||||||
|
|
||||||
pub const empty = Input{
|
|
||||||
.keyboard = .empty,
|
|
||||||
.mouse_button = .empty,
|
|
||||||
.mouse_position = null,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const KeyState = struct {
|
|
||||||
down: bool,
|
|
||||||
pressed: bool,
|
|
||||||
released: bool,
|
|
||||||
down_duration: ?f64,
|
|
||||||
|
|
||||||
pub const RepeatOptions = struct {
|
|
||||||
first_at: f64 = 0,
|
|
||||||
period: f64
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn repeat(self: KeyState, last_repeat_at: *?f64, opts: RepeatOptions) bool {
|
|
||||||
if (!self.down) {
|
|
||||||
last_repeat_at.* = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const down_duration = self.down_duration.?;
|
|
||||||
if (last_repeat_at.* != null) {
|
|
||||||
if (down_duration >= last_repeat_at.*.? + opts.period) {
|
|
||||||
last_repeat_at.* = last_repeat_at.*.? + opts.period;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (down_duration >= opts.first_at) {
|
|
||||||
last_repeat_at.* = opts.first_at;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Audio = struct {
|
|
||||||
commands: std.ArrayList(AudioCommand),
|
|
||||||
|
|
||||||
pub const empty = Audio{
|
|
||||||
.commands = .empty
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
|
||||||
|
|
||||||
time_ns: Nanoseconds,
|
|
||||||
dt_ns: Nanoseconds,
|
|
||||||
input: Input,
|
|
||||||
audio: Audio,
|
|
||||||
graphics: Graphics,
|
|
||||||
|
|
||||||
show_debug: bool,
|
|
||||||
hide_cursor: bool,
|
|
||||||
|
|
||||||
pub fn init(self: *Frame, gpa: std.mem.Allocator) void {
|
|
||||||
self.* = Frame{
|
|
||||||
.arena = std.heap.ArenaAllocator.init(gpa),
|
|
||||||
.time_ns = 0,
|
|
||||||
.dt_ns = 0,
|
|
||||||
.input = .empty,
|
|
||||||
.audio = .empty,
|
|
||||||
.graphics = .empty,
|
|
||||||
.show_debug = false,
|
|
||||||
.hide_cursor = false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Frame) void {
|
|
||||||
self.arena.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deltaTime(self: Frame) f32 {
|
|
||||||
return @as(f32, @floatFromInt(self.dt_ns)) / std.time.ns_per_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn time(self: Frame) f64 {
|
|
||||||
return @as(f64, @floatFromInt(self.time_ns)) / std.time.ns_per_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn isKeyDown(self: Frame, key_code: KeyCode) bool {
|
|
||||||
const keyboard = &self.input.keyboard;
|
|
||||||
return keyboard.down.contains(key_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getKeyDownDuration(self: Frame, key_code: KeyCode) ?f32 {
|
|
||||||
if (!self.isKeyDown(key_code)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyboard = &self.input.keyboard;
|
|
||||||
const pressed_at_ns = keyboard.pressed_at.get(key_code).?;
|
|
||||||
const duration_ns = self.time_ns - pressed_at_ns;
|
|
||||||
|
|
||||||
return @as(f32, @floatFromInt(duration_ns)) / std.time.ns_per_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn isKeyPressed(self: Frame, key_code: KeyCode) bool {
|
|
||||||
const keyboard = &self.input.keyboard;
|
|
||||||
return keyboard.pressed.contains(key_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn isKeyReleased(self: Frame, key_code: KeyCode) bool {
|
|
||||||
const keyboard = &self.input.keyboard;
|
|
||||||
return keyboard.released.contains(key_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getKeyState(self: Frame, key_code: KeyCode) KeyState {
|
|
||||||
return KeyState{
|
|
||||||
.down = self.isKeyDown(key_code),
|
|
||||||
.released = self.isKeyReleased(key_code),
|
|
||||||
.pressed = self.isKeyPressed(key_code),
|
|
||||||
.down_duration = self.getKeyDownDuration(key_code)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn isMousePressed(self: Frame, button: MouseButton) bool {
|
|
||||||
return self.input.mouse_button.pressed.contains(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn isMouseDown(self: Frame, button: MouseButton) bool {
|
|
||||||
return self.input.mouse_button.down.contains(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
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});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub 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 prependGraphicsCommand(self: *Frame, command: GraphicsCommand) void {
|
|
||||||
const arena = self.arena.allocator();
|
|
||||||
|
|
||||||
self.graphics.commands.insert(arena, 0, command) catch |e|{
|
|
||||||
log.warn("Failed to push graphics command: {}", .{e});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn playAudio(self: *Frame, options: AudioCommand.Play) void {
|
|
||||||
self.pushAudioCommand(.{
|
|
||||||
.play = options,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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, opts: GraphicsCommand.DrawRectangle) void {
|
|
||||||
self.pushGraphicsCommand(.{ .draw_rectangle = opts });
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = {}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
const sokol = @import("sokol");
|
|
||||||
|
|
||||||
const Frame = @import("./frame.zig");
|
|
||||||
const Nanoseconds = Frame.Nanoseconds;
|
|
||||||
|
|
||||||
const Math = @import("./math.zig");
|
|
||||||
const Vec2 = Math.Vec2;
|
|
||||||
|
|
||||||
const Input = @This();
|
|
||||||
|
|
||||||
const SokolKeyCodeInfo = @typeInfo(sokol.app.Keycode);
|
|
||||||
pub const KeyCode = @Type(.{
|
|
||||||
.@"enum" = .{
|
|
||||||
.tag_type = std.math.IntFittingRange(0, sokol.app.max_keycodes-1),
|
|
||||||
.decls = SokolKeyCodeInfo.@"enum".decls,
|
|
||||||
.fields = SokolKeyCodeInfo.@"enum".fields,
|
|
||||||
.is_exhaustive = false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
pub const MouseButton = enum(i3) {
|
|
||||||
left = @intFromEnum(sokol.app.Mousebutton.LEFT),
|
|
||||||
right = @intFromEnum(sokol.app.Mousebutton.RIGHT),
|
|
||||||
middle = @intFromEnum(sokol.app.Mousebutton.MIDDLE),
|
|
||||||
_
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn ButtonStateSet(E: type) type {
|
|
||||||
return struct {
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
down: std.EnumSet(E),
|
|
||||||
pressed: std.EnumSet(E),
|
|
||||||
released: std.EnumSet(E),
|
|
||||||
pressed_at: std.EnumMap(E, Nanoseconds),
|
|
||||||
|
|
||||||
pub const empty = Self{
|
|
||||||
.down = .initEmpty(),
|
|
||||||
.pressed = .initEmpty(),
|
|
||||||
.released = .initEmpty(),
|
|
||||||
.pressed_at = .init(.{}),
|
|
||||||
};
|
|
||||||
|
|
||||||
fn press(self: *Self, button: E, now: Nanoseconds) void {
|
|
||||||
self.pressed_at.put(button, now);
|
|
||||||
self.pressed.insert(button);
|
|
||||||
self.down.insert(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn release(self: *Self, button: E) void {
|
|
||||||
self.down.remove(button);
|
|
||||||
self.released.insert(button);
|
|
||||||
self.pressed_at.remove(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn releaseAll(self: *Self) void {
|
|
||||||
var iter = self.down.iterator();
|
|
||||||
while (iter.next()) |key_code| {
|
|
||||||
self.released.insert(key_code);
|
|
||||||
}
|
|
||||||
self.down = .initEmpty();
|
|
||||||
self.pressed_at = .init(.{});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const Event = union(enum) {
|
|
||||||
mouse_pressed: struct {
|
|
||||||
button: MouseButton,
|
|
||||||
position: Vec2,
|
|
||||||
},
|
|
||||||
mouse_released: struct {
|
|
||||||
button: MouseButton,
|
|
||||||
position: Vec2,
|
|
||||||
},
|
|
||||||
mouse_move: Vec2,
|
|
||||||
mouse_enter: Vec2,
|
|
||||||
mouse_leave,
|
|
||||||
mouse_scroll: Vec2,
|
|
||||||
key_pressed: struct {
|
|
||||||
code: KeyCode,
|
|
||||||
repeat: bool
|
|
||||||
},
|
|
||||||
key_released: Input.KeyCode,
|
|
||||||
window_resize,
|
|
||||||
char: u21,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn processEvent(frame: *Frame, event: Event) void {
|
|
||||||
const input = &frame.input;
|
|
||||||
|
|
||||||
switch (event) {
|
|
||||||
.key_pressed => |opts| {
|
|
||||||
if (!opts.repeat) {
|
|
||||||
input.keyboard.press(opts.code, frame.time_ns);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.key_released => |key_code| {
|
|
||||||
input.keyboard.release(key_code);
|
|
||||||
},
|
|
||||||
.mouse_leave => {
|
|
||||||
input.keyboard.releaseAll();
|
|
||||||
|
|
||||||
input.mouse_position = null;
|
|
||||||
input.mouse_button = .empty;
|
|
||||||
},
|
|
||||||
.mouse_enter => |pos| {
|
|
||||||
input.mouse_position = pos;
|
|
||||||
},
|
|
||||||
.mouse_move => |pos| {
|
|
||||||
input.mouse_position = pos;
|
|
||||||
},
|
|
||||||
.mouse_pressed => |opts| {
|
|
||||||
input.mouse_position = opts.position;
|
|
||||||
input.mouse_button.press(opts.button, frame.time_ns);
|
|
||||||
},
|
|
||||||
.mouse_released => |opts| {
|
|
||||||
input.mouse_position = opts.position;
|
|
||||||
input.mouse_button.release(opts.button);
|
|
||||||
},
|
|
||||||
else => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
37
engine/src/lib/imgui.zig
Normal file
37
engine/src/lib/imgui.zig
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const log = std.log.scoped(.imgui);
|
||||||
|
|
||||||
|
const ImGui = @This();
|
||||||
|
|
||||||
|
const Command = union(enum) {
|
||||||
|
text: [:0]const u8
|
||||||
|
};
|
||||||
|
|
||||||
|
arena_state: std.heap.ArenaAllocator,
|
||||||
|
commands: std.ArrayList(Command),
|
||||||
|
|
||||||
|
pub fn init(gpa: std.mem.Allocator) ImGui {
|
||||||
|
return ImGui{
|
||||||
|
.arena_state = .init(gpa),
|
||||||
|
.commands = .empty
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *ImGui) void {
|
||||||
|
self.arena_state.deinit();
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text(self: *ImGui, comptime fmt: []const u8, args: anytype) void {
|
||||||
|
const arena = self.arena_state.allocator();
|
||||||
|
|
||||||
|
const formatted = std.fmt.allocPrintSentinel(arena, fmt, args, 0) catch |e| {
|
||||||
|
log.warn("formatting text failed: {}", .{e});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.commands.append(arena, .{ .text = formatted }) catch |e| {
|
||||||
|
log.warn("appending command failed: {}", .{e});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
}
|
||||||
473
engine/src/lib/root.zig
Normal file
473
engine/src/lib/root.zig
Normal file
@ -0,0 +1,473 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const log = std.log.scoped(.engine);
|
||||||
|
|
||||||
|
pub const ImGui = @import("./imgui.zig");
|
||||||
|
pub const Math = @import("./math.zig");
|
||||||
|
|
||||||
|
const rgb = Math.rgb;
|
||||||
|
const Rect = Math.Rect;
|
||||||
|
const Vec2 = Math.Vec2;
|
||||||
|
const Vec4 = Math.Vec4;
|
||||||
|
|
||||||
|
pub const Nanoseconds = u64;
|
||||||
|
|
||||||
|
pub const KeyCode = enum {
|
||||||
|
SPACE,
|
||||||
|
APOSTROPHE,
|
||||||
|
COMMA,
|
||||||
|
MINUS,
|
||||||
|
PERIOD,
|
||||||
|
SLASH,
|
||||||
|
_0,
|
||||||
|
_1,
|
||||||
|
_2,
|
||||||
|
_3,
|
||||||
|
_4,
|
||||||
|
_5,
|
||||||
|
_6,
|
||||||
|
_7,
|
||||||
|
_8,
|
||||||
|
_9,
|
||||||
|
SEMICOLON,
|
||||||
|
EQUAL,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
D,
|
||||||
|
E,
|
||||||
|
F,
|
||||||
|
G,
|
||||||
|
H,
|
||||||
|
I,
|
||||||
|
J,
|
||||||
|
K,
|
||||||
|
L,
|
||||||
|
M,
|
||||||
|
N,
|
||||||
|
O,
|
||||||
|
P,
|
||||||
|
Q,
|
||||||
|
R,
|
||||||
|
S,
|
||||||
|
T,
|
||||||
|
U,
|
||||||
|
V,
|
||||||
|
W,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Z,
|
||||||
|
LEFT_BRACKET,
|
||||||
|
BACKSLASH,
|
||||||
|
RIGHT_BRACKET,
|
||||||
|
GRAVE_ACCENT,
|
||||||
|
WORLD_1,
|
||||||
|
WORLD_2,
|
||||||
|
ESCAPE,
|
||||||
|
ENTER,
|
||||||
|
TAB,
|
||||||
|
BACKSPACE,
|
||||||
|
INSERT,
|
||||||
|
DELETE,
|
||||||
|
RIGHT,
|
||||||
|
LEFT,
|
||||||
|
DOWN,
|
||||||
|
UP,
|
||||||
|
PAGE_UP,
|
||||||
|
PAGE_DOWN,
|
||||||
|
HOME,
|
||||||
|
END,
|
||||||
|
CAPS_LOCK,
|
||||||
|
SCROLL_LOCK,
|
||||||
|
NUM_LOCK,
|
||||||
|
PRINT_SCREEN,
|
||||||
|
PAUSE,
|
||||||
|
F1,
|
||||||
|
F2,
|
||||||
|
F3,
|
||||||
|
F4,
|
||||||
|
F5,
|
||||||
|
F6,
|
||||||
|
F7,
|
||||||
|
F8,
|
||||||
|
F9,
|
||||||
|
F10,
|
||||||
|
F11,
|
||||||
|
F12,
|
||||||
|
F13,
|
||||||
|
F14,
|
||||||
|
F15,
|
||||||
|
F16,
|
||||||
|
F17,
|
||||||
|
F18,
|
||||||
|
F19,
|
||||||
|
F20,
|
||||||
|
F21,
|
||||||
|
F22,
|
||||||
|
F23,
|
||||||
|
F24,
|
||||||
|
F25,
|
||||||
|
KP_0,
|
||||||
|
KP_1,
|
||||||
|
KP_2,
|
||||||
|
KP_3,
|
||||||
|
KP_4,
|
||||||
|
KP_5,
|
||||||
|
KP_6,
|
||||||
|
KP_7,
|
||||||
|
KP_8,
|
||||||
|
KP_9,
|
||||||
|
KP_DECIMAL,
|
||||||
|
KP_DIVIDE,
|
||||||
|
KP_MULTIPLY,
|
||||||
|
KP_SUBTRACT,
|
||||||
|
KP_ADD,
|
||||||
|
KP_ENTER,
|
||||||
|
KP_EQUAL,
|
||||||
|
LEFT_SHIFT,
|
||||||
|
LEFT_CONTROL,
|
||||||
|
LEFT_ALT,
|
||||||
|
LEFT_SUPER,
|
||||||
|
RIGHT_SHIFT,
|
||||||
|
RIGHT_CONTROL,
|
||||||
|
RIGHT_ALT,
|
||||||
|
RIGHT_SUPER,
|
||||||
|
MENU,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const MouseButton = enum {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
middle,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const TextureId = enum(u16) { _ };
|
||||||
|
pub const FontId = enum(u16) { _ };
|
||||||
|
pub const AudioId = enum(u16) { _ };
|
||||||
|
|
||||||
|
pub const Sprite = struct {
|
||||||
|
texture: TextureId,
|
||||||
|
uv: Rect
|
||||||
|
};
|
||||||
|
|
||||||
|
fn ButtonStateSet(E: type) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
down: std.EnumSet(E),
|
||||||
|
pressed: std.EnumSet(E),
|
||||||
|
released: std.EnumSet(E),
|
||||||
|
pressed_at: std.EnumMap(E, Nanoseconds),
|
||||||
|
|
||||||
|
pub const empty = Self{
|
||||||
|
.down = .initEmpty(),
|
||||||
|
.pressed = .initEmpty(),
|
||||||
|
.released = .initEmpty(),
|
||||||
|
.pressed_at = .init(.{}),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn press(self: *Self, button: E, now: Nanoseconds) void {
|
||||||
|
self.pressed_at.put(button, now);
|
||||||
|
self.pressed.insert(button);
|
||||||
|
self.down.insert(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(self: *Self, button: E) void {
|
||||||
|
self.down.remove(button);
|
||||||
|
self.released.insert(button);
|
||||||
|
self.pressed_at.remove(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn releaseAll(self: *Self) void {
|
||||||
|
var iter = self.down.iterator();
|
||||||
|
while (iter.next()) |key_code| {
|
||||||
|
self.released.insert(key_code);
|
||||||
|
}
|
||||||
|
self.down = .initEmpty();
|
||||||
|
self.pressed_at = .init(.{});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const GraphicsCommand = union(enum) {
|
||||||
|
pub const DrawRectangle = struct {
|
||||||
|
rect: Rect,
|
||||||
|
color: Vec4,
|
||||||
|
sprite: ?Sprite = null,
|
||||||
|
rotation: f32 = 0,
|
||||||
|
origin: Vec2 = .init(0, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DrawLine = struct {
|
||||||
|
pos1: Vec2,
|
||||||
|
pos2: Vec2,
|
||||||
|
color: Vec4,
|
||||||
|
width: f32
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DrawText = struct {
|
||||||
|
pos: Vec2,
|
||||||
|
text: []const u8,
|
||||||
|
font: FontId,
|
||||||
|
size: f32,
|
||||||
|
color: Vec4,
|
||||||
|
};
|
||||||
|
|
||||||
|
push_scissor: Rect,
|
||||||
|
pop_scissor: void,
|
||||||
|
draw_rectangle: DrawRectangle,
|
||||||
|
draw_line: DrawLine,
|
||||||
|
draw_text: DrawText,
|
||||||
|
push_transformation: struct {
|
||||||
|
translation: Vec2,
|
||||||
|
scale: Vec2
|
||||||
|
},
|
||||||
|
pop_transformation: void
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const AudioCommand = union(enum) {
|
||||||
|
pub const Play = struct {
|
||||||
|
id: AudioId,
|
||||||
|
volume: f32 = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
play: Play,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const KeyState = struct {
|
||||||
|
down: bool,
|
||||||
|
pressed: bool,
|
||||||
|
released: bool,
|
||||||
|
down_duration: ?f64,
|
||||||
|
|
||||||
|
pub const RepeatOptions = struct {
|
||||||
|
first_at: f64 = 0,
|
||||||
|
period: f64
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn repeat(self: KeyState, last_repeat_at: *?f64, opts: RepeatOptions) bool {
|
||||||
|
if (!self.down) {
|
||||||
|
last_repeat_at.* = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const down_duration = self.down_duration.?;
|
||||||
|
if (last_repeat_at.* != null) {
|
||||||
|
if (down_duration >= last_repeat_at.*.? + opts.period) {
|
||||||
|
last_repeat_at.* = last_repeat_at.*.? + opts.period;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (down_duration >= opts.first_at) {
|
||||||
|
last_repeat_at.* = opts.first_at;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Frame = struct {
|
||||||
|
arena: std.heap.ArenaAllocator,
|
||||||
|
time_ns: Nanoseconds,
|
||||||
|
dt_ns: Nanoseconds,
|
||||||
|
|
||||||
|
char_mapping: std.EnumMap(KeyCode, u21),
|
||||||
|
keyboard: ButtonStateSet(KeyCode),
|
||||||
|
mouse_button: ButtonStateSet(MouseButton),
|
||||||
|
mouse_position: ?Vec2,
|
||||||
|
hide_cursor: bool,
|
||||||
|
|
||||||
|
audio_commands: std.ArrayList(AudioCommand),
|
||||||
|
|
||||||
|
graphics_commands: std.ArrayList(GraphicsCommand),
|
||||||
|
canvas_size: ?Vec2,
|
||||||
|
screen_size: Vec2,
|
||||||
|
clear_color: Vec4,
|
||||||
|
|
||||||
|
show_debug: bool,
|
||||||
|
|
||||||
|
pub fn init(self: *Frame, gpa: std.mem.Allocator) void {
|
||||||
|
self.* = Frame{
|
||||||
|
.arena = std.heap.ArenaAllocator.init(gpa),
|
||||||
|
.time_ns = 0,
|
||||||
|
.dt_ns = 0,
|
||||||
|
.char_mapping = .{},
|
||||||
|
.keyboard = .empty,
|
||||||
|
.mouse_button = .empty,
|
||||||
|
.mouse_position = null,
|
||||||
|
.graphics_commands = .empty,
|
||||||
|
.canvas_size = null,
|
||||||
|
.clear_color = rgb(0, 0, 0),
|
||||||
|
.show_debug = false,
|
||||||
|
.audio_commands = .empty,
|
||||||
|
.hide_cursor = false,
|
||||||
|
.screen_size = .init(0, 0),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Frame) void {
|
||||||
|
self.arena.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deltaTime(self: Frame) f32 {
|
||||||
|
return @as(f32, @floatFromInt(self.dt_ns)) / std.time.ns_per_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn time(self: Frame) f64 {
|
||||||
|
return @as(f64, @floatFromInt(self.time_ns)) / std.time.ns_per_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------- Audio ----------------------- //
|
||||||
|
|
||||||
|
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});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn playAudio(self: *Frame, options: AudioCommand.Play) void {
|
||||||
|
self.pushAudioCommand(.{
|
||||||
|
.play = options,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------- Graphics ----------------------- //
|
||||||
|
|
||||||
|
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 drawRectangle(self: *Frame, opts: GraphicsCommand.DrawRectangle) void {
|
||||||
|
self.pushGraphicsCommand(.{ .draw_rectangle = opts });
|
||||||
|
}
|
||||||
|
|
||||||
|
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 fn pushScissor(self: *Frame, rect: Rect) void {
|
||||||
|
self.pushGraphicsCommand(.{
|
||||||
|
.push_scissor = rect
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn popScissor(self: *Frame) void {
|
||||||
|
self.pushGraphicsCommand(.{
|
||||||
|
.pop_scissor = {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const DrawTextOptions = struct {
|
||||||
|
font: FontId,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------- Mouse ----------------------- //
|
||||||
|
|
||||||
|
pub fn isMousePressed(self: Frame, button: MouseButton) bool {
|
||||||
|
return self.mouse_button.pressed.contains(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isMouseDown(self: Frame, button: MouseButton) bool {
|
||||||
|
return self.mouse_button.down.contains(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isMouseReleased(self: Frame, button: MouseButton) bool {
|
||||||
|
return self.mouse_button.released.contains(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------- Keyboard ----------------------- //
|
||||||
|
|
||||||
|
pub fn isKeyDown(self: Frame, key_code: KeyCode) bool {
|
||||||
|
return self.keyboard.down.contains(key_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isKeyPressed(self: Frame, key_code: KeyCode) bool {
|
||||||
|
return self.keyboard.pressed.contains(key_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isKeyReleased(self: Frame, key_code: KeyCode) bool {
|
||||||
|
return self.keyboard.released.contains(key_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getKeyDownDuration(self: Frame, key_code: KeyCode) ?f32 {
|
||||||
|
if (!self.isKeyDown(key_code)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pressed_at_ns = self.keyboard.pressed_at.get(key_code).?;
|
||||||
|
const duration_ns = self.time_ns - pressed_at_ns;
|
||||||
|
|
||||||
|
return @as(f32, @floatFromInt(duration_ns)) / std.time.ns_per_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getKeyState(self: Frame, key_code: KeyCode) KeyState {
|
||||||
|
return KeyState{
|
||||||
|
.down = self.isKeyDown(key_code),
|
||||||
|
.released = self.isKeyReleased(key_code),
|
||||||
|
.pressed = self.isKeyPressed(key_code),
|
||||||
|
.down_duration = self.getKeyDownDuration(key_code)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Init = struct {
|
||||||
|
gpa: std.mem.Allocator,
|
||||||
|
seed: u64
|
||||||
|
};
|
||||||
@ -2,6 +2,7 @@ const std = @import("std");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
const STBVorbis = @import("stb_vorbis");
|
const STBVorbis = @import("stb_vorbis");
|
||||||
|
const Lib = @import("lib");
|
||||||
|
|
||||||
pub const Data = union(enum) {
|
pub const Data = union(enum) {
|
||||||
raw: struct {
|
raw: struct {
|
||||||
@ -70,5 +71,5 @@ pub const Data = union(enum) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Id = enum (u16) { _ };
|
pub const Id = Lib.AudioId;
|
||||||
};
|
};
|
||||||
@ -6,26 +6,21 @@ const Allocator = std.mem.Allocator;
|
|||||||
const sokol = @import("sokol");
|
const sokol = @import("sokol");
|
||||||
const saudio = sokol.audio;
|
const saudio = sokol.audio;
|
||||||
|
|
||||||
|
const Lib = @import("lib");
|
||||||
const AudioData = @import("./data.zig").Data;
|
const AudioData = @import("./data.zig").Data;
|
||||||
pub const Store = @import("./store.zig");
|
pub const Store = @import("./store.zig");
|
||||||
|
|
||||||
const Mixer = @This();
|
const Mixer = @This();
|
||||||
|
|
||||||
pub const Instance = struct {
|
pub const Instance = struct {
|
||||||
data_id: AudioData.Id,
|
data_id: Lib.AudioId,
|
||||||
volume: f32 = 0,
|
volume: f32 = 0,
|
||||||
cursor: u32 = 0,
|
cursor: u32 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Command = union(enum) {
|
pub const Command = Lib.AudioCommand;
|
||||||
pub const Play = struct {
|
|
||||||
id: AudioData.Id,
|
|
||||||
volume: f32 = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
play: Play,
|
pub const RingBuffer = struct {
|
||||||
|
|
||||||
pub const RingBuffer = struct {
|
|
||||||
// TODO: This ring buffer will work in a single producer single consumer configuration
|
// TODO: This ring buffer will work in a single producer single consumer configuration
|
||||||
// For my game this will be good enough
|
// For my game this will be good enough
|
||||||
|
|
||||||
@ -59,13 +54,12 @@ pub const Command = union(enum) {
|
|||||||
self.tail.store(@mod(tail + 1, self.items.len), .monotonic);
|
self.tail.store(@mod(tail + 1, self.items.len), .monotonic);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Tracks
|
// TODO: Tracks
|
||||||
|
|
||||||
instances: std.ArrayList(Instance),
|
instances: std.ArrayList(Instance),
|
||||||
commands: Command.RingBuffer,
|
commands: RingBuffer,
|
||||||
working_buffer: []f32,
|
working_buffer: []f32,
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
@ -4,7 +4,7 @@ const assert = std.debug.assert;
|
|||||||
|
|
||||||
const tracy = @import("tracy");
|
const tracy = @import("tracy");
|
||||||
|
|
||||||
const Math = @import("../math.zig");
|
const Math = @import("lib").Math;
|
||||||
const STBVorbis = @import("stb_vorbis");
|
const STBVorbis = @import("stb_vorbis");
|
||||||
|
|
||||||
pub const Data = @import("./data.zig").Data;
|
pub const Data = @import("./data.zig").Data;
|
||||||
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
const Math = @import("../math.zig");
|
const Math = @import("lib").Math;
|
||||||
const STBVorbis = @import("stb_vorbis");
|
const STBVorbis = @import("stb_vorbis");
|
||||||
|
|
||||||
const AudioData = @import("./data.zig").Data;
|
const AudioData = @import("./data.zig").Data;
|
||||||
@ -6,7 +6,7 @@ const sapp = sokol.app;
|
|||||||
const simgui = sokol.imgui;
|
const simgui = sokol.imgui;
|
||||||
const sgl = sokol.gl;
|
const sgl = sokol.gl;
|
||||||
|
|
||||||
const Math = @import("./math.zig");
|
const Math = @import("lib").Math;
|
||||||
const Vec2 = Math.Vec2;
|
const Vec2 = Math.Vec2;
|
||||||
const Vec4 = Math.Vec4;
|
const Vec4 = Math.Vec4;
|
||||||
const rgb = Math.rgb;
|
const rgb = Math.rgb;
|
||||||
@ -21,7 +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;
|
const Lib = @import("lib");
|
||||||
|
const Command = Lib.GraphicsCommand;
|
||||||
|
|
||||||
const Graphics = @This();
|
const Graphics = @This();
|
||||||
|
|
||||||
@ -43,37 +44,6 @@ const Options = struct {
|
|||||||
imgui_font: ?ImguiFont = null
|
imgui_font: ?ImguiFont = null
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Command = union(enum) {
|
|
||||||
pub const DrawRectangle = struct {
|
|
||||||
rect: Rect,
|
|
||||||
color: Vec4,
|
|
||||||
sprite: ?Sprite = null,
|
|
||||||
rotation: f32 = 0,
|
|
||||||
origin: Vec2 = .init(0, 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
set_scissor: Rect,
|
|
||||||
draw_rectangle: DrawRectangle,
|
|
||||||
draw_line: struct {
|
|
||||||
pos1: Vec2,
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
const Texture = struct {
|
const Texture = struct {
|
||||||
image: sg.Image,
|
image: sg.Image,
|
||||||
view: sg.View,
|
view: sg.View,
|
||||||
@ -84,20 +54,16 @@ const Texture = struct {
|
|||||||
height: u32,
|
height: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Id = enum(u32) { _ };
|
|
||||||
const Data = struct {
|
const Data = struct {
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
rgba: [*]u8
|
rgba: [*]u8
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
pub const TextureId = Texture.Id;
|
pub const TextureId = Lib.TextureId;
|
||||||
pub const TextureInfo = Texture.Info;
|
pub const TextureInfo = Texture.Info;
|
||||||
|
|
||||||
pub const Sprite = struct {
|
pub const Sprite = Lib.Sprite;
|
||||||
texture: TextureId,
|
|
||||||
uv: Rect,
|
|
||||||
};
|
|
||||||
|
|
||||||
main_pipeline: sgl.Pipeline,
|
main_pipeline: sgl.Pipeline,
|
||||||
linear_sampler: sg.Sampler,
|
linear_sampler: sg.Sampler,
|
||||||
@ -108,6 +74,11 @@ textures: std.ArrayList(Texture) = .empty,
|
|||||||
scale_stack_buffer: [32]Vec2 = undefined,
|
scale_stack_buffer: [32]Vec2 = undefined,
|
||||||
scale_stack: std.ArrayList(Vec2) = .empty,
|
scale_stack: std.ArrayList(Vec2) = .empty,
|
||||||
|
|
||||||
|
scissor_stack_buffer: [32]Rect = undefined,
|
||||||
|
scissor_stack: std.ArrayList(Rect) = .empty,
|
||||||
|
|
||||||
|
font_id_lookup: std.AutoArrayHashMapUnmanaged(Lib.FontId, fontstash.Font.Id) = .empty,
|
||||||
|
|
||||||
pub fn init(self: *Graphics, options: Options) !void {
|
pub fn init(self: *Graphics, options: Options) !void {
|
||||||
sg.setup(.{
|
sg.setup(.{
|
||||||
.logger = options.logger,
|
.logger = options.logger,
|
||||||
@ -187,6 +158,7 @@ pub fn init(self: *Graphics, options: Options) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Graphics, gpa: std.mem.Allocator) void {
|
pub fn deinit(self: *Graphics, gpa: std.mem.Allocator) void {
|
||||||
|
self.font_id_lookup.deinit(gpa);
|
||||||
self.textures.deinit(gpa);
|
self.textures.deinit(gpa);
|
||||||
imgui.shutdown();
|
imgui.shutdown();
|
||||||
self.font_context.deinit();
|
self.font_context.deinit();
|
||||||
@ -206,12 +178,29 @@ pub fn drawCommand(self: *Graphics, command: Command) void {
|
|||||||
.draw_rectangle => |opts| {
|
.draw_rectangle => |opts| {
|
||||||
self.drawRectangle(opts);
|
self.drawRectangle(opts);
|
||||||
},
|
},
|
||||||
.set_scissor => |opts| {
|
.push_scissor => |rect| {
|
||||||
|
self.scissor_stack.appendBounded(rect) catch |e| {
|
||||||
|
log.warn("Failed to push scissor region: {}", .{e});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
sgl.scissorRectf(
|
sgl.scissorRectf(
|
||||||
opts.pos.x,
|
rect.pos.x,
|
||||||
opts.pos.y,
|
rect.pos.y,
|
||||||
opts.size.x,
|
rect.size.x,
|
||||||
opts.size.y,
|
rect.size.y,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
},
|
||||||
|
.pop_scissor => {
|
||||||
|
_ = self.scissor_stack.pop().?;
|
||||||
|
const rect = self.scissor_stack.getLast();
|
||||||
|
|
||||||
|
sgl.scissorRectf(
|
||||||
|
rect.pos.x,
|
||||||
|
rect.pos.y,
|
||||||
|
rect.size.x,
|
||||||
|
rect.size.y,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -231,7 +220,11 @@ pub fn drawCommand(self: *Graphics, command: Command) void {
|
|||||||
|
|
||||||
sgl.scale(1/font_resolution_scale.x, 1/font_resolution_scale.y, 1);
|
sgl.scale(1/font_resolution_scale.x, 1/font_resolution_scale.y, 1);
|
||||||
|
|
||||||
self.font_context.setFont(opts.font);
|
const font_id = self.font_id_lookup.get(opts.font) orelse {
|
||||||
|
log.warn("Attempt to use font that doesn't exist", .{});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
self.font_context.setFont(font_id);
|
||||||
self.font_context.setSize(opts.size * font_resolution_scale.y);
|
self.font_context.setSize(opts.size * font_resolution_scale.y);
|
||||||
self.font_context.setAlign(.{ .x = .left, .y = .top });
|
self.font_context.setAlign(.{ .x = .left, .y = .top });
|
||||||
self.font_context.setSpacing(0);
|
self.font_context.setSpacing(0);
|
||||||
@ -271,6 +264,9 @@ pub fn beginFrame(self: *Graphics) void {
|
|||||||
self.scale_stack = .initBuffer(&self.scale_stack_buffer);
|
self.scale_stack = .initBuffer(&self.scale_stack_buffer);
|
||||||
self.scale_stack.appendAssumeCapacity(.init(1, 1));
|
self.scale_stack.appendAssumeCapacity(.init(1, 1));
|
||||||
|
|
||||||
|
self.scissor_stack = .initBuffer(&self.scissor_stack_buffer);
|
||||||
|
self.scissor_stack.appendAssumeCapacity(.init(0, 0, sapp.widthf(), sapp.heightf()));
|
||||||
|
|
||||||
self.font_context.clearState();
|
self.font_context.clearState();
|
||||||
sgl.defaults();
|
sgl.defaults();
|
||||||
sgl.matrixModeProjection();
|
sgl.matrixModeProjection();
|
||||||
@ -310,7 +306,7 @@ pub fn endFrame(self: *Graphics, clear_color: Vec4) void {
|
|||||||
sg.commit();
|
sg.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pushTransform(self: *Graphics, translation: Vec2, scale: Vec2) void {
|
pub fn pushTransform(self: *Graphics, 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.x, scale.y, 1);
|
sgl.scale(scale.x, scale.y, 1);
|
||||||
@ -318,7 +314,7 @@ fn pushTransform(self: *Graphics, translation: Vec2, scale: Vec2) void {
|
|||||||
self.scale_stack.appendAssumeCapacity(self.scale_stack.getLast().multiply(scale));
|
self.scale_stack.appendAssumeCapacity(self.scale_stack.getLast().multiply(scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn popTransform(self: *Graphics) void {
|
pub fn popTransform(self: *Graphics) void {
|
||||||
sgl.popMatrix();
|
sgl.popMatrix();
|
||||||
_ = self.scale_stack.pop().?;
|
_ = self.scale_stack.pop().?;
|
||||||
}
|
}
|
||||||
@ -357,7 +353,7 @@ fn drawQuadNoUVs(quad: [4]Vec2, color: Vec4) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drawRectangle(self: *Graphics, opts: Command.DrawRectangle) void {
|
pub fn drawRectangle(self: *Graphics, opts: Command.DrawRectangle) void {
|
||||||
const pos = opts.rect.pos;
|
const pos = opts.rect.pos;
|
||||||
const size = opts.rect.size;
|
const size = opts.rect.size;
|
||||||
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Math = @import("./math.zig");
|
const Lib = @import("lib");
|
||||||
|
const Math = Lib.Math;
|
||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
pub const ig = @import("cimgui");
|
pub const ig = @import("cimgui");
|
||||||
const Vec2 = Math.Vec2;
|
const Vec2 = Math.Vec2;
|
||||||
210
engine/src/runtime/input.zig
Normal file
210
engine/src/runtime/input.zig
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const sokol = @import("sokol");
|
||||||
|
|
||||||
|
const lib = @import("lib");
|
||||||
|
const Frame = lib.Frame;
|
||||||
|
const Nanoseconds = lib.Nanoseconds;
|
||||||
|
const Vec2 = lib.Math.Vec2;
|
||||||
|
|
||||||
|
const Input = @This();
|
||||||
|
|
||||||
|
const SokolKeyCodeInfo = @typeInfo(sokol.app.Keycode);
|
||||||
|
|
||||||
|
pub const Event = union(enum) {
|
||||||
|
mouse_pressed: struct {
|
||||||
|
button: lib.MouseButton,
|
||||||
|
position: Vec2,
|
||||||
|
},
|
||||||
|
mouse_released: struct {
|
||||||
|
button: lib.MouseButton,
|
||||||
|
position: Vec2,
|
||||||
|
},
|
||||||
|
mouse_move: Vec2,
|
||||||
|
mouse_enter: Vec2,
|
||||||
|
mouse_leave,
|
||||||
|
mouse_scroll: Vec2,
|
||||||
|
key_pressed: struct {
|
||||||
|
code: lib.KeyCode,
|
||||||
|
repeat: bool
|
||||||
|
},
|
||||||
|
key_released: lib.KeyCode,
|
||||||
|
window_resize,
|
||||||
|
char: u21,
|
||||||
|
};
|
||||||
|
|
||||||
|
mouse_position: ?Vec2 = null,
|
||||||
|
|
||||||
|
pub fn processEvent(self: *Input, frame: *Frame, event: Event) void {
|
||||||
|
switch (event) {
|
||||||
|
.key_pressed => |opts| {
|
||||||
|
if (!opts.repeat) {
|
||||||
|
frame.keyboard.press(opts.code, frame.time_ns);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.key_released => |key_code| {
|
||||||
|
frame.keyboard.release(key_code);
|
||||||
|
},
|
||||||
|
.mouse_leave => {
|
||||||
|
frame.keyboard.releaseAll();
|
||||||
|
|
||||||
|
assert(self.mouse_position != null);
|
||||||
|
self.mouse_position = null;
|
||||||
|
frame.mouse_button = .empty;
|
||||||
|
},
|
||||||
|
.mouse_enter => |pos| {
|
||||||
|
assert(self.mouse_position == null);
|
||||||
|
self.mouse_position = pos;
|
||||||
|
},
|
||||||
|
.mouse_move => |pos| {
|
||||||
|
assert(self.mouse_position != null);
|
||||||
|
self.mouse_position = pos;
|
||||||
|
},
|
||||||
|
.mouse_pressed => |opts| {
|
||||||
|
assert(self.mouse_position != null);
|
||||||
|
self.mouse_position = opts.position;
|
||||||
|
frame.mouse_button.press(opts.button, frame.time_ns);
|
||||||
|
},
|
||||||
|
.mouse_released => |opts| {
|
||||||
|
assert(self.mouse_position != null);
|
||||||
|
self.mouse_position = opts.position;
|
||||||
|
frame.mouse_button.release(opts.button);
|
||||||
|
},
|
||||||
|
else => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getKeyCodeFromSokol(key_code: sokol.app.Keycode) ?lib.KeyCode {
|
||||||
|
return switch (key_code) {
|
||||||
|
.SPACE => .SPACE,
|
||||||
|
.APOSTROPHE => .APOSTROPHE,
|
||||||
|
.COMMA => .COMMA,
|
||||||
|
.MINUS => .MINUS,
|
||||||
|
.PERIOD => .PERIOD,
|
||||||
|
.SLASH => .SLASH,
|
||||||
|
._0 => ._0,
|
||||||
|
._1 => ._1,
|
||||||
|
._2 => ._2,
|
||||||
|
._3 => ._3,
|
||||||
|
._4 => ._4,
|
||||||
|
._5 => ._5,
|
||||||
|
._6 => ._6,
|
||||||
|
._7 => ._7,
|
||||||
|
._8 => ._8,
|
||||||
|
._9 => ._9,
|
||||||
|
.SEMICOLON => .SEMICOLON,
|
||||||
|
.EQUAL => .EQUAL,
|
||||||
|
.A => .A,
|
||||||
|
.B => .B,
|
||||||
|
.C => .C,
|
||||||
|
.D => .D,
|
||||||
|
.E => .E,
|
||||||
|
.F => .F,
|
||||||
|
.G => .G,
|
||||||
|
.H => .H,
|
||||||
|
.I => .I,
|
||||||
|
.J => .J,
|
||||||
|
.K => .K,
|
||||||
|
.L => .L,
|
||||||
|
.M => .M,
|
||||||
|
.N => .N,
|
||||||
|
.O => .O,
|
||||||
|
.P => .P,
|
||||||
|
.Q => .Q,
|
||||||
|
.R => .R,
|
||||||
|
.S => .S,
|
||||||
|
.T => .T,
|
||||||
|
.U => .U,
|
||||||
|
.V => .V,
|
||||||
|
.W => .W,
|
||||||
|
.X => .X,
|
||||||
|
.Y => .Y,
|
||||||
|
.Z => .Z,
|
||||||
|
.LEFT_BRACKET => .LEFT_BRACKET,
|
||||||
|
.BACKSLASH => .BACKSLASH,
|
||||||
|
.RIGHT_BRACKET => .RIGHT_BRACKET,
|
||||||
|
.GRAVE_ACCENT => .GRAVE_ACCENT,
|
||||||
|
.WORLD_1 => .WORLD_1,
|
||||||
|
.WORLD_2 => .WORLD_2,
|
||||||
|
.ESCAPE => .ESCAPE,
|
||||||
|
.ENTER => .ENTER,
|
||||||
|
.TAB => .TAB,
|
||||||
|
.BACKSPACE => .BACKSPACE,
|
||||||
|
.INSERT => .INSERT,
|
||||||
|
.DELETE => .DELETE,
|
||||||
|
.RIGHT => .RIGHT,
|
||||||
|
.LEFT => .LEFT,
|
||||||
|
.DOWN => .DOWN,
|
||||||
|
.UP => .UP,
|
||||||
|
.PAGE_UP => .PAGE_UP,
|
||||||
|
.PAGE_DOWN => .PAGE_DOWN,
|
||||||
|
.HOME => .HOME,
|
||||||
|
.END => .END,
|
||||||
|
.CAPS_LOCK => .CAPS_LOCK,
|
||||||
|
.SCROLL_LOCK => .SCROLL_LOCK,
|
||||||
|
.NUM_LOCK => .NUM_LOCK,
|
||||||
|
.PRINT_SCREEN => .PRINT_SCREEN,
|
||||||
|
.PAUSE => .PAUSE,
|
||||||
|
.F1 => .F1,
|
||||||
|
.F2 => .F2,
|
||||||
|
.F3 => .F3,
|
||||||
|
.F4 => .F4,
|
||||||
|
.F5 => .F5,
|
||||||
|
.F6 => .F6,
|
||||||
|
.F7 => .F7,
|
||||||
|
.F8 => .F8,
|
||||||
|
.F9 => .F9,
|
||||||
|
.F10 => .F10,
|
||||||
|
.F11 => .F11,
|
||||||
|
.F12 => .F12,
|
||||||
|
.F13 => .F13,
|
||||||
|
.F14 => .F14,
|
||||||
|
.F15 => .F15,
|
||||||
|
.F16 => .F16,
|
||||||
|
.F17 => .F17,
|
||||||
|
.F18 => .F18,
|
||||||
|
.F19 => .F19,
|
||||||
|
.F20 => .F20,
|
||||||
|
.F21 => .F21,
|
||||||
|
.F22 => .F22,
|
||||||
|
.F23 => .F23,
|
||||||
|
.F24 => .F24,
|
||||||
|
.F25 => .F25,
|
||||||
|
.KP_0 => .KP_0,
|
||||||
|
.KP_1 => .KP_1,
|
||||||
|
.KP_2 => .KP_2,
|
||||||
|
.KP_3 => .KP_3,
|
||||||
|
.KP_4 => .KP_4,
|
||||||
|
.KP_5 => .KP_5,
|
||||||
|
.KP_6 => .KP_6,
|
||||||
|
.KP_7 => .KP_7,
|
||||||
|
.KP_8 => .KP_8,
|
||||||
|
.KP_9 => .KP_9,
|
||||||
|
.KP_DECIMAL => .KP_DECIMAL,
|
||||||
|
.KP_DIVIDE => .KP_DIVIDE,
|
||||||
|
.KP_MULTIPLY => .KP_MULTIPLY,
|
||||||
|
.KP_SUBTRACT => .KP_SUBTRACT,
|
||||||
|
.KP_ADD => .KP_ADD,
|
||||||
|
.KP_ENTER => .KP_ENTER,
|
||||||
|
.KP_EQUAL => .KP_EQUAL,
|
||||||
|
.LEFT_SHIFT => .LEFT_SHIFT,
|
||||||
|
.LEFT_CONTROL => .LEFT_CONTROL,
|
||||||
|
.LEFT_ALT => .LEFT_ALT,
|
||||||
|
.LEFT_SUPER => .LEFT_SUPER,
|
||||||
|
.RIGHT_SHIFT => .RIGHT_SHIFT,
|
||||||
|
.RIGHT_CONTROL => .RIGHT_CONTROL,
|
||||||
|
.RIGHT_ALT => .RIGHT_ALT,
|
||||||
|
.RIGHT_SUPER => .RIGHT_SUPER,
|
||||||
|
.MENU => .MENU,
|
||||||
|
else => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getMouseButtonFromSokol(mouse_button: sokol.app.Mousebutton) ?lib.MouseButton {
|
||||||
|
return switch (mouse_button) {
|
||||||
|
.RIGHT => .right,
|
||||||
|
.MIDDLE => .middle,
|
||||||
|
.LEFT => .left,
|
||||||
|
else => null
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -5,14 +5,8 @@ const assert = std.debug.assert;
|
|||||||
const sokol = @import("sokol");
|
const sokol = @import("sokol");
|
||||||
const sapp = sokol.app;
|
const sapp = sokol.app;
|
||||||
|
|
||||||
pub const Math = @import("./math.zig");
|
|
||||||
pub const Vec2 = Math.Vec2;
|
|
||||||
const rgb = Math.rgb;
|
|
||||||
|
|
||||||
pub const Input = @import("./input.zig");
|
pub const Input = @import("./input.zig");
|
||||||
|
|
||||||
pub const Frame = @import("./frame.zig");
|
|
||||||
|
|
||||||
const ScreenScalar = @import("./screen_scaler.zig");
|
const ScreenScalar = @import("./screen_scaler.zig");
|
||||||
pub const imgui = @import("./imgui.zig");
|
pub const imgui = @import("./imgui.zig");
|
||||||
pub const Graphics = @import("./graphics.zig");
|
pub const Graphics = @import("./graphics.zig");
|
||||||
@ -23,37 +17,44 @@ const STBImage = @import("stb_image");
|
|||||||
|
|
||||||
const Gfx = Graphics;
|
const Gfx = Graphics;
|
||||||
|
|
||||||
|
const Lib = @import("lib");
|
||||||
|
pub const Math = Lib.Math;
|
||||||
|
pub const Vec2 = Math.Vec2;
|
||||||
|
const rgb = Math.rgb;
|
||||||
|
|
||||||
const GameCallbacks = struct {
|
const GameCallbacks = struct {
|
||||||
init: *const fn(opts: *const Engine.InitOptions) callconv(.c) void,
|
init: *const fn(opts: *const Lib.Init) callconv(.c) void,
|
||||||
tick: *const fn(frame: *Frame) callconv(.c) void,
|
tick: *const fn(frame: *Lib.Frame) callconv(.c) void,
|
||||||
deinit: *const fn() callconv(.c) void,
|
deinit: *const fn() callconv(.c) void,
|
||||||
debug: *const fn() callconv(.c) void,
|
debug: *const fn(imgui: *Lib.ImGui) callconv(.c) void,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern fn init(opts: *const Engine.InitOptions) void;
|
extern fn init(opts: *const Lib.Init) void;
|
||||||
extern fn tick(frame: *Frame) void;
|
extern fn tick(frame: *Lib.Frame) void;
|
||||||
extern fn deinit() void;
|
extern fn deinit() void;
|
||||||
extern fn debug() void;
|
extern fn debug(imgui: *Lib.ImGui) void;
|
||||||
|
const static_game_callbacks = GameCallbacks{
|
||||||
|
.init = init,
|
||||||
|
.deinit = deinit,
|
||||||
|
.tick = tick,
|
||||||
|
.debug = debug,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const Engine = @This();
|
const Engine = @This();
|
||||||
|
|
||||||
pub const Nanoseconds = u64;
|
pub const Nanoseconds = u64;
|
||||||
|
|
||||||
pub const InitOptions = struct {
|
|
||||||
gpa: std.mem.Allocator,
|
|
||||||
seed: u64
|
|
||||||
};
|
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
started_at: std.time.Instant,
|
started_at: std.time.Instant,
|
||||||
mouse_inside: bool,
|
|
||||||
last_frame_at: Nanoseconds,
|
last_frame_at: Nanoseconds,
|
||||||
graphics: Graphics,
|
graphics: Graphics,
|
||||||
|
input: Input,
|
||||||
game_callbacks: GameCallbacks,
|
game_callbacks: GameCallbacks,
|
||||||
|
|
||||||
frame: Frame,
|
frame: Lib.Frame,
|
||||||
|
|
||||||
canvas_size: ?Vec2 = null,
|
previous_tick_canvas_size: ?Vec2 = null,
|
||||||
|
|
||||||
const RunOptions = struct {
|
const RunOptions = struct {
|
||||||
window_title: [*:0]const u8 = "Game",
|
window_title: [*:0]const u8 = "Game",
|
||||||
@ -65,16 +66,11 @@ pub fn run(self: *Engine, opts: RunOptions) !void {
|
|||||||
self.* = Engine{
|
self.* = Engine{
|
||||||
.allocator = undefined,
|
.allocator = undefined,
|
||||||
.started_at = std.time.Instant.now() catch @panic("Instant.now() unsupported"),
|
.started_at = std.time.Instant.now() catch @panic("Instant.now() unsupported"),
|
||||||
.mouse_inside = false,
|
|
||||||
.last_frame_at = 0,
|
.last_frame_at = 0,
|
||||||
.frame = undefined,
|
.frame = undefined,
|
||||||
.graphics = undefined,
|
.graphics = undefined,
|
||||||
.game_callbacks = .{
|
.game_callbacks = static_game_callbacks,
|
||||||
.init = init,
|
.input = .{}
|
||||||
.deinit = deinit,
|
|
||||||
.tick = tick,
|
|
||||||
.debug = debug,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
|
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
|
||||||
@ -157,7 +153,7 @@ fn sokolInit(self: *Engine) !void {
|
|||||||
|
|
||||||
const seed: u64 = @bitCast(std.time.milliTimestamp());
|
const seed: u64 = @bitCast(std.time.milliTimestamp());
|
||||||
|
|
||||||
const opts = InitOptions{
|
const opts = Lib.Init{
|
||||||
.gpa = self.allocator,
|
.gpa = self.allocator,
|
||||||
.seed = seed,
|
.seed = seed,
|
||||||
};
|
};
|
||||||
@ -188,83 +184,71 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
|
|
||||||
const screen_size = Vec2.init(sapp.widthf(), sapp.heightf());
|
const screen_size = Vec2.init(sapp.widthf(), sapp.heightf());
|
||||||
|
|
||||||
var revert_mouse_position: ?Vec2 = null;
|
var maybe_screen_scaler: ?ScreenScalar = null;
|
||||||
if (self.canvas_size) |canvas_size| {
|
if (self.previous_tick_canvas_size) |canvas_size| {
|
||||||
if (self.frame.input.mouse_position) |mouse| {
|
maybe_screen_scaler = ScreenScalar.init(screen_size, canvas_size);
|
||||||
const transform = ScreenScalar.init(screen_size, canvas_size);
|
|
||||||
|
|
||||||
revert_mouse_position = mouse;
|
|
||||||
self.frame.input.mouse_position = mouse.sub(transform.translation).divideScalar(transform.scale);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
_ = frame.arena.reset(.retain_capacity);
|
_ = frame.arena.reset(.retain_capacity);
|
||||||
const arena = frame.arena.allocator();
|
const arena = frame.arena.allocator();
|
||||||
|
|
||||||
const audio_commands_capacity = frame.audio.commands.capacity;
|
const audio_commands_capacity = frame.audio_commands.capacity;
|
||||||
frame.audio = .empty;
|
frame.audio_commands = .empty;
|
||||||
try frame.audio.commands.ensureTotalCapacity(arena, audio_commands_capacity);
|
try frame.audio_commands.ensureTotalCapacity(arena, audio_commands_capacity);
|
||||||
|
|
||||||
const graphics_commands_capacity = frame.graphics.commands.capacity;
|
const graphics_commands_capacity = frame.graphics_commands.capacity;
|
||||||
const scissor_stack_capacity = frame.graphics.scissor_stack.capacity;
|
frame.graphics_commands = .empty;
|
||||||
frame.graphics = .empty;
|
try frame.graphics_commands.ensureTotalCapacity(arena, graphics_commands_capacity);
|
||||||
frame.graphics.screen_size = screen_size;
|
|
||||||
try frame.graphics.commands.ensureTotalCapacity(arena, graphics_commands_capacity);
|
|
||||||
try frame.graphics.scissor_stack.ensureTotalCapacity(arena, scissor_stack_capacity);
|
|
||||||
frame.pushScissor(.init(0, 0, sapp.widthf(), sapp.heightf()));
|
|
||||||
|
|
||||||
|
frame.screen_size = screen_size;
|
||||||
frame.time_ns = time_passed;
|
frame.time_ns = time_passed;
|
||||||
frame.dt_ns = time_passed - self.last_frame_at;
|
frame.dt_ns = time_passed - self.last_frame_at;
|
||||||
frame.hide_cursor = false;
|
|
||||||
|
|
||||||
self.game_callbacks.tick(&self.frame);
|
frame.mouse_position = self.input.mouse_position;
|
||||||
|
if (maybe_screen_scaler) |screen_scaler| {
|
||||||
|
screen_scaler.push(frame);
|
||||||
|
|
||||||
frame.input.keyboard.pressed = .initEmpty();
|
if (frame.mouse_position) |mouse_position| {
|
||||||
frame.input.keyboard.released = .initEmpty();
|
frame.mouse_position = mouse_position.sub(screen_scaler.translation).divideScalar(screen_scaler.scale);
|
||||||
frame.input.mouse_button.pressed = .initEmpty();
|
}
|
||||||
frame.input.mouse_button.released = .initEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.canvas_size) |canvas_size| {
|
self.game_callbacks.tick(frame);
|
||||||
const transform = ScreenScalar.init(
|
|
||||||
screen_size,
|
if (maybe_screen_scaler) |screen_scaler| {
|
||||||
canvas_size
|
screen_scaler.pop(frame, frame.clear_color);
|
||||||
);
|
|
||||||
transform.apply(
|
|
||||||
screen_size,
|
|
||||||
&self.frame,
|
|
||||||
rgb(0, 0, 0)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sapp.showMouse(!self.frame.hide_cursor);
|
frame.keyboard.pressed = .initEmpty();
|
||||||
|
frame.keyboard.released = .initEmpty();
|
||||||
|
frame.mouse_button.pressed = .initEmpty();
|
||||||
|
frame.mouse_button.released = .initEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
// Canvas size modification must always be applied a frame later.
|
// Canvas size modification must always be applied a frame later.
|
||||||
// So that mouse coordinate transformations are consistent.
|
// So that mouse coordinate transformations are consistent.
|
||||||
self.canvas_size = self.frame.graphics.canvas_size;
|
self.previous_tick_canvas_size = self.frame.canvas_size;
|
||||||
|
|
||||||
|
sapp.showMouse(!self.frame.hide_cursor);
|
||||||
|
|
||||||
{
|
{
|
||||||
self.graphics.beginFrame();
|
self.graphics.beginFrame();
|
||||||
defer self.graphics.endFrame(frame.graphics.clear_color);
|
defer self.graphics.endFrame(frame.clear_color);
|
||||||
|
|
||||||
self.graphics.drawCommands(frame.graphics.commands.items);
|
self.graphics.drawCommands(frame.graphics_commands.items);
|
||||||
|
|
||||||
if (frame.show_debug) {
|
if (frame.show_debug) {
|
||||||
try self.showDebugWindow(&self.frame);
|
try self.showDebugWindow(frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (frame.audio.commands.items) |command| {
|
for (frame.audio_commands.items) |command| {
|
||||||
try Audio.mixer.commands.push(command);
|
try Audio.mixer.commands.push(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (revert_mouse_position) |pos| {
|
|
||||||
self.frame.input.mouse_position = pos;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn showDebugWindow(self: *Engine, frame: *Frame) !void {
|
fn showDebugWindow(self: *Engine, frame: *Lib.Frame) !void {
|
||||||
if (!imgui.beginWindow(.{
|
if (!imgui.beginWindow(.{
|
||||||
.name = "Debug",
|
.name = "Debug",
|
||||||
.pos = Vec2.init(20, 20),
|
.pos = Vec2.init(20, 20),
|
||||||
@ -274,24 +258,31 @@ fn showDebugWindow(self: *Engine, frame: *Frame) !void {
|
|||||||
}
|
}
|
||||||
defer imgui.endWindow();
|
defer imgui.endWindow();
|
||||||
|
|
||||||
if (imgui.beginTabBar("debug")) {
|
_ = imgui.beginTabBar("debug");
|
||||||
defer imgui.endTabBar();
|
|
||||||
|
|
||||||
if (imgui.beginTabItem("Game")) {
|
if (imgui.beginTabItem("Game")) {
|
||||||
defer imgui.endTabItem();
|
defer imgui.endTabItem();
|
||||||
self.game_callbacks.debug();
|
|
||||||
|
var imgui_ctx = Lib.ImGui.init(self.allocator);
|
||||||
|
defer imgui_ctx.deinit();
|
||||||
|
self.game_callbacks.debug(&imgui_ctx);
|
||||||
|
for (imgui_ctx.commands.items) |cmd| {
|
||||||
|
switch (cmd) {
|
||||||
|
.text => |str| imgui.text(str)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (imgui.beginTabItem("Engine")) {
|
if (imgui.beginTabItem("Engine")) {
|
||||||
defer imgui.endTabItem();
|
defer imgui.endTabItem();
|
||||||
imgui.textFmt("Draw commands: {}\n", .{
|
imgui.textFmt("Draw commands: {}\n", .{
|
||||||
frame.graphics.commands.items.len,
|
frame.graphics_commands.items.len,
|
||||||
});
|
});
|
||||||
imgui.textFmt("Audio instances: {}/{}\n", .{
|
imgui.textFmt("Audio instances: {}/{}\n", .{
|
||||||
Audio.mixer.instances.items.len,
|
Audio.mixer.instances.items.len,
|
||||||
Audio.mixer.instances.capacity
|
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 {
|
||||||
@ -301,20 +292,22 @@ fn sokolEvent(self: *Engine, e_ptr: [*c]const sapp.Event) !bool {
|
|||||||
const e = e_ptr.*;
|
const e = e_ptr.*;
|
||||||
|
|
||||||
if (imgui.handleEvent(e)) {
|
if (imgui.handleEvent(e)) {
|
||||||
if (self.mouse_inside) {
|
if (self.input.mouse_position != null) {
|
||||||
Input.processEvent(&self.frame, .{
|
self.input.processEvent(&self.frame, .{
|
||||||
.mouse_leave = {}
|
.mouse_leave = {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
self.mouse_inside = false;
|
self.input.mouse_position = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (e.type) {
|
blk: switch (e.type) {
|
||||||
.MOUSE_DOWN => {
|
.MOUSE_DOWN => {
|
||||||
Input.processEvent(&self.frame, .{
|
const mouse_button = Input.getMouseButtonFromSokol(e.mouse_button) orelse break :blk;
|
||||||
|
|
||||||
|
self.input.processEvent(&self.frame, .{
|
||||||
.mouse_pressed = .{
|
.mouse_pressed = .{
|
||||||
.button = @enumFromInt(@intFromEnum(e.mouse_button)),
|
.button = mouse_button,
|
||||||
.position = Vec2.init(e.mouse_x, e.mouse_y)
|
.position = Vec2.init(e.mouse_x, e.mouse_y)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -322,9 +315,11 @@ fn sokolEvent(self: *Engine, e_ptr: [*c]const sapp.Event) !bool {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
.MOUSE_UP => {
|
.MOUSE_UP => {
|
||||||
Input.processEvent(&self.frame, .{
|
const mouse_button = Input.getMouseButtonFromSokol(e.mouse_button) orelse break :blk;
|
||||||
|
|
||||||
|
self.input.processEvent(&self.frame, .{
|
||||||
.mouse_released = .{
|
.mouse_released = .{
|
||||||
.button = @enumFromInt(@intFromEnum(e.mouse_button)),
|
.button = mouse_button,
|
||||||
.position = Vec2.init(e.mouse_x, e.mouse_y)
|
.position = Vec2.init(e.mouse_x, e.mouse_y)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -332,64 +327,59 @@ fn sokolEvent(self: *Engine, e_ptr: [*c]const sapp.Event) !bool {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
.MOUSE_MOVE => {
|
.MOUSE_MOVE => {
|
||||||
if (!self.mouse_inside) {
|
if (self.input.mouse_position == null) {
|
||||||
Input.processEvent(&self.frame, .{
|
self.input.processEvent(&self.frame, .{
|
||||||
.mouse_enter = Vec2.init(e.mouse_x, e.mouse_y)
|
.mouse_enter = Vec2.init(e.mouse_x, e.mouse_y)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Input.processEvent(&self.frame, .{
|
self.input.processEvent(&self.frame, .{
|
||||||
.mouse_move = Vec2.init(e.mouse_x, e.mouse_y)
|
.mouse_move = Vec2.init(e.mouse_x, e.mouse_y)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mouse_inside = true;
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
.MOUSE_ENTER => {
|
.MOUSE_ENTER => {
|
||||||
if (!self.mouse_inside) {
|
if (self.input.mouse_position == null) {
|
||||||
Input.processEvent(&self.frame, .{
|
self.input.processEvent(&self.frame, .{
|
||||||
.mouse_enter = Vec2.init(e.mouse_x, e.mouse_y)
|
.mouse_enter = Vec2.init(e.mouse_x, e.mouse_y)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mouse_inside = true;
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
.RESIZED => {
|
.RESIZED => {
|
||||||
if (self.mouse_inside) {
|
if (self.input.mouse_position != null) {
|
||||||
Input.processEvent(&self.frame, .{
|
self.input.processEvent(&self.frame, .{
|
||||||
.mouse_leave = {}
|
.mouse_leave = {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Input.processEvent(&self.frame, .{
|
self.input.processEvent(&self.frame, .{
|
||||||
.window_resize = {}
|
.window_resize = {}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.mouse_inside = false;
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
.MOUSE_LEAVE => {
|
.MOUSE_LEAVE => {
|
||||||
if (self.mouse_inside) {
|
if (self.input.mouse_position != null) {
|
||||||
Input.processEvent(&self.frame, .{
|
self.input.processEvent(&self.frame, .{
|
||||||
.mouse_leave = {}
|
.mouse_leave = {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mouse_inside = false;
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
.MOUSE_SCROLL => {
|
.MOUSE_SCROLL => {
|
||||||
Input.processEvent(&self.frame, .{
|
self.input.processEvent(&self.frame, .{
|
||||||
.mouse_scroll = Vec2.init(e.scroll_x, e.scroll_y)
|
.mouse_scroll = Vec2.init(e.scroll_x, e.scroll_y)
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
.KEY_DOWN => {
|
.KEY_DOWN => {
|
||||||
Input.processEvent(&self.frame, .{
|
const key_code = Input.getKeyCodeFromSokol(e.key_code) orelse break :blk;
|
||||||
|
|
||||||
|
self.input.processEvent(&self.frame, .{
|
||||||
.key_pressed = .{
|
.key_pressed = .{
|
||||||
.code = @enumFromInt(@intFromEnum(e.key_code)),
|
.code = key_code,
|
||||||
.repeat = e.key_repeat
|
.repeat = e.key_repeat
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -397,14 +387,16 @@ fn sokolEvent(self: *Engine, e_ptr: [*c]const sapp.Event) !bool {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
.KEY_UP => {
|
.KEY_UP => {
|
||||||
Input.processEvent(&self.frame, .{
|
const key_code = Input.getKeyCodeFromSokol(e.key_code) orelse break :blk;
|
||||||
.key_released = @enumFromInt(@intFromEnum(e.key_code))
|
|
||||||
|
self.input.processEvent(&self.frame, .{
|
||||||
|
.key_released = key_code
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
.CHAR => {
|
.CHAR => {
|
||||||
Input.processEvent(&self.frame, .{
|
self.input.processEvent(&self.frame, .{
|
||||||
.char = @intCast(e.char_code)
|
.char = @intCast(e.char_code)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1,11 +1,12 @@
|
|||||||
const Gfx = @import("./graphics.zig");
|
const Gfx = @import("./graphics.zig");
|
||||||
|
|
||||||
const Math = @import("./math.zig");
|
const Math = @import("lib").Math;
|
||||||
const Vec2 = Math.Vec2;
|
const Vec2 = Math.Vec2;
|
||||||
const Vec4 = Math.Vec4;
|
const Vec4 = Math.Vec4;
|
||||||
const rgb = Math.rgb;
|
const rgb = Math.rgb;
|
||||||
|
|
||||||
const Frame = @import("./frame.zig");
|
const Lib = @import("lib");
|
||||||
|
const Frame = Lib.Frame;
|
||||||
|
|
||||||
const ScreenScalar = @This();
|
const ScreenScalar = @This();
|
||||||
|
|
||||||
@ -34,30 +35,30 @@ pub fn init(window_size: Vec2, canvas_size: Vec2) ScreenScalar {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply(self: ScreenScalar, window_size: Vec2, frame: *Frame, color: Vec4) void {
|
pub fn push(self: ScreenScalar, frame: *Frame) void {
|
||||||
const scale = self.scale;
|
const scale = self.scale;
|
||||||
const translation = self.translation;
|
const translation = self.translation;
|
||||||
|
|
||||||
frame.prependGraphicsCommand(.{
|
frame.pushTransform(translation, .init(scale, scale));
|
||||||
.push_transformation = .{
|
}
|
||||||
.translation = translation,
|
|
||||||
.scale = .init(scale, scale)
|
pub fn pop(self: ScreenScalar, frame: *Frame, color: Vec4) void {
|
||||||
}
|
const translation = self.translation;
|
||||||
});
|
|
||||||
frame.popTransform();
|
frame.popTransform();
|
||||||
|
|
||||||
frame.drawRectangle(.{
|
frame.drawRectangle(.{
|
||||||
.rect = .{
|
.rect = .{
|
||||||
.pos = .init(0, 0),
|
.pos = .init(0, 0),
|
||||||
.size = .init(window_size.x, translation.y),
|
.size = .init(frame.screen_size.x, translation.y),
|
||||||
},
|
},
|
||||||
.color = color
|
.color = color
|
||||||
});
|
});
|
||||||
|
|
||||||
frame.drawRectangle(.{
|
frame.drawRectangle(.{
|
||||||
.rect = .{
|
.rect = .{
|
||||||
.pos = .init(0, window_size.y - translation.y),
|
.pos = .init(0, frame.screen_size.y - translation.y),
|
||||||
.size = .init(window_size.x, translation.y),
|
.size = .init(frame.screen_size.x, translation.y),
|
||||||
},
|
},
|
||||||
.color = color
|
.color = color
|
||||||
});
|
});
|
||||||
@ -65,15 +66,15 @@ pub fn apply(self: ScreenScalar, window_size: Vec2, frame: *Frame, color: Vec4)
|
|||||||
frame.drawRectangle(.{
|
frame.drawRectangle(.{
|
||||||
.rect = .{
|
.rect = .{
|
||||||
.pos = .init(0, 0),
|
.pos = .init(0, 0),
|
||||||
.size = .init(translation.x, window_size.y),
|
.size = .init(translation.x, frame.screen_size.y),
|
||||||
},
|
},
|
||||||
.color = color
|
.color = color
|
||||||
});
|
});
|
||||||
|
|
||||||
frame.drawRectangle(.{
|
frame.drawRectangle(.{
|
||||||
.rect = .{
|
.rect = .{
|
||||||
.pos = .init(window_size.x - translation.x, 0),
|
.pos = .init(frame.screen_size.x - translation.x, 0),
|
||||||
.size = .init(translation.x, window_size.y),
|
.size = .init(translation.x, frame.screen_size.y),
|
||||||
},
|
},
|
||||||
.color = color
|
.color = color
|
||||||
});
|
});
|
||||||
16
src/game.zig
16
src/game.zig
@ -3,11 +3,9 @@ const Allocator = std.mem.Allocator;
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
const Engine = @import("engine");
|
const Engine = @import("engine");
|
||||||
const imgui = Engine.imgui;
|
const FontId = Engine.FontId;
|
||||||
const Vec2 = Engine.Vec2;
|
const Vec2 = Engine.Math.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();
|
||||||
|
|
||||||
@ -16,7 +14,7 @@ const FontName = enum {
|
|||||||
bold,
|
bold,
|
||||||
italic,
|
italic,
|
||||||
|
|
||||||
const EnumArray = std.EnumArray(FontName, Gfx.Font.Id);
|
const EnumArray = std.EnumArray(FontName, FontId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const State = struct {
|
const State = struct {
|
||||||
@ -29,7 +27,7 @@ const State = struct {
|
|||||||
|
|
||||||
var g_state: *State = undefined;
|
var g_state: *State = undefined;
|
||||||
|
|
||||||
pub export fn init(opts: *const Engine.InitOptions) void {
|
pub export fn init(opts: *const Engine.Init) void {
|
||||||
const gpa = opts.gpa;
|
const gpa = opts.gpa;
|
||||||
|
|
||||||
// const font_id_array: FontName.EnumArray = .init(.{
|
// const font_id_array: FontName.EnumArray = .init(.{
|
||||||
@ -63,7 +61,7 @@ pub export fn tick(frame: *Engine.Frame) void {
|
|||||||
const dt = frame.deltaTime();
|
const dt = frame.deltaTime();
|
||||||
|
|
||||||
const canvas_size = Vec2.init(100, 100);
|
const canvas_size = Vec2.init(100, 100);
|
||||||
frame.graphics.canvas_size = canvas_size;
|
frame.canvas_size = canvas_size;
|
||||||
|
|
||||||
if (frame.isKeyPressed(.F3)) {
|
if (frame.isKeyPressed(.F3)) {
|
||||||
frame.show_debug = !frame.show_debug;
|
frame.show_debug = !frame.show_debug;
|
||||||
@ -116,6 +114,6 @@ pub export fn tick(frame: *Engine.Frame) void {
|
|||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub export fn debug() void {
|
pub export fn debug(imgui: *Engine.ImGui) void {
|
||||||
imgui.text("Hello World!\n");
|
imgui.text("Hello World!\n", .{});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user