split engine to separate library
This commit is contained in:
parent
8434ea6a64
commit
e5fccc21f2
299
build.zig
299
build.zig
@ -1,161 +1,32 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const sokol = @import("sokol");
|
const Engine = @import("engine");
|
||||||
const builtin = @import("builtin");
|
|
||||||
|
|
||||||
pub fn build(b: *std.Build) !void {
|
pub fn build(b: *std.Build) !void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
const has_imgui = b.option(bool, "imgui", "ImGui integration") orelse (optimize == .Debug);
|
const mod = b.createModule(.{
|
||||||
var has_tracy = b.option(bool, "tracy", "Tracy integration") orelse (optimize == .Debug);
|
.root_source_file = b.path("src/game.zig"),
|
||||||
const has_console = b.option(bool, "console", "Show console (Window only)") orelse (optimize == .Debug);
|
|
||||||
|
|
||||||
const isWasm = target.result.cpu.arch.isWasm();
|
|
||||||
|
|
||||||
if (isWasm) {
|
|
||||||
has_tracy = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mod_main = b.createModule(.{
|
|
||||||
.root_source_file = b.path("src/main.zig"),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.link_libc = true
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const dep_sokol = b.dependency("sokol", .{
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.with_sokol_imgui = has_imgui,
|
|
||||||
});
|
|
||||||
mod_main.linkLibrary(dep_sokol.artifact("sokol_clib"));
|
|
||||||
mod_main.addImport("sokol", dep_sokol.module("sokol"));
|
|
||||||
|
|
||||||
if (has_imgui) {
|
|
||||||
if (b.lazyDependency("cimgui", .{
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
})) |dep_cimgui| {
|
|
||||||
const cimgui = b.lazyImport(@This(), "cimgui").?;
|
|
||||||
const cimgui_conf = cimgui.getConfig(false);
|
|
||||||
mod_main.addImport("cimgui", dep_cimgui.module(cimgui_conf.module_name));
|
|
||||||
dep_sokol.artifact("sokol_clib").addIncludePath(dep_cimgui.path(cimgui_conf.include_dir));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const dep_tracy = b.dependency("tracy", .{
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.tracy_enable = has_tracy,
|
|
||||||
.tracy_only_localhost = true
|
|
||||||
});
|
|
||||||
if (has_tracy) {
|
|
||||||
mod_main.linkLibrary(dep_tracy.artifact("tracy"));
|
|
||||||
}
|
|
||||||
mod_main.addImport("tracy", dep_tracy.module("tracy"));
|
|
||||||
|
|
||||||
const dep_tiled = b.dependency("tiled", .{});
|
const dep_tiled = b.dependency("tiled", .{});
|
||||||
mod_main.addImport("tiled", dep_tiled.module("tiled"));
|
mod.addImport("tiled", dep_tiled.module("tiled"));
|
||||||
|
|
||||||
const dep_stb = b.dependency("stb", .{});
|
Engine.init(b, .{
|
||||||
mod_main.addImport("stb_image", dep_stb.module("stb_image"));
|
.name = "sokol_template",
|
||||||
mod_main.addImport("stb_vorbis", dep_stb.module("stb_vorbis"));
|
.root_module = mod,
|
||||||
|
.target = target,
|
||||||
const dep_fontstash_c = b.dependency("fontstash_c", .{});
|
.optimize = optimize,
|
||||||
mod_main.addIncludePath(dep_fontstash_c.path("src"));
|
.dep_engine = b.dependency("engine", .{}),
|
||||||
|
.has_imgui = b.option(bool, "imgui", "ImGui integration"),
|
||||||
const dep_sokol_c = b.dependency("sokol_c", .{});
|
.has_tracy = b.option(bool, "tracy", "Tracy integration"),
|
||||||
{
|
.win32_has_console = b.option(bool, "console", "Show console (Window only)"),
|
||||||
var cflags_buffer: [64][]const u8 = undefined;
|
.win32_png_icon = b.path("src/assets/icon.png")
|
||||||
var cflags = std.ArrayListUnmanaged([]const u8).initBuffer(&cflags_buffer);
|
|
||||||
switch (sokol.resolveSokolBackend(.auto, target.result)) {
|
|
||||||
.d3d11 => try cflags.appendBounded("-DSOKOL_D3D11"),
|
|
||||||
.metal => try cflags.appendBounded("-DSOKOL_METAL"),
|
|
||||||
.gl => try cflags.appendBounded("-DSOKOL_GLCORE"),
|
|
||||||
.gles3 => try cflags.appendBounded("-DSOKOL_GLES3"),
|
|
||||||
.wgpu => try cflags.appendBounded("-DSOKOL_WGPU"),
|
|
||||||
else => @panic("unknown sokol backend"),
|
|
||||||
}
|
|
||||||
|
|
||||||
mod_main.addIncludePath(dep_sokol_c.path("util"));
|
|
||||||
mod_main.addCSourceFile(.{
|
|
||||||
.file = b.path("src/engine/fontstash/sokol_fontstash_impl.c"),
|
|
||||||
.flags = cflags.items
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// const sdl = b.dependency("sdl", .{
|
|
||||||
// .optimize = optimize,
|
|
||||||
// .target = target,
|
|
||||||
// .linkage = .static,
|
|
||||||
// .default_target_config = !isWasm
|
|
||||||
// });
|
|
||||||
// mod_main.linkLibrary(sdl.artifact("SDL3"));
|
|
||||||
// if (isWasm) {
|
|
||||||
// // TODO: Define buid config for wasm
|
|
||||||
// }
|
|
||||||
|
|
||||||
var options = b.addOptions();
|
|
||||||
options.addOption(bool, "has_imgui", has_imgui);
|
|
||||||
options.addOption(bool, "has_tracy", has_tracy);
|
|
||||||
mod_main.addOptions("build_options", options);
|
|
||||||
|
|
||||||
// from here on different handling for native vs wasm builds
|
|
||||||
if (target.result.cpu.arch.isWasm()) {
|
|
||||||
try buildWasm(b, .{
|
|
||||||
.name = "sokol_template",
|
|
||||||
.mod_main = mod_main,
|
|
||||||
.dep_sokol = dep_sokol,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
try buildNative(b, "sokol_template", mod_main, has_console);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn buildNative(b: *std.Build, name: []const u8, mod: *std.Build.Module, has_console: bool) !void {
|
|
||||||
const exe = b.addExecutable(.{
|
|
||||||
.name = name,
|
|
||||||
.root_module = mod
|
|
||||||
});
|
});
|
||||||
const target = mod.resolved_target.?;
|
|
||||||
if (target.result.os.tag == .windows) {
|
|
||||||
exe.subsystem = if (has_console) .Console else .Windows;
|
|
||||||
|
|
||||||
const png_to_icon_tool = b.addExecutable(.{
|
|
||||||
.name = "png-to-icon",
|
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.target = b.graph.host,
|
|
||||||
.root_source_file = b.path("tools/png-to-icon.zig"),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
const dep_stb_image = b.dependency("stb_image", .{});
|
|
||||||
png_to_icon_tool.root_module.addImport("stb_image", dep_stb_image.module("stb_image"));
|
|
||||||
|
|
||||||
const png_to_icon_step = b.addRunArtifact(png_to_icon_tool);
|
|
||||||
png_to_icon_step.addFileArg(b.path("src/assets/icon.png"));
|
|
||||||
const icon_file = png_to_icon_step.addOutputFileArg("icon.ico");
|
|
||||||
|
|
||||||
const add_icon_step = AddExecutableIcon.init(exe, icon_file);
|
|
||||||
exe.step.dependOn(&add_icon_step.step);
|
|
||||||
}
|
|
||||||
b.installArtifact(exe);
|
|
||||||
|
|
||||||
{
|
|
||||||
const run_step = b.step("run", "Run game");
|
|
||||||
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
|
||||||
run_step.dependOn(&run_cmd.step);
|
|
||||||
run_cmd.step.dependOn(b.getInstallStep());
|
|
||||||
|
|
||||||
if (b.args) |args| {
|
|
||||||
run_cmd.addArgs(args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
mod.resolved_target = target;
|
||||||
const exe_tests = b.addTest(.{
|
const exe_tests = b.addTest(.{
|
||||||
.root_module = exe.root_module,
|
.root_module = mod,
|
||||||
});
|
});
|
||||||
|
|
||||||
const run_exe_tests = b.addRunArtifact(exe_tests);
|
const run_exe_tests = b.addRunArtifact(exe_tests);
|
||||||
@ -164,141 +35,3 @@ fn buildNative(b: *std.Build, name: []const u8, mod: *std.Build.Module, has_cons
|
|||||||
test_step.dependOn(&run_exe_tests.step);
|
test_step.dependOn(&run_exe_tests.step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const BuildWasmOptions = struct {
|
|
||||||
name: []const u8,
|
|
||||||
mod_main: *std.Build.Module,
|
|
||||||
dep_sokol: *std.Build.Dependency,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn patchWasmIncludeDirs(
|
|
||||||
module: *std.Build.Module,
|
|
||||||
path: std.Build.LazyPath,
|
|
||||||
depend_step: *std.Build.Step
|
|
||||||
) void {
|
|
||||||
if (module.link_libc != null and module.link_libc.?) {
|
|
||||||
// need to inject the Emscripten system header include path into
|
|
||||||
// the cimgui C library otherwise the C/C++ code won't find
|
|
||||||
// C stdlib headers
|
|
||||||
module.addSystemIncludePath(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (module.import_table.values()) |imported_module| {
|
|
||||||
patchWasmIncludeDirs(imported_module, path, depend_step);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (module.link_objects.items) |link_object| {
|
|
||||||
if (link_object != .other_step) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const lib = link_object.other_step;
|
|
||||||
if (&lib.step == depend_step) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lib.root_module.link_libc != null and lib.root_module.link_libc.?) {
|
|
||||||
// need to inject the Emscripten system header include path into
|
|
||||||
// the cimgui C library otherwise the C/C++ code won't find
|
|
||||||
// C stdlib headers
|
|
||||||
lib.root_module.addSystemIncludePath(path);
|
|
||||||
|
|
||||||
// all C libraries need to depend on the sokol library, when building for
|
|
||||||
// WASM this makes sure that the Emscripten SDK has been setup before
|
|
||||||
// C compilation is attempted (since the sokol C library depends on the
|
|
||||||
// Emscripten SDK setup step)
|
|
||||||
lib.step.dependOn(depend_step);
|
|
||||||
}
|
|
||||||
patchWasmIncludeDirs(lib.root_module, path, depend_step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn buildWasm(b: *std.Build, opts: BuildWasmOptions) !void {
|
|
||||||
opts.mod_main.sanitize_c = .off;
|
|
||||||
|
|
||||||
// build the main file into a library, this is because the WASM 'exe'
|
|
||||||
// needs to be linked in a separate build step with the Emscripten linker
|
|
||||||
const main_lib = b.addLibrary(.{
|
|
||||||
.name = "index",
|
|
||||||
.root_module = opts.mod_main,
|
|
||||||
});
|
|
||||||
|
|
||||||
const dep_emsdk = opts.dep_sokol.builder.dependency("emsdk", .{});
|
|
||||||
|
|
||||||
patchWasmIncludeDirs(
|
|
||||||
opts.mod_main,
|
|
||||||
dep_emsdk.path("upstream/emscripten/cache/sysroot/include"),
|
|
||||||
&(opts.dep_sokol.artifact("sokol_clib").step)
|
|
||||||
);
|
|
||||||
|
|
||||||
// create a build step which invokes the Emscripten linker
|
|
||||||
const link_step = try sokol.emLinkStep(b, .{
|
|
||||||
.lib_main = main_lib,
|
|
||||||
.target = opts.mod_main.resolved_target.?,
|
|
||||||
.optimize = opts.mod_main.optimize.?,
|
|
||||||
.emsdk = dep_emsdk,
|
|
||||||
.use_webgl2 = true,
|
|
||||||
.use_emmalloc = true,
|
|
||||||
.use_filesystem = false,
|
|
||||||
.shell_file_path = b.path("src/engine/shell.html"),
|
|
||||||
});
|
|
||||||
// attach to default target
|
|
||||||
b.getInstallStep().dependOn(&link_step.step);
|
|
||||||
// ...and a special run step to start the web build output via 'emrun'
|
|
||||||
const run = sokol.emRunStep(b, .{ .name = "index", .emsdk = dep_emsdk });
|
|
||||||
run.step.dependOn(&link_step.step);
|
|
||||||
b.step("run", "Run game").dependOn(&run.step);
|
|
||||||
|
|
||||||
// TODO: Create a zip archive of all of the files. Would be useful for easier itch.io upload
|
|
||||||
}
|
|
||||||
|
|
||||||
const AddExecutableIcon = struct {
|
|
||||||
obj: *std.Build.Step.Compile,
|
|
||||||
step: std.Build.Step,
|
|
||||||
icon_file: std.Build.LazyPath,
|
|
||||||
resource_file: std.Build.LazyPath,
|
|
||||||
|
|
||||||
fn init(obj: *std.Build.Step.Compile, icon_file: std.Build.LazyPath) *AddExecutableIcon {
|
|
||||||
const b = obj.step.owner;
|
|
||||||
const self = b.allocator.create(AddExecutableIcon) catch @panic("OOM");
|
|
||||||
|
|
||||||
self.obj = obj;
|
|
||||||
self.step = std.Build.Step.init(.{
|
|
||||||
.id = .custom,
|
|
||||||
.name = "add executable icon",
|
|
||||||
.owner = b,
|
|
||||||
.makeFn = make
|
|
||||||
});
|
|
||||||
|
|
||||||
self.icon_file = icon_file;
|
|
||||||
icon_file.addStepDependencies(&self.step);
|
|
||||||
|
|
||||||
const write_files = b.addWriteFiles();
|
|
||||||
self.resource_file = write_files.add("resource-file.rc", "");
|
|
||||||
self.step.dependOn(&write_files.step);
|
|
||||||
|
|
||||||
self.obj.addWin32ResourceFile(.{
|
|
||||||
.file = self.resource_file,
|
|
||||||
});
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void {
|
|
||||||
const b = step.owner;
|
|
||||||
const self: *AddExecutableIcon = @fieldParentPtr("step", step);
|
|
||||||
|
|
||||||
const resource_file = try std.fs.cwd().createFile(self.resource_file.getPath(b), .{ });
|
|
||||||
defer resource_file.close();
|
|
||||||
|
|
||||||
const relative_icon_path = try std.fs.path.relative(
|
|
||||||
b.allocator,
|
|
||||||
self.resource_file.dirname().getPath(b),
|
|
||||||
self.icon_file.getPath(b)
|
|
||||||
);
|
|
||||||
std.mem.replaceScalar(u8, relative_icon_path, '\\', '/');
|
|
||||||
|
|
||||||
try resource_file.writeAll("IDI_ICON ICON \"");
|
|
||||||
try resource_file.writeAll(relative_icon_path);
|
|
||||||
try resource_file.writeAll("\"");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
@ -4,37 +4,12 @@
|
|||||||
.fingerprint = 0x60a8e079a691c8d9, // Changing this has security and trust implications.
|
.fingerprint = 0x60a8e079a691c8d9, // Changing this has security and trust implications.
|
||||||
.minimum_zig_version = "0.15.2",
|
.minimum_zig_version = "0.15.2",
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.sokol = .{
|
|
||||||
.url = "git+https://github.com/floooh/sokol-zig.git#aaf291ca2d3d1cedc05d65f5a1cacae0f53d934a",
|
|
||||||
.hash = "sokol-0.1.0-pb1HK4iDNgCom5dkY66eUBm_bYBHEl8KWFDAiqwWgpEy",
|
|
||||||
},
|
|
||||||
.sokol_c = .{
|
|
||||||
.url = "git+https://github.com/floooh/sokol.git#c66a1f04e6495d635c5e913335ab2308281e0492",
|
|
||||||
.hash = "N-V-__8AAC3eYABB1DVLb4dkcEzq_xVeEZZugVfQ6DoNQBDN",
|
|
||||||
},
|
|
||||||
.fontstash_c = .{
|
|
||||||
.url = "git+https://github.com/memononen/fontstash.git#b5ddc9741061343740d85d636d782ed3e07cf7be",
|
|
||||||
.hash = "N-V-__8AAA9xHgAxdLYPmlNTy6qzv9IYqiIePEHQUOPWYQ_6",
|
|
||||||
},
|
|
||||||
.cimgui = .{
|
|
||||||
.url = "git+https://github.com/floooh/dcimgui.git#33c99ef426b68030412b5a4b11487a23da9d4f13",
|
|
||||||
.hash = "cimgui-0.1.0-44ClkQRJlABdFMKRqIG8KDD6jy1eQbgPO335NziPYjmL",
|
|
||||||
.lazy = true,
|
|
||||||
},
|
|
||||||
.tracy = .{
|
|
||||||
.url = "git+https://github.com/sagehane/zig-tracy.git#80933723efe9bf840fe749b0bfc0d610f1db1669",
|
|
||||||
.hash = "zig_tracy-0.0.5-aOIqsX1tAACKaRRB-sraMLuNiMASXi_y-4FtRuw4cTpx",
|
|
||||||
},
|
|
||||||
.tiled = .{
|
.tiled = .{
|
||||||
.path = "./libs/tiled",
|
.path = "./libs/tiled",
|
||||||
},
|
},
|
||||||
.stb = .{
|
.engine = .{
|
||||||
.path = "./libs/stb",
|
.path = "./engine/",
|
||||||
},
|
},
|
||||||
// .sdl = .{
|
|
||||||
// .url = "git+https://github.com/allyourcodebase/SDL3.git#f85824b0db782b7d01c60aaad8bcb537892394e8",
|
|
||||||
// .hash = "sdl-0.0.0-i4QD0UuFqADRQysNyJ1OvCOZnq-clcVhq3BfPcBOf9zr",
|
|
||||||
// },
|
|
||||||
},
|
},
|
||||||
.paths = .{
|
.paths = .{
|
||||||
"build.zig",
|
"build.zig",
|
||||||
|
|||||||
385
engine/build.zig
Normal file
385
engine/build.zig
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const sokol = @import("sokol");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) !void {
|
||||||
|
_ = b; // autofix
|
||||||
|
}
|
||||||
|
|
||||||
|
const InitOptions = struct {
|
||||||
|
name: []const u8,
|
||||||
|
root_module: *std.Build.Module,
|
||||||
|
|
||||||
|
target: std.Build.ResolvedTarget,
|
||||||
|
optimize: std.builtin.OptimizeMode,
|
||||||
|
|
||||||
|
dep_engine: *std.Build.Dependency,
|
||||||
|
|
||||||
|
has_imgui: ?bool = null,
|
||||||
|
has_tracy: ?bool = null,
|
||||||
|
win32_has_console: ?bool = null,
|
||||||
|
win32_png_icon: ?std.Build.LazyPath = null
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(outer_builder: *std.Build, opts: InitOptions) void {
|
||||||
|
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.optimize = opts.optimize;
|
||||||
|
const game_lib = b.addLibrary(.{
|
||||||
|
.name = "game",
|
||||||
|
.root_module = opts.root_module,
|
||||||
|
.linkage = .static,
|
||||||
|
});
|
||||||
|
opts.root_module.addImport("engine", engine_module.root_module);
|
||||||
|
|
||||||
|
const mod_main = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.link_libc = true
|
||||||
|
});
|
||||||
|
mod_main.addImport("engine", engine_module.root_module);
|
||||||
|
mod_main.linkLibrary(game_lib);
|
||||||
|
|
||||||
|
var run_cmd_step: *std.Build.Step = undefined;
|
||||||
|
if (opts.target.result.cpu.arch.isWasm()) {
|
||||||
|
const build_step = buildWasm(b, .{
|
||||||
|
.name = "index",
|
||||||
|
.root_module = mod_main,
|
||||||
|
.dep_sokol = engine_module.dep_sokol,
|
||||||
|
.outer_builder = outer_builder
|
||||||
|
});
|
||||||
|
outer_builder.getInstallStep().dependOn(build_step);
|
||||||
|
|
||||||
|
const dep_sokol = engine_module.dep_sokol;
|
||||||
|
const dep_emsdk = dep_sokol.builder.dependency("emsdk", .{});
|
||||||
|
const emrun_step = sokol.emRunStep(b, .{ .name = "index", .emsdk = dep_emsdk });
|
||||||
|
emrun_step.step.dependOn(build_step);
|
||||||
|
run_cmd_step = &emrun_step.step;
|
||||||
|
|
||||||
|
// TODO: Create a zip archive of all of the files. Would be useful for easier itch.io upload
|
||||||
|
} else {
|
||||||
|
const exe = buildNative(b, .{
|
||||||
|
.name = opts.name,
|
||||||
|
.root_module = mod_main,
|
||||||
|
.win32_has_console = opts.win32_has_console,
|
||||||
|
.win32_png_icon = opts.win32_png_icon
|
||||||
|
});
|
||||||
|
outer_builder.installArtifact(exe);
|
||||||
|
|
||||||
|
{
|
||||||
|
const run_cmd = outer_builder.addRunArtifact(exe);
|
||||||
|
if (outer_builder.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
run_cmd_step = &run_cmd.step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const run_step = outer_builder.step("run", "Run game");
|
||||||
|
run_step.dependOn(run_cmd_step);
|
||||||
|
}
|
||||||
|
|
||||||
|
const EngineModule = struct {
|
||||||
|
root_module: *std.Build.Module,
|
||||||
|
dep_sokol: *std.Build.Dependency,
|
||||||
|
|
||||||
|
const Options = struct {
|
||||||
|
target: std.Build.ResolvedTarget,
|
||||||
|
optimize: std.builtin.OptimizeMode,
|
||||||
|
|
||||||
|
has_imgui: ?bool = null,
|
||||||
|
has_tracy: ?bool = null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fn createEngineModule(b: *std.Build, opts: EngineModule.Options) EngineModule {
|
||||||
|
const has_imgui = opts.has_imgui orelse (opts.optimize == .Debug);
|
||||||
|
var has_tracy = opts.has_tracy orelse (opts.optimize == .Debug);
|
||||||
|
const isWasm = opts.target.result.cpu.arch.isWasm();
|
||||||
|
|
||||||
|
if (isWasm) {
|
||||||
|
has_tracy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/root.zig"),
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.link_libc = true
|
||||||
|
});
|
||||||
|
|
||||||
|
const dep_sokol = b.dependency("sokol", .{
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.with_sokol_imgui = has_imgui,
|
||||||
|
});
|
||||||
|
mod.linkLibrary(dep_sokol.artifact("sokol_clib"));
|
||||||
|
mod.addImport("sokol", dep_sokol.module("sokol"));
|
||||||
|
|
||||||
|
if (has_imgui) {
|
||||||
|
if (b.lazyDependency("cimgui", .{
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
})) |dep_cimgui| {
|
||||||
|
const cimgui = b.lazyImport(@This(), "cimgui").?;
|
||||||
|
const cimgui_conf = cimgui.getConfig(false);
|
||||||
|
mod.addImport("cimgui", dep_cimgui.module(cimgui_conf.module_name));
|
||||||
|
dep_sokol.artifact("sokol_clib").addIncludePath(dep_cimgui.path(cimgui_conf.include_dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dep_tracy = b.dependency("tracy", .{
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.tracy_enable = has_tracy,
|
||||||
|
.tracy_only_localhost = true
|
||||||
|
});
|
||||||
|
if (has_tracy) {
|
||||||
|
mod.linkLibrary(dep_tracy.artifact("tracy"));
|
||||||
|
}
|
||||||
|
mod.addImport("tracy", dep_tracy.module("tracy"));
|
||||||
|
|
||||||
|
const dep_stb = b.dependency("stb", .{});
|
||||||
|
mod.addImport("stb_image", dep_stb.module("stb_image"));
|
||||||
|
mod.addImport("stb_vorbis", dep_stb.module("stb_vorbis"));
|
||||||
|
|
||||||
|
const dep_fontstash_c = b.dependency("fontstash_c", .{});
|
||||||
|
mod.addIncludePath(dep_fontstash_c.path("src"));
|
||||||
|
|
||||||
|
const dep_sokol_c = b.dependency("sokol_c", .{});
|
||||||
|
{
|
||||||
|
var cflags_buffer: [64][]const u8 = undefined;
|
||||||
|
var cflags = std.ArrayListUnmanaged([]const u8).initBuffer(&cflags_buffer);
|
||||||
|
switch (sokol.resolveSokolBackend(.auto, opts.target.result)) {
|
||||||
|
.d3d11 => cflags.appendAssumeCapacity("-DSOKOL_D3D11"),
|
||||||
|
.metal => cflags.appendAssumeCapacity("-DSOKOL_METAL"),
|
||||||
|
.gl => cflags.appendAssumeCapacity("-DSOKOL_GLCORE"),
|
||||||
|
.gles3 => cflags.appendAssumeCapacity("-DSOKOL_GLES3"),
|
||||||
|
.wgpu => cflags.appendAssumeCapacity("-DSOKOL_WGPU"),
|
||||||
|
else => @panic("unknown sokol backend"),
|
||||||
|
}
|
||||||
|
|
||||||
|
mod.addIncludePath(dep_sokol_c.path("util"));
|
||||||
|
mod.addCSourceFile(.{
|
||||||
|
.file = b.path("src/fontstash/sokol_fontstash_impl.c"),
|
||||||
|
.flags = cflags.items
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// const sdl = b.dependency("sdl", Run game.{
|
||||||
|
// .optimize = optimize,
|
||||||
|
// .target = target,
|
||||||
|
// .linkage = .static,
|
||||||
|
// .default_target_config = !isWasm
|
||||||
|
// });
|
||||||
|
// mod_main.linkLibrary(sdl.artifact("SDL3"));
|
||||||
|
// if (isWasm) {
|
||||||
|
// // TODO: Define buid config for wasm
|
||||||
|
// }
|
||||||
|
|
||||||
|
var options = b.addOptions();
|
||||||
|
options.addOption(bool, "has_imgui", has_imgui);
|
||||||
|
options.addOption(bool, "has_tracy", has_tracy);
|
||||||
|
mod.addOptions("build_options", options);
|
||||||
|
|
||||||
|
return EngineModule{
|
||||||
|
.root_module = mod,
|
||||||
|
.dep_sokol = dep_sokol
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn buildPngToIconTool(
|
||||||
|
b: *std.Build,
|
||||||
|
target: std.Build.ResolvedTarget,
|
||||||
|
optimize: std.builtin.OptimizeMode,
|
||||||
|
) *std.Build.Step.Compile {
|
||||||
|
const mod = b.createModule(.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("tools/png-to-icon.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const dep_stb = b.dependency("stb", .{});
|
||||||
|
mod.addImport("stb_image", dep_stb.module("stb_image"));
|
||||||
|
|
||||||
|
return b.addExecutable(.{
|
||||||
|
.name = "png-to-icon",
|
||||||
|
.root_module = mod,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const BuildNativeOptions = struct {
|
||||||
|
name: []const u8,
|
||||||
|
root_module: *std.Build.Module,
|
||||||
|
win32_has_console: ?bool = null,
|
||||||
|
win32_png_icon: ?std.Build.LazyPath = null
|
||||||
|
};
|
||||||
|
|
||||||
|
fn buildNative(b: *std.Build, opts: BuildNativeOptions) *std.Build.Step.Compile {
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = opts.name,
|
||||||
|
.root_module = opts.root_module
|
||||||
|
});
|
||||||
|
|
||||||
|
const target = opts.root_module.resolved_target.?;
|
||||||
|
if (target.result.os.tag == .windows) {
|
||||||
|
const optimize = opts.root_module.optimize.?;
|
||||||
|
const has_console = opts.win32_has_console orelse (optimize == .Debug);
|
||||||
|
exe.subsystem = if (has_console) .Console else .Windows;
|
||||||
|
|
||||||
|
if (opts.win32_png_icon) |win32_png_icon| {
|
||||||
|
const png_to_icon_tool = buildPngToIconTool(b, b.graph.host, .ReleaseSafe);
|
||||||
|
|
||||||
|
const png_to_icon_step = b.addRunArtifact(png_to_icon_tool);
|
||||||
|
png_to_icon_step.addFileArg(win32_png_icon);
|
||||||
|
const icon_file = png_to_icon_step.addOutputFileArg("icon.ico");
|
||||||
|
|
||||||
|
const add_icon_step = AddExecutableIcon.init(exe, icon_file);
|
||||||
|
exe.step.dependOn(&add_icon_step.step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exe;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BuildWasmOptions = struct {
|
||||||
|
name: []const u8,
|
||||||
|
root_module: *std.Build.Module,
|
||||||
|
dep_sokol: *std.Build.Dependency,
|
||||||
|
outer_builder: *std.Build
|
||||||
|
};
|
||||||
|
|
||||||
|
fn buildWasm(b: *std.Build, opts: BuildWasmOptions) *std.Build.Step {
|
||||||
|
opts.root_module.sanitize_c = .off;
|
||||||
|
|
||||||
|
// build the main file into a library, this is because the WASM 'exe'
|
||||||
|
// needs to be linked in a separate build step with the Emscripten linker
|
||||||
|
const main_lib = b.addLibrary(.{
|
||||||
|
.name = opts.name,
|
||||||
|
.root_module = opts.root_module,
|
||||||
|
});
|
||||||
|
|
||||||
|
const dep_sokol = opts.dep_sokol;
|
||||||
|
const dep_emsdk = dep_sokol.builder.dependency("emsdk", .{});
|
||||||
|
|
||||||
|
patchWasmIncludeDirs(
|
||||||
|
opts.root_module,
|
||||||
|
dep_emsdk.path("upstream/emscripten/cache/sysroot/include"),
|
||||||
|
&(dep_sokol.artifact("sokol_clib").step)
|
||||||
|
);
|
||||||
|
|
||||||
|
const link_step = sokol.emLinkStep(opts.outer_builder, .{
|
||||||
|
.lib_main = main_lib,
|
||||||
|
.target = opts.root_module.resolved_target.?,
|
||||||
|
.optimize = opts.root_module.optimize.?,
|
||||||
|
.emsdk = dep_emsdk,
|
||||||
|
.use_webgl2 = true,
|
||||||
|
.use_emmalloc = true,
|
||||||
|
.use_filesystem = false,
|
||||||
|
.shell_file_path = b.path("src/shell.html"),
|
||||||
|
}) catch unreachable;
|
||||||
|
|
||||||
|
return &link_step.step;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patchWasmIncludeDirs(
|
||||||
|
module: *std.Build.Module,
|
||||||
|
path: std.Build.LazyPath,
|
||||||
|
depend_step: *std.Build.Step
|
||||||
|
) void {
|
||||||
|
if (module.link_libc != null and module.link_libc.?) {
|
||||||
|
// need to inject the Emscripten system header include path into
|
||||||
|
// the cimgui C library otherwise the C/C++ code won't find
|
||||||
|
// C stdlib headers
|
||||||
|
module.addSystemIncludePath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (module.import_table.values()) |imported_module| {
|
||||||
|
patchWasmIncludeDirs(imported_module, path, depend_step);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (module.link_objects.items) |link_object| {
|
||||||
|
if (link_object != .other_step) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const lib = link_object.other_step;
|
||||||
|
if (&lib.step == depend_step) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lib.root_module.link_libc != null and lib.root_module.link_libc.?) {
|
||||||
|
// need to inject the Emscripten system header include path into
|
||||||
|
// the cimgui C library otherwise the C/C++ code won't find
|
||||||
|
// C stdlib headers
|
||||||
|
lib.root_module.addSystemIncludePath(path);
|
||||||
|
|
||||||
|
// all C libraries need to depend on the sokol library, when building for
|
||||||
|
// WASM this makes sure that the Emscripten SDK has been setup before
|
||||||
|
// C compilation is attempted (since the sokol C library depends on the
|
||||||
|
// Emscripten SDK setup step)
|
||||||
|
lib.step.dependOn(depend_step);
|
||||||
|
}
|
||||||
|
patchWasmIncludeDirs(lib.root_module, path, depend_step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const AddExecutableIcon = struct {
|
||||||
|
obj: *std.Build.Step.Compile,
|
||||||
|
step: std.Build.Step,
|
||||||
|
icon_file: std.Build.LazyPath,
|
||||||
|
resource_file: std.Build.LazyPath,
|
||||||
|
|
||||||
|
fn init(obj: *std.Build.Step.Compile, icon_file: std.Build.LazyPath) *AddExecutableIcon {
|
||||||
|
const b = obj.step.owner;
|
||||||
|
const self = b.allocator.create(AddExecutableIcon) catch @panic("OOM");
|
||||||
|
|
||||||
|
self.obj = obj;
|
||||||
|
self.step = std.Build.Step.init(.{
|
||||||
|
.id = .custom,
|
||||||
|
.name = "add executable icon",
|
||||||
|
.owner = b,
|
||||||
|
.makeFn = make
|
||||||
|
});
|
||||||
|
|
||||||
|
self.icon_file = icon_file;
|
||||||
|
icon_file.addStepDependencies(&self.step);
|
||||||
|
|
||||||
|
const write_files = b.addWriteFiles();
|
||||||
|
self.resource_file = write_files.add("resource-file.rc", "");
|
||||||
|
self.step.dependOn(&write_files.step);
|
||||||
|
|
||||||
|
self.obj.addWin32ResourceFile(.{
|
||||||
|
.file = self.resource_file,
|
||||||
|
});
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void {
|
||||||
|
const b = step.owner;
|
||||||
|
const self: *AddExecutableIcon = @fieldParentPtr("step", step);
|
||||||
|
|
||||||
|
const resource_file = try std.fs.cwd().createFile(self.resource_file.getPath(b), .{ });
|
||||||
|
defer resource_file.close();
|
||||||
|
|
||||||
|
const relative_icon_path = try std.fs.path.relative(
|
||||||
|
b.allocator,
|
||||||
|
self.resource_file.dirname().getPath(b),
|
||||||
|
self.icon_file.getPath(b)
|
||||||
|
);
|
||||||
|
std.mem.replaceScalar(u8, relative_icon_path, '\\', '/');
|
||||||
|
|
||||||
|
try resource_file.writeAll("IDI_ICON ICON \"");
|
||||||
|
try resource_file.writeAll(relative_icon_path);
|
||||||
|
try resource_file.writeAll("\"");
|
||||||
|
}
|
||||||
|
};
|
||||||
42
engine/build.zig.zon
Normal file
42
engine/build.zig.zon
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
.{
|
||||||
|
.name = .engine,
|
||||||
|
.version = "0.0.0",
|
||||||
|
.fingerprint = 0xe8a81a8d6fb6f0fb,
|
||||||
|
.minimum_zig_version = "0.15.2",
|
||||||
|
.dependencies = .{
|
||||||
|
.sokol = .{
|
||||||
|
.url = "git+https://github.com/floooh/sokol-zig.git#aaf291ca2d3d1cedc05d65f5a1cacae0f53d934a",
|
||||||
|
.hash = "sokol-0.1.0-pb1HK4iDNgCom5dkY66eUBm_bYBHEl8KWFDAiqwWgpEy",
|
||||||
|
},
|
||||||
|
.sokol_c = .{
|
||||||
|
.url = "git+https://github.com/floooh/sokol.git#c66a1f04e6495d635c5e913335ab2308281e0492",
|
||||||
|
.hash = "N-V-__8AAC3eYABB1DVLb4dkcEzq_xVeEZZugVfQ6DoNQBDN",
|
||||||
|
},
|
||||||
|
.fontstash_c = .{
|
||||||
|
.url = "git+https://github.com/memononen/fontstash.git#b5ddc9741061343740d85d636d782ed3e07cf7be",
|
||||||
|
.hash = "N-V-__8AAA9xHgAxdLYPmlNTy6qzv9IYqiIePEHQUOPWYQ_6",
|
||||||
|
},
|
||||||
|
.cimgui = .{
|
||||||
|
.url = "git+https://github.com/floooh/dcimgui.git#33c99ef426b68030412b5a4b11487a23da9d4f13",
|
||||||
|
.hash = "cimgui-0.1.0-44ClkQRJlABdFMKRqIG8KDD6jy1eQbgPO335NziPYjmL",
|
||||||
|
.lazy = true,
|
||||||
|
},
|
||||||
|
.tracy = .{
|
||||||
|
.url = "git+https://github.com/sagehane/zig-tracy.git#80933723efe9bf840fe749b0bfc0d610f1db1669",
|
||||||
|
.hash = "zig_tracy-0.0.5-aOIqsX1tAACKaRRB-sraMLuNiMASXi_y-4FtRuw4cTpx",
|
||||||
|
},
|
||||||
|
.stb = .{
|
||||||
|
.path = "./libs/stb",
|
||||||
|
},
|
||||||
|
// .sdl = .{
|
||||||
|
// .url = "git+https://github.com/allyourcodebase/SDL3.git#f85824b0db782b7d01c60aaad8bcb537892394e8",
|
||||||
|
// .hash = "sdl-0.0.0-i4QD0UuFqADRQysNyJ1OvCOZnq-clcVhq3BfPcBOf9zr",
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
.paths = .{
|
||||||
|
"build.zig",
|
||||||
|
"build.zig.zon",
|
||||||
|
"src",
|
||||||
|
"tools",
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -23,6 +23,8 @@ pub const Font = fontstash.Font;
|
|||||||
|
|
||||||
const GraphicsFrame = @import("./frame.zig").Graphics;
|
const GraphicsFrame = @import("./frame.zig").Graphics;
|
||||||
|
|
||||||
|
const Graphics = @This();
|
||||||
|
|
||||||
// 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?
|
||||||
@ -97,20 +99,16 @@ pub const Sprite = struct {
|
|||||||
uv: Rect,
|
uv: Rect,
|
||||||
};
|
};
|
||||||
|
|
||||||
var gpa: std.mem.Allocator = undefined;
|
main_pipeline: sgl.Pipeline,
|
||||||
|
linear_sampler: sg.Sampler,
|
||||||
|
nearest_sampler: sg.Sampler,
|
||||||
|
font_context: fontstash.Context,
|
||||||
|
textures: std.ArrayList(Texture) = .empty,
|
||||||
|
|
||||||
var main_pipeline: sgl.Pipeline = .{};
|
scale_stack_buffer: [32]Vec2 = undefined,
|
||||||
var linear_sampler: sg.Sampler = .{};
|
scale_stack: std.ArrayList(Vec2) = .empty,
|
||||||
var nearest_sampler: sg.Sampler = .{};
|
|
||||||
var font_context: fontstash.Context = undefined;
|
|
||||||
var textures: std.ArrayList(Texture) = .empty;
|
|
||||||
|
|
||||||
var scale_stack_buffer: [32]Vec2 = undefined;
|
|
||||||
var scale_stack: std.ArrayList(Vec2) = .empty;
|
|
||||||
|
|
||||||
pub fn init(options: Options) !void {
|
|
||||||
gpa = options.allocator;
|
|
||||||
|
|
||||||
|
pub fn init(self: *Graphics, options: Options) !void {
|
||||||
sg.setup(.{
|
sg.setup(.{
|
||||||
.logger = options.logger,
|
.logger = options.logger,
|
||||||
.environment = sglue.environment(),
|
.environment = sglue.environment(),
|
||||||
@ -123,7 +121,7 @@ pub fn init(options: Options) !void {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
main_pipeline = sgl.makePipeline(.{
|
const main_pipeline = sgl.makePipeline(.{
|
||||||
.colors = init: {
|
.colors = init: {
|
||||||
var colors: [8]sg.ColorTargetState = @splat(.{});
|
var colors: [8]sg.ColorTargetState = @splat(.{});
|
||||||
colors[0] = .{
|
colors[0] = .{
|
||||||
@ -158,14 +156,14 @@ pub fn init(options: Options) !void {
|
|||||||
imgui.addFont(imgui_font.ttf_data, imgui_font.size);
|
imgui.addFont(imgui_font.ttf_data, imgui_font.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
linear_sampler = sg.makeSampler(.{
|
const linear_sampler = sg.makeSampler(.{
|
||||||
.min_filter = .LINEAR,
|
.min_filter = .LINEAR,
|
||||||
.mag_filter = .LINEAR,
|
.mag_filter = .LINEAR,
|
||||||
.mipmap_filter = .LINEAR,
|
.mipmap_filter = .LINEAR,
|
||||||
.label = "linear-sampler",
|
.label = "linear-sampler",
|
||||||
});
|
});
|
||||||
|
|
||||||
nearest_sampler = sg.makeSampler(.{
|
const nearest_sampler = sg.makeSampler(.{
|
||||||
.min_filter = .NEAREST,
|
.min_filter = .NEAREST,
|
||||||
.mag_filter = .NEAREST,
|
.mag_filter = .NEAREST,
|
||||||
.mipmap_filter = .NEAREST,
|
.mipmap_filter = .NEAREST,
|
||||||
@ -175,31 +173,38 @@ pub fn init(options: Options) !void {
|
|||||||
const dpi_scale = sapp.dpiScale();
|
const dpi_scale = sapp.dpiScale();
|
||||||
const atlas_size = 512;
|
const atlas_size = 512;
|
||||||
const atlas_dim = std.math.ceilPowerOfTwoAssert(u32, @intFromFloat(atlas_size * dpi_scale));
|
const atlas_dim = std.math.ceilPowerOfTwoAssert(u32, @intFromFloat(atlas_size * dpi_scale));
|
||||||
font_context = try fontstash.Context.init(.{
|
const font_context = try fontstash.Context.init(.{
|
||||||
.width = @intCast(atlas_dim),
|
.width = @intCast(atlas_dim),
|
||||||
.height = @intCast(atlas_dim),
|
.height = @intCast(atlas_dim),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.* = Graphics{
|
||||||
|
.main_pipeline = main_pipeline,
|
||||||
|
.linear_sampler = linear_sampler,
|
||||||
|
.nearest_sampler = nearest_sampler,
|
||||||
|
.font_context = font_context,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit() void {
|
pub fn deinit(self: *Graphics, gpa: std.mem.Allocator) void {
|
||||||
textures.deinit(gpa);
|
self.textures.deinit(gpa);
|
||||||
imgui.shutdown();
|
imgui.shutdown();
|
||||||
font_context.deinit();
|
self.font_context.deinit();
|
||||||
sgl.shutdown();
|
sgl.shutdown();
|
||||||
sg.shutdown();
|
sg.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawCommand(command: Command) void {
|
pub fn drawCommand(self: *Graphics, command: Command) void {
|
||||||
switch(command) {
|
switch(command) {
|
||||||
.push_transformation => |opts| {
|
.push_transformation => |opts| {
|
||||||
pushTransform(opts.translation, opts.scale);
|
self.pushTransform(opts.translation, opts.scale);
|
||||||
// font_resolution_scale = font_resolution_scale.multiply(opts.scale);
|
// font_resolution_scale = font_resolution_scale.multiply(opts.scale);
|
||||||
},
|
},
|
||||||
.pop_transformation => {
|
.pop_transformation => {
|
||||||
popTransform();
|
self.popTransform();
|
||||||
},
|
},
|
||||||
.draw_rectangle => |opts| {
|
.draw_rectangle => |opts| {
|
||||||
drawRectangle(opts);
|
self.drawRectangle(opts);
|
||||||
},
|
},
|
||||||
.set_scissor => |opts| {
|
.set_scissor => |opts| {
|
||||||
sgl.scissorRectf(
|
sgl.scissorRectf(
|
||||||
@ -219,25 +224,25 @@ pub fn drawCommand(command: Command) void {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
.draw_text => |opts| {
|
.draw_text => |opts| {
|
||||||
const font_resolution_scale = scale_stack.getLast();
|
const font_resolution_scale = self.scale_stack.getLast();
|
||||||
|
|
||||||
sgl.pushMatrix();
|
sgl.pushMatrix();
|
||||||
defer sgl.popMatrix();
|
defer sgl.popMatrix();
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
font_context.setFont(opts.font);
|
self.font_context.setFont(opts.font);
|
||||||
font_context.setSize(opts.size * font_resolution_scale.y);
|
self.font_context.setSize(opts.size * font_resolution_scale.y);
|
||||||
font_context.setAlign(.{ .x = .left, .y = .top });
|
self.font_context.setAlign(.{ .x = .left, .y = .top });
|
||||||
font_context.setSpacing(0);
|
self.font_context.setSpacing(0);
|
||||||
|
|
||||||
const r: u8 = @intFromFloat(opts.color.x * 255);
|
const r: u8 = @intFromFloat(opts.color.x * 255);
|
||||||
const g: u8 = @intFromFloat(opts.color.y * 255);
|
const g: u8 = @intFromFloat(opts.color.y * 255);
|
||||||
const b: u8 = @intFromFloat(opts.color.z * 255);
|
const b: u8 = @intFromFloat(opts.color.z * 255);
|
||||||
const a: u8 = @intFromFloat(opts.color.w * 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);
|
const color: u32 = r | (@as(u32, g) << 8) | (@as(u32, b) << 16) | (@as(u32, a) << 24);
|
||||||
font_context.setColor(color);
|
self.font_context.setColor(color);
|
||||||
font_context.drawText(
|
self.font_context.drawText(
|
||||||
opts.pos.x * font_resolution_scale.x,
|
opts.pos.x * font_resolution_scale.x,
|
||||||
opts.pos.y * font_resolution_scale.y,
|
opts.pos.y * font_resolution_scale.y,
|
||||||
opts.text
|
opts.text
|
||||||
@ -246,13 +251,13 @@ pub fn drawCommand(command: Command) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawCommands(commands: []const Command) void {
|
pub fn drawCommands(self: *Graphics, commands: []const Command) void {
|
||||||
for (commands) |command| {
|
for (commands) |command| {
|
||||||
drawCommand(command);
|
self.drawCommand(command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn beginFrame() void {
|
pub fn beginFrame(self: *Graphics) void {
|
||||||
const zone = tracy.initZone(@src(), .{ });
|
const zone = tracy.initZone(@src(), .{ });
|
||||||
defer zone.deinit();
|
defer zone.deinit();
|
||||||
|
|
||||||
@ -263,17 +268,17 @@ pub fn beginFrame() void {
|
|||||||
.dpi_scale = sapp.dpiScale()
|
.dpi_scale = sapp.dpiScale()
|
||||||
});
|
});
|
||||||
|
|
||||||
scale_stack = .initBuffer(&scale_stack_buffer);
|
self.scale_stack = .initBuffer(&self.scale_stack_buffer);
|
||||||
scale_stack.appendAssumeCapacity(.init(1, 1));
|
self.scale_stack.appendAssumeCapacity(.init(1, 1));
|
||||||
|
|
||||||
font_context.clearState();
|
self.font_context.clearState();
|
||||||
sgl.defaults();
|
sgl.defaults();
|
||||||
sgl.matrixModeProjection();
|
sgl.matrixModeProjection();
|
||||||
sgl.ortho(0, sapp.widthf(), sapp.heightf(), 0, -1, 1);
|
sgl.ortho(0, sapp.widthf(), sapp.heightf(), 0, -1, 1);
|
||||||
sgl.loadPipeline(main_pipeline);
|
sgl.loadPipeline(self.main_pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn endFrame(clear_color: Vec4) void {
|
pub fn endFrame(self: *Graphics, clear_color: Vec4) void {
|
||||||
const zone = tracy.initZone(@src(), .{ });
|
const zone = tracy.initZone(@src(), .{ });
|
||||||
defer zone.deinit();
|
defer zone.deinit();
|
||||||
|
|
||||||
@ -289,7 +294,7 @@ pub fn endFrame(clear_color: Vec4) void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
font_context.flush();
|
self.font_context.flush();
|
||||||
|
|
||||||
{
|
{
|
||||||
sg.beginPass(.{
|
sg.beginPass(.{
|
||||||
@ -305,17 +310,17 @@ pub fn endFrame(clear_color: Vec4) void {
|
|||||||
sg.commit();
|
sg.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pushTransform(translation: Vec2, scale: Vec2) void {
|
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);
|
||||||
|
|
||||||
scale_stack.appendAssumeCapacity(scale_stack.getLast().multiply(scale));
|
self.scale_stack.appendAssumeCapacity(self.scale_stack.getLast().multiply(scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn popTransform() void {
|
fn popTransform(self: *Graphics) void {
|
||||||
sgl.popMatrix();
|
sgl.popMatrix();
|
||||||
_ = scale_stack.pop().?;
|
_ = self.scale_stack.pop().?;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Vertex = struct {
|
const Vertex = struct {
|
||||||
@ -323,13 +328,13 @@ const Vertex = struct {
|
|||||||
uv: Vec2
|
uv: Vec2
|
||||||
};
|
};
|
||||||
|
|
||||||
fn drawQuad(quad: [4]Vertex, color: Vec4, texture_id: TextureId) void {
|
fn drawQuad(self: *Graphics, quad: [4]Vertex, color: Vec4, texture_id: TextureId) void {
|
||||||
sgl.enableTexture();
|
sgl.enableTexture();
|
||||||
defer sgl.disableTexture();
|
defer sgl.disableTexture();
|
||||||
|
|
||||||
const view = textures.items[@intFromEnum(texture_id)].view;
|
const view = self.textures.items[@intFromEnum(texture_id)].view;
|
||||||
// TODO: Make sampler configurable
|
// TODO: Make sampler configurable
|
||||||
sgl.texture(view, nearest_sampler);
|
sgl.texture(view, self.nearest_sampler);
|
||||||
|
|
||||||
sgl.beginQuads();
|
sgl.beginQuads();
|
||||||
defer sgl.end();
|
defer sgl.end();
|
||||||
@ -352,7 +357,7 @@ fn drawQuadNoUVs(quad: [4]Vec2, color: Vec4) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drawRectangle(opts: Command.DrawRectangle) void {
|
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;
|
||||||
|
|
||||||
@ -381,7 +386,7 @@ fn drawRectangle(opts: Command.DrawRectangle) void {
|
|||||||
.uv = .init(uv.left(), uv.bottom())
|
.uv = .init(uv.left(), uv.bottom())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
drawQuad(quad, opts.color, sprite.texture);
|
self.drawQuad(quad, opts.color, sprite.texture);
|
||||||
} else {
|
} else {
|
||||||
const quad = .{
|
const quad = .{
|
||||||
pos.add(top_left),
|
pos.add(top_left),
|
||||||
@ -407,8 +412,8 @@ fn drawLine(from: Vec2, to: Vec2, color: Vec4, width: f32) void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addFont(name: [*c]const u8, data: []const u8) !Font.Id {
|
fn addFont(self: *Graphics, name: [*c]const u8, data: []const u8) !Font.Id {
|
||||||
return try font_context.addFont(name, data);
|
return try self.font_context.addFont(name, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn makeView(image: sg.Image) !sg.View {
|
fn makeView(image: sg.Image) !sg.View {
|
||||||
@ -453,7 +458,7 @@ fn makeImageWithMipMaps(mipmaps: []const Texture.Data) !sg.Image {
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addTexture(mipmaps: []const Texture.Data) !TextureId {
|
pub fn addTexture(self: *Graphics, gpa: std.mem.Allocator, mipmaps: []const Texture.Data) !TextureId {
|
||||||
const image = try makeImageWithMipMaps(mipmaps);
|
const image = try makeImageWithMipMaps(mipmaps);
|
||||||
errdefer sg.deallocImage(image);
|
errdefer sg.deallocImage(image);
|
||||||
|
|
||||||
@ -461,8 +466,8 @@ pub fn addTexture(mipmaps: []const Texture.Data) !TextureId {
|
|||||||
errdefer sg.deallocView(view);
|
errdefer sg.deallocView(view);
|
||||||
|
|
||||||
assert(mipmaps.len > 0);
|
assert(mipmaps.len > 0);
|
||||||
const index = textures.items.len;
|
const index = self.textures.items.len;
|
||||||
try textures.append(gpa, .{
|
try self.textures.append(gpa, .{
|
||||||
.image = image,
|
.image = image,
|
||||||
.view = view,
|
.view = view,
|
||||||
.info = .{
|
.info = .{
|
||||||
@ -474,7 +479,7 @@ pub fn addTexture(mipmaps: []const Texture.Data) !TextureId {
|
|||||||
return @enumFromInt(index);
|
return @enumFromInt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTextureInfo(id: TextureId) TextureInfo {
|
pub fn getTextureInfo(self: *Graphics, id: TextureId) TextureInfo {
|
||||||
const texture = textures.items[@intFromEnum(id)];
|
const texture = self.textures.items[@intFromEnum(id)];
|
||||||
return texture.info;
|
return texture.info;
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
const Engine = @import("./engine/root.zig");
|
const Engine = @import("engine");
|
||||||
|
|
||||||
var engine: Engine = undefined;
|
var engine: Engine = undefined;
|
||||||
|
|
||||||
@ -23,20 +23,34 @@ const STBImage = @import("stb_image");
|
|||||||
|
|
||||||
const Gfx = Graphics;
|
const Gfx = Graphics;
|
||||||
|
|
||||||
const Game = @import("../game.zig");
|
const GameCallbacks = struct {
|
||||||
const Assets = @import("../assets.zig");
|
init: *const fn(opts: *const Engine.InitOptions) callconv(.c) void,
|
||||||
|
tick: *const fn(frame: *Frame) callconv(.c) void,
|
||||||
|
deinit: *const fn() callconv(.c) void,
|
||||||
|
debug: *const fn() callconv(.c) void,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern fn init(opts: *const Engine.InitOptions) void;
|
||||||
|
extern fn tick(frame: *Frame) void;
|
||||||
|
extern fn deinit() void;
|
||||||
|
extern fn debug() void;
|
||||||
|
|
||||||
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,
|
mouse_inside: bool,
|
||||||
last_frame_at: Nanoseconds,
|
last_frame_at: Nanoseconds,
|
||||||
|
graphics: Graphics,
|
||||||
|
game_callbacks: GameCallbacks,
|
||||||
|
|
||||||
game: Game,
|
|
||||||
assets: Assets,
|
|
||||||
frame: Frame,
|
frame: Frame,
|
||||||
|
|
||||||
canvas_size: ?Vec2 = null,
|
canvas_size: ?Vec2 = null,
|
||||||
@ -53,9 +67,14 @@ pub fn run(self: *Engine, opts: RunOptions) !void {
|
|||||||
.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,
|
.mouse_inside = false,
|
||||||
.last_frame_at = 0,
|
.last_frame_at = 0,
|
||||||
.assets = undefined,
|
.frame = undefined,
|
||||||
.game = undefined,
|
.graphics = undefined,
|
||||||
.frame = undefined
|
.game_callbacks = .{
|
||||||
|
.init = init,
|
||||||
|
.deinit = deinit,
|
||||||
|
.tick = tick,
|
||||||
|
.debug = debug,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
|
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
|
||||||
@ -84,19 +103,20 @@ pub fn run(self: *Engine, opts: RunOptions) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Don't hard code icon path, allow changing through options
|
// TODO: Don't hard code icon path, allow changing through options
|
||||||
var icon_data = try STBImage.load(@embedFile("../assets/icon.png"));
|
// var icon_data = try STBImage.load(@embedFile("../assets/icon.png"));
|
||||||
defer icon_data.deinit();
|
// defer icon_data.deinit();
|
||||||
|
|
||||||
var icon: sapp.IconDesc = .{};
|
var icon: sapp.IconDesc = .{};
|
||||||
icon.sokol_default = false;
|
icon.sokol_default = true;
|
||||||
icon.images[0] = .{
|
// TODO:
|
||||||
.width = @intCast(icon_data.width),
|
// icon.images[0] = .{
|
||||||
.height = @intCast(icon_data.height),
|
// .width = @intCast(icon_data.width),
|
||||||
.pixels = .{
|
// .height = @intCast(icon_data.height),
|
||||||
.ptr = icon_data.rgba8_pixels,
|
// .pixels = .{
|
||||||
.size = icon_data.width * icon_data.height * 4
|
// .ptr = icon_data.rgba8_pixels,
|
||||||
}
|
// .size = icon_data.width * icon_data.height * 4
|
||||||
};
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
sapp.run(.{
|
sapp.run(.{
|
||||||
.init_userdata_cb = sokolInitCallback,
|
.init_userdata_cb = sokolInitCallback,
|
||||||
@ -119,12 +139,15 @@ fn sokolInit(self: *Engine) !void {
|
|||||||
const zone = tracy.initZone(@src(), .{ });
|
const zone = tracy.initZone(@src(), .{ });
|
||||||
defer zone.deinit();
|
defer zone.deinit();
|
||||||
|
|
||||||
try Gfx.init(.{
|
log.debug("Init", .{});
|
||||||
|
|
||||||
|
try self.graphics.init(.{
|
||||||
.allocator = self.allocator,
|
.allocator = self.allocator,
|
||||||
.logger = .{ .func = sokolLogCallback },
|
.logger = .{ .func = sokolLogCallback },
|
||||||
.imgui_font = .{
|
// TODO:
|
||||||
.ttf_data = @embedFile("../assets/roboto-font/Roboto-Regular.ttf"),
|
// .imgui_font = .{
|
||||||
}
|
// .ttf_data = @embedFile("../assets/roboto-font/Roboto-Regular.ttf"),
|
||||||
|
// }
|
||||||
});
|
});
|
||||||
|
|
||||||
try Audio.init(.{
|
try Audio.init(.{
|
||||||
@ -134,8 +157,11 @@ fn sokolInit(self: *Engine) !void {
|
|||||||
|
|
||||||
const seed: u64 = @bitCast(std.time.milliTimestamp());
|
const seed: u64 = @bitCast(std.time.milliTimestamp());
|
||||||
|
|
||||||
self.assets = try Assets.init(self.allocator);
|
const opts = InitOptions{
|
||||||
self.game = try Game.init(self.allocator, seed, &self.assets);
|
.gpa = self.allocator,
|
||||||
|
.seed = seed,
|
||||||
|
};
|
||||||
|
self.game_callbacks.init(&opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sokolCleanup(self: *Engine) void {
|
fn sokolCleanup(self: *Engine) void {
|
||||||
@ -144,9 +170,8 @@ fn sokolCleanup(self: *Engine) void {
|
|||||||
|
|
||||||
self.frame.deinit();
|
self.frame.deinit();
|
||||||
Audio.deinit();
|
Audio.deinit();
|
||||||
self.game.deinit();
|
self.game_callbacks.deinit();
|
||||||
self.assets.deinit(self.allocator);
|
self.graphics.deinit(self.allocator);
|
||||||
Gfx.deinit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sokolFrame(self: *Engine) !void {
|
fn sokolFrame(self: *Engine) !void {
|
||||||
@ -193,7 +218,7 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
frame.dt_ns = time_passed - self.last_frame_at;
|
frame.dt_ns = time_passed - self.last_frame_at;
|
||||||
frame.hide_cursor = false;
|
frame.hide_cursor = false;
|
||||||
|
|
||||||
try self.game.tick(&self.frame);
|
self.game_callbacks.tick(&self.frame);
|
||||||
|
|
||||||
frame.input.keyboard.pressed = .initEmpty();
|
frame.input.keyboard.pressed = .initEmpty();
|
||||||
frame.input.keyboard.released = .initEmpty();
|
frame.input.keyboard.released = .initEmpty();
|
||||||
@ -220,14 +245,13 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
self.canvas_size = self.frame.graphics.canvas_size;
|
self.canvas_size = self.frame.graphics.canvas_size;
|
||||||
|
|
||||||
{
|
{
|
||||||
Gfx.beginFrame();
|
self.graphics.beginFrame();
|
||||||
defer Gfx.endFrame(frame.graphics.clear_color);
|
defer self.graphics.endFrame(frame.graphics.clear_color);
|
||||||
|
|
||||||
Gfx.drawCommands(frame.graphics.commands.items);
|
self.graphics.drawCommands(frame.graphics.commands.items);
|
||||||
|
|
||||||
if (frame.show_debug) {
|
if (frame.show_debug) {
|
||||||
try self.game.debug();
|
try self.showDebugWindow(&self.frame);
|
||||||
try showDebugWindow(&self.frame);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,23 +264,34 @@ fn sokolFrame(self: *Engine) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn showDebugWindow(frame: *Frame) !void {
|
fn showDebugWindow(self: *Engine, frame: *Frame) !void {
|
||||||
if (!imgui.beginWindow(.{
|
if (!imgui.beginWindow(.{
|
||||||
.name = "Engine",
|
.name = "Debug",
|
||||||
.pos = Vec2.init(240, 20),
|
.pos = Vec2.init(20, 20),
|
||||||
.size = Vec2.init(200, 200),
|
.size = Vec2.init(200, 200),
|
||||||
})) {
|
})) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
defer imgui.endWindow();
|
defer imgui.endWindow();
|
||||||
|
|
||||||
imgui.textFmt("Draw commands: {}\n", .{
|
if (imgui.beginTabBar("debug")) {
|
||||||
frame.graphics.commands.items.len,
|
defer imgui.endTabBar();
|
||||||
});
|
|
||||||
imgui.textFmt("Audio instances: {}/{}\n", .{
|
if (imgui.beginTabItem("Game")) {
|
||||||
Audio.mixer.instances.items.len,
|
defer imgui.endTabItem();
|
||||||
Audio.mixer.instances.capacity
|
self.game_callbacks.debug();
|
||||||
});
|
}
|
||||||
|
if (imgui.beginTabItem("Engine")) {
|
||||||
|
defer imgui.endTabItem();
|
||||||
|
imgui.textFmt("Draw commands: {}\n", .{
|
||||||
|
frame.graphics.commands.items.len,
|
||||||
|
});
|
||||||
|
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 {
|
||||||
@ -1,44 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
|
|
||||||
const Math = @import("./engine/math.zig");
|
|
||||||
const Engine = @import("./engine/root.zig");
|
|
||||||
const Gfx = Engine.Graphics;
|
|
||||||
const Audio = Engine.Audio;
|
|
||||||
|
|
||||||
const Assets = @This();
|
|
||||||
|
|
||||||
const FontName = enum {
|
|
||||||
regular,
|
|
||||||
bold,
|
|
||||||
italic,
|
|
||||||
|
|
||||||
const EnumArray = std.EnumArray(FontName, Gfx.Font.Id);
|
|
||||||
};
|
|
||||||
|
|
||||||
font_id: FontName.EnumArray,
|
|
||||||
|
|
||||||
wood01: Audio.Data.Id,
|
|
||||||
|
|
||||||
pub fn init(gpa: std.mem.Allocator) !Assets {
|
|
||||||
_ = gpa; // autofix
|
|
||||||
const font_id_array: FontName.EnumArray = .init(.{
|
|
||||||
.regular = try Gfx.addFont("regular", @embedFile("assets/roboto-font/Roboto-Regular.ttf")),
|
|
||||||
.bold = try Gfx.addFont("bold", @embedFile("assets/roboto-font/Roboto-Bold.ttf")),
|
|
||||||
.italic = try Gfx.addFont("italic", @embedFile("assets/roboto-font/Roboto-Italic.ttf")),
|
|
||||||
});
|
|
||||||
|
|
||||||
const wood01 = try Audio.load(.{
|
|
||||||
.format = .vorbis,
|
|
||||||
.data = @embedFile("assets/wood01.ogg"),
|
|
||||||
});
|
|
||||||
|
|
||||||
return Assets{
|
|
||||||
.font_id = font_id_array,
|
|
||||||
.wood01 = wood01
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Assets, gpa: std.mem.Allocator) void {
|
|
||||||
_ = self; // autofix
|
|
||||||
_ = gpa; // autofix
|
|
||||||
}
|
|
||||||
97
src/game.zig
97
src/game.zig
@ -2,9 +2,7 @@ const std = @import("std");
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
const Assets = @import("./assets.zig");
|
const Engine = @import("engine");
|
||||||
|
|
||||||
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;
|
||||||
@ -13,25 +11,55 @@ const Audio = Engine.Audio;
|
|||||||
|
|
||||||
const Game = @This();
|
const Game = @This();
|
||||||
|
|
||||||
gpa: Allocator,
|
const FontName = enum {
|
||||||
assets: *Assets,
|
regular,
|
||||||
|
bold,
|
||||||
|
italic,
|
||||||
|
|
||||||
player: Vec2,
|
const EnumArray = std.EnumArray(FontName, Gfx.Font.Id);
|
||||||
|
};
|
||||||
|
|
||||||
pub fn init(gpa: Allocator, seed: u64, assets: *Assets) !Game {
|
const State = struct {
|
||||||
_ = seed; // autofix
|
gpa: Allocator,
|
||||||
return Game{
|
player: Vec2,
|
||||||
|
|
||||||
|
// font_id: FontName.EnumArray,
|
||||||
|
// wood01: Audio.Data.Id,
|
||||||
|
};
|
||||||
|
|
||||||
|
var g_state: *State = undefined;
|
||||||
|
|
||||||
|
pub export fn init(opts: *const Engine.InitOptions) void {
|
||||||
|
const gpa = opts.gpa;
|
||||||
|
|
||||||
|
// const font_id_array: FontName.EnumArray = .init(.{
|
||||||
|
// .regular = try Gfx.addFont("regular", @embedFile("assets/roboto-font/Roboto-Regular.ttf")),
|
||||||
|
// .bold = try Gfx.addFont("bold", @embedFile("assets/roboto-font/Roboto-Bold.ttf")),
|
||||||
|
// .italic = try Gfx.addFont("italic", @embedFile("assets/roboto-font/Roboto-Italic.ttf")),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const wood01 = try Audio.load(.{
|
||||||
|
// .format = .vorbis,
|
||||||
|
// .data = @embedFile("assets/wood01.ogg"),
|
||||||
|
// });
|
||||||
|
|
||||||
|
g_state = gpa.create(State) catch @panic("OOM");
|
||||||
|
g_state.* = State{
|
||||||
.gpa = gpa,
|
.gpa = gpa,
|
||||||
.assets = assets,
|
.player = .init(50, 50),
|
||||||
.player = .init(50, 50)
|
// .font_id = font_id_array,
|
||||||
|
// .wood01 = wood01
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Game) void {
|
pub export fn deinit() void {
|
||||||
_ = self; // autofix
|
const gpa = g_state.gpa;
|
||||||
|
|
||||||
|
gpa.destroy(g_state);
|
||||||
|
g_state = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
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);
|
||||||
@ -57,15 +85,13 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
|||||||
dir = dir.normalized();
|
dir = dir.normalized();
|
||||||
|
|
||||||
if (dir.x != 0 or dir.y != 0) {
|
if (dir.x != 0 or dir.y != 0) {
|
||||||
frame.playAudio(.{
|
// frame.playAudio(.{
|
||||||
.id = self.assets.wood01,
|
// .id = g_state.wood01,
|
||||||
.volume = 0.1
|
// .volume = 0.1
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
self.player = self.player.add(dir.multiplyScalar(50 * dt));
|
g_state.player = g_state.player.add(dir.multiplyScalar(50 * dt));
|
||||||
|
|
||||||
const regular_font = self.assets.font_id.get(.regular);
|
|
||||||
|
|
||||||
frame.drawRectangle(.{
|
frame.drawRectangle(.{
|
||||||
.rect = .{ .pos = .init(0, 0), .size = canvas_size },
|
.rect = .{ .pos = .init(0, 0), .size = canvas_size },
|
||||||
@ -74,35 +100,22 @@ pub fn tick(self: *Game, frame: *Engine.Frame) !void {
|
|||||||
const size = Vec2.init(20, 20);
|
const size = Vec2.init(20, 20);
|
||||||
frame.drawRectangle(.{
|
frame.drawRectangle(.{
|
||||||
.rect = .{
|
.rect = .{
|
||||||
.pos = self.player.sub(size.divideScalar(2)),
|
.pos = g_state.player.sub(size.divideScalar(2)),
|
||||||
.size = size
|
.size = size
|
||||||
},
|
},
|
||||||
.color = rgb(200, 20, 20)
|
.color = rgb(200, 20, 20)
|
||||||
});
|
});
|
||||||
if (dir.x != 0 or dir.y != 0) {
|
if (dir.x != 0 or dir.y != 0) {
|
||||||
frame.drawRectanglOutline(self.player.sub(size.divideScalar(2)), size, rgb(20, 200, 20), 3);
|
frame.drawRectanglOutline(g_state.player.sub(size.divideScalar(2)), size, rgb(20, 200, 20), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.drawText(self.player, "Player", .{
|
// const regular_font = g_state.font_id.get(.regular);
|
||||||
.font = regular_font,
|
// frame.drawText(g_state.player, "Player", .{
|
||||||
.size = 10
|
// .font = regular_font,
|
||||||
});
|
// .size = 10
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug(self: *Game) !void {
|
pub export fn debug() void {
|
||||||
_ = self; // autofix
|
|
||||||
if (!imgui.beginWindow(.{
|
|
||||||
.name = "Debug",
|
|
||||||
.pos = Vec2.init(20, 20),
|
|
||||||
.size = Vec2.init(400, 200),
|
|
||||||
})) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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