Compare commits

...

21 Commits

Author SHA1 Message Date
peterino2 2d59109994 saving 2026-01-19 21:40:05 -08:00
Peterino2 bae150305d enabling shader gen 2026-01-08 17:19:52 -08:00
peterino2 6300ef0e35 something broke with core 2026-01-08 09:40:02 -08:00
peterino2 a518a89798 hot reloading with trampoline 2026-01-06 09:14:02 -08:00
peterino2 e69a8d13ec hot reloading and module watching done 2026-01-03 20:39:31 -08:00
peterino2 ef91c4599b updated install script 2026-01-03 16:37:02 -08:00
peterino2 9f9f40abd9 updates to engine time and seemingly bugs are fixed 2026-01-03 16:35:31 -08:00
peterino2 81aaaa81b7 big refactor to new lifetime rules 2026-01-03 16:02:52 -08:00
peterino2 c36cae7db9 engine object changes 2026-01-03 14:05:30 -08:00
peterino2 a06b0e6394 saving 2026-01-02 16:47:56 -08:00
peterino2 17b3a4c23d trampoline loading is now working for coreTest... now onto hot reloading 2026-01-01 16:10:54 -08:00
peterino2 81132ac97b saving 2025-12-30 14:40:51 -08:00
peterino2 97c8de24b9 saving 2025-12-30 13:55:35 -08:00
peterino2 bb99e9025e saving 2025-12-28 17:38:50 -08:00
Peter Li b4fa25106a Merge branch 'dev/variant-engine' of http://archon:3000/searzocom/Backlog into dev/variant-engine 2025-12-27 22:54:20 -08:00
Peter Li 75a9ae1b39 spec generation complete 2025-12-27 22:51:40 -08:00
peterino2 18b5537826 saving 2025-12-19 02:18:45 -08:00
Peter Li b248573930 more work on variant engine 2025-12-19 01:45:12 -08:00
peterino2 3648615829 new build system who dis 2025-12-07 14:35:58 -08:00
peterino2 8a30c78260 archiving a lot of things then moving to yet another redo of the build system 2025-11-28 20:22:51 -08:00
peterino2 cc00fb076e switched all builds to bh.declareOptions 2025-11-28 20:14:56 -08:00
165 changed files with 3127 additions and 9456 deletions

View File

@ -97,11 +97,4 @@ git bug bug comment abc123
- Issues sync with `git bug pull/push`
- Keep descriptions factual and clear
---
/// --------------------------------------------------------
void* malloc(size_t size); // gives you a pointer to a memory buffer of size
void free(void* ptr); // releases a pointer to memory
/// --------------------------------------------------------

662
archive/build.zig Normal file
View File

@ -0,0 +1,662 @@
// MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1 -- use this if you're getting that odd crash on mac
b: *std.Build,
nw_builder: *std.Build,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
nw_mod: *std.Build.Module,
gltf2ozz: ozz.GltfToOzz,
options: *std.Build.Step.Options,
cookShaders: bool,
backlogRoot: []const u8,
// list of all shaders discovered under
// content/_shaders/def
reflectShaderPathList: [][]u8 = undefined,
staticBuild: bool = false,
nwdep: *std.Build.Dependency,
apigen: *std.Build.Step.Compile,
shaderEmbedGen: *std.Build.Step.Compile,
loadDynamicsGen: *std.Build.Step.Compile,
rcGen: *std.Build.Step.Compile,
generatedApis: std.StringHashMapUnmanaged(*std.Build.Module) = .{},
const engineDepList = [_][]const u8{
"assets",
"audio",
"core",
"net",
"papyrus",
"platform",
"rend",
"ui",
"imgui",
"physics",
"sys",
};
const BuildSystem = @This();
const std = @import("std");
const Build = std.Build;
const LazyPath = Build.LazyPath;
const ozz = @import("ozz");
pub const InitOptions = struct {
import_name: []const u8 = "Backlog",
backlogRoot: []const u8 = "./BacklogEngine",
staticBuild: bool = false,
target: Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
};
pub fn init(b: *std.Build, opts: InitOptions) BuildSystem {
var buildOpts = declareBuildOptions(b);
if (opts.target.result.os.tag == .linux) {
// using a static build for linux... object loading hell is not fun
std.debug.print("Important! only supporting static builds for linux", .{});
buildOpts.static_build = true;
}
const nwdep = b.dependency(opts.import_name, .{
.target = opts.target,
.optimize = opts.optimize,
.static_build = buildOpts.static_build,
});
var self = BuildSystem{
.b = b,
.nw_builder = nwdep.builder,
.target = opts.target,
.optimize = opts.optimize,
.nw_mod = nwdep.module("Backlog"),
.backlogRoot = opts.backlogRoot,
.options = createGameOptions(b, buildOpts),
.gltf2ozz = ozz.GltfToOzz.init(nwdep.builder, .{}),
.cookShaders = b.option(bool, "cookShaders", "generates shaders and updates .json files before running the build. (needs to be done whenever shaders are updated, this just runs tools/scripts/cook-shaders.py)") orelse false,
.staticBuild = buildOpts.static_build,
.nwdep = nwdep,
.apigen = nwdep.artifact("backlog-apigen"),
.loadDynamicsGen = nwdep.artifact("backlog-generate-loadDynamics"),
.rcGen = nwdep.artifact("backlog-generate-rc"),
.shaderEmbedGen = nwdep.artifact("backlog-shaderEmbedGen"),
};
const exeList = [1]*std.Build.Step.Compile{self.gltf2ozz.exe};
const install_tools = b.step("tools", "installs tools needed to generate outputs for the engine");
for (exeList) |exe| {
const toolsInstall = b.addInstallArtifact(exe, .{
.dest_dir = .{ .override = .{ .custom = "tools" } },
});
install_tools.dependOn(&toolsInstall.step);
}
{
const runArtifact = b.addRunArtifact(self.gltf2ozz.exe);
if (b.args) |args| {
runArtifact.addArgs(args);
}
const run_exe = b.step("gltf2ozz", "runs the gltf animation converter.");
run_exe.dependOn(&runArtifact.step);
}
self.addDependencyInstalls(self.b, .ReleaseFast);
return self;
}
pub const AddProgramOptions = struct {
name: []const u8,
desc: []const u8,
root_source_file: LazyPath,
imports: []const Build.Module.Import = &.{},
};
pub fn addProgram(self: *BuildSystem, opts: AddProgramOptions) *std.Build.Module {
const b = self.b;
const exe = self.nw_builder.addExecutable(.{
.name = opts.name,
.root_module = b.createModule(.{
.target = self.target,
.optimize = self.optimize,
.root_source_file = self.nw_builder.path("engine/main.zig"),
}),
});
b.installArtifact(exe);
const runArtifact = b.addRunArtifact(exe);
if (b.args) |args| {
runArtifact.addArgs(args);
}
const run_exe = b.step(self.b.fmt("run-{s}", .{opts.name}), opts.desc);
run_exe.dependOn(&runArtifact.step);
// main path = name/main.zig
const mod = b.addModule(opts.name, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = opts.root_source_file,
.imports = opts.imports,
});
exe.root_module.addImport("main", mod);
// todo.. remove this one and see what happens
exe.root_module.addImport("core", self.nwdep.module("core"));
// mod.addImport("Backlog", self.nw_mod);
exe.root_module.addOptions("BacklogOptions", self.options);
if (self.cookShaders) {
const cookShadersScript = b.fmt("{s}/tools/scripts/cookShaders.py", .{self.backlogRoot});
const cookShadersCommand = b.addSystemCommand(&[_][]const u8{"python"});
cookShadersCommand.addArg(cookShadersScript);
run_exe.dependOn(&cookShadersCommand.step);
}
b.getInstallStep().dependOn(self.nw_builder.getInstallStep());
// run_exe.dependOn(b.getInstallStep());
return mod;
}
pub const BuildOptions = struct {
mutex_job_queue: bool,
static_build: bool,
zero_logging: bool,
slow_logging: bool,
force_mailbox: bool,
};
pub fn declareBuildOptions(b: *std.Build) BuildOptions {
return .{
.mutex_job_queue = b.option(bool, "mutex_job_queue", "temporary test, reverts to old mutex based queue behaviour in jobs.zig:JobManager") orelse false,
.static_build = b.option(bool, "static_build", "builds the entire game as a single executable") orelse false,
.zero_logging = b.option(bool, "zero_logging", "disables all logging, only intended for use on job dispatch testing") orelse false,
.slow_logging = b.option(bool, "slow_logging", "Disables buffered logging, takes a hit to performance but gain timing information on logging") orelse false,
.force_mailbox = b.option(bool, "force_mailbox", "forces mailbox mode for present mode. unlocks framerate to irresponsible levels") orelse false,
};
}
pub fn createGameOptions(b: *std.Build, options: BuildOptions) *std.Build.Step.Options {
const opts = b.addOptions();
inline for (@typeInfo(BuildOptions).@"struct".fields) |field| {
opts.addOption(bool, field.name, @field(options, field.name));
}
return opts;
}
pub fn addExtraModule(self: *BuildSystem, mod: *std.Build.Module, moduleName: []const u8) void {
const dep = self.b.dependency(moduleName, .{ .target = self.target, .optimize = self.optimize, .static_build = self.staticBuild });
mod.addImport(moduleName, dep.module(moduleName));
}
pub fn addDependencyInstalls(self: *BuildSystem, b: *std.Build, optimize: std.builtin.OptimizeMode) void {
//if (self.staticBuild) {
//return;
// }
inline for (DynamicDepList) |d| {
b.installArtifact(b.dependency(
d.dep,
.{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
).artifact(d.artifact));
}
// b.installArtifact(b.dependency(
// "sdl3",
// .{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
// ).artifact("SDL3"));
}
const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } = &.{
.{ .dep = "sdl3", .artifact = "SDL3" },
.{ .dep = "spng", .artifact = "spng_c" },
.{ .dep = "lua", .artifact = "luac" },
.{ .dep = "miniaudio", .artifact = "miniaudio_c" },
.{ .dep = "zphysics", .artifact = "joltc" },
// .{ .dep = "enet", .artifact = "enet_c" },
.{ .dep = "ozz", .artifact = "ozz_cpp" },
};
// all other modules are disabled by default
pub const defaultEnabledModules: []const []const u8 = &.{
"core",
"assets",
"platform",
"rend",
};
pub const moduleOrder: []const []const u8 = &.{
"core",
"sys",
"assets",
"platform",
"net",
"physics",
"audio",
"rend",
"ui",
"imgui",
"papyrus",
};
pub const DynamicModule = struct {
name: []const u8,
allocator: std.mem.Allocator,
buildSystem: *BuildSystem,
programName: []const u8,
opts: AddProgramOptions,
extras: std.ArrayListUnmanaged(GameModule) = .{},
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
library: ?*std.Build.Step.Compile = null,
pub fn addExtraModule(self: *@This(), module: []const u8) void {
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
}
pub fn init(name: []const u8, p: *Program) *@This() {
var self: *@This() = p.allocator.create(@This()) catch @panic("out of memory");
self.* = .{
.opts = p.opts,
.programName = p.opts.name,
.buildSystem = p.buildSystem,
.allocator = p.allocator,
.name = name,
};
for (p.gameModules.items) |module| {
self.gameModules.append(self.allocator, module) catch @panic("out of memory");
}
for (p.extras.items) |module| {
self.extras.append(self.allocator, module) catch @panic("out of memory");
}
return self;
}
pub fn compileInstall(self: *@This()) *std.Build.Step.Compile {
if (self.library) |lib| {
return lib;
}
const b = self.buildSystem.b;
const static = self.buildSystem.staticBuild;
const lib = b.addLibrary(.{
.name = self.name,
.linkage = if (static) .static else .dynamic,
.root_module = b.createModule(.{
.root_source_file = self.opts.root_source_file,
.link_libc = true,
.optimize = self.buildSystem.optimize,
.target = self.buildSystem.target,
}),
});
const allocator = self.buildSystem.b.allocator;
var modlist = std.ArrayList([]const u8){};
for (self.gameModules.items) |mod| {
if (mod.enabled) {
modlist.append(allocator, mod.name) catch @panic("out of memory");
}
}
for (self.extras.items) |extra| {
self.buildSystem.addExtraModule(lib.root_module, extra.name);
}
lib.root_module.addImport("backlog", self.buildSystem.generateApi(self.name, modlist.items, null));
lib.root_module.addOptions("BacklogOptions", self.buildSystem.options);
if (static) {
// generateApi should create static callers for the main program
} else {
const installExtern = b.addInstallArtifact(lib, .{
.dest_dir = .{ .override = .{ .custom = "modules" } },
});
b.getInstallStep().dependOn(&installExtern.step);
}
return lib;
}
};
pub const GameModule = struct {
name: []const u8,
enabled: bool = true,
};
pub const Program = struct {
allocator: std.mem.Allocator,
opts: AddProgramOptions,
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
extras: std.ArrayListUnmanaged(GameModule) = .{},
dynamicModules: std.ArrayListUnmanaged(*DynamicModule) = .{},
buildSystem: *BuildSystem,
iconPath: ?std.Build.LazyPath = null,
pub fn setIconPath(self: *@This(), path: []const u8) void {
if (self.iconPath != null) {
return;
}
self.iconPath = self.buildSystem.generateRc(self.opts.name, path) catch return;
}
pub fn setModuleEnabled(self: *@This(), module: []const u8, enable: bool) void {
for (self.gameModules.items) |*m| {
if (std.mem.eql(u8, m.name, module)) {
m.enabled = enable;
return;
}
}
// module not found, add it here.
self.gameModules.append(self.allocator, .{ .name = module, .enabled = enable }) catch @panic("out of memory");
}
pub fn addExtraModule(self: *@This(), module: []const u8) void {
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
}
pub fn addDynamicModule(self: *@This(), module: []const u8, root_source_file: std.Build.LazyPath) *DynamicModule {
const dynamicModule = DynamicModule.init(module, self);
dynamicModule.opts.root_source_file = root_source_file;
self.dynamicModules.append(self.allocator, dynamicModule) catch @panic("out of memory");
return dynamicModule;
}
pub fn compileInstall(self: *@This()) *std.Build.Module {
const exe = self.buildSystem.addProgram(self.opts);
const allocator = self.buildSystem.b.allocator;
var modlist = std.ArrayList([]const u8){};
for (self.gameModules.items) |mod| {
if (mod.enabled) {
modlist.append(allocator, mod.name) catch @panic("out of memory");
}
}
for (self.extras.items) |extra| {
self.buildSystem.addExtraModule(exe, extra.name);
}
exe.addImport("backlog", self.buildSystem.generateApi(self.opts.name, modlist.items, self.dynamicModules.items));
if (self.buildSystem.target.result.os.tag == .windows) {
if (self.iconPath) |ip| {
exe.addWin32ResourceFile(.{
.file = ip,
.flags = &.{},
});
}
}
return exe;
}
};
pub fn program(self: *BuildSystem, opts: AddProgramOptions) *Program {
const prog = self.b.allocator.create(Program) catch unreachable;
prog.* = .{
.allocator = self.b.allocator,
.opts = opts,
.buildSystem = self,
};
for (moduleOrder) |module| {
prog.setModuleEnabled(module, false);
}
for (defaultEnabledModules) |module| {
prog.setModuleEnabled(module, true);
}
return prog;
}
// ========= standalone build instance =======
// maybe the default should be like an engine launcher/project launcher or something
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const fwdGeneratorExe = b.addExecutable(.{
.name = "backlog-generate-fwd",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateFwd.zig"),
}),
});
const generateExe = b.addExecutable(.{
.name = "backlog-apigen",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateApi.zig"),
}),
});
const generateShaders = b.addExecutable(.{
.name = "backlog-shaderEmbedGen",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateEmbeddedShaders.zig"),
}),
});
const generateRcExe = b.addExecutable(.{
.name = "backlog-generate-rc",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateRc.zig"),
}),
});
const generateLoadDynamicsExe = b.addExecutable(.{
.name = "backlog-generate-loadDynamics",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateLoadDynamics.zig"),
}),
});
b.installArtifact(generateLoadDynamicsExe);
b.installArtifact(generateExe);
b.installArtifact(generateShaders);
b.installArtifact(generateRcExe);
{
const loadDynamicsStub = b.addModule("loadDynamicsStub", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("engine/loadDynamicsStub.zig"),
});
_ = loadDynamicsStub;
const mod = b.addModule("Backlog", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("engine/backlog.zig"),
});
for (engineDepList) |depName| {
const dep = b.dependency(
depName,
.{
.target = target,
.optimize = optimize,
.static_build = static_build,
},
);
const run = b.addRunArtifact(fwdGeneratorExe);
const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName}));
const modFwd = b.addModule(depName, .{
.target = target,
.optimize = optimize,
.root_source_file = output,
});
mod.addImport(b.fmt("{s}", .{depName}), modFwd);
modFwd.addImport("module", dep.module(depName));
// mod.addImport(depName, dep.module(depName));
}
// link in large platform support functions... special case.
{
const dep = b.dependency("sdl3", .{
.target = target,
.optimize = optimize,
.static_build = static_build,
});
const lib = dep.module("SDL3");
mod.addImport("sdl3_fwd", lib);
}
}
}
pub fn generateApi(self: *@This(), programName: []const u8, moduleList: []const []const u8, dynamicModules: ?[]const *DynamicModule) *std.Build.Module {
// std.debug.print("GENERATE API:: {s}\n", .{programName});
for (moduleList) |mod| {
_ = mod;
// std.debug.print("{s}\n", .{mod});
}
//
if (self.generatedApis.get(programName)) |m| {
return m;
}
const run = self.b.addRunArtifact(self.apigen);
const pfile = self.b.fmt("{s}Api.zig", .{programName});
const output = run.addOutputFileArg(pfile);
for (moduleList) |modName| {
run.addArg(modName);
}
const mod = self.b.addModule(pfile, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = output,
});
for (moduleList) |modName| {
mod.addImport(modName, self.nwdep.module(modName));
}
const loadStatics = self.generateInstallStaticResources(programName, "content/_shaders") catch unreachable;
mod.addImport("staticShaderLoader", loadStatics);
// deal with dynamics
if (dynamicModules) |dynamics| {
const loadDynamics = self.generateLoadDynamics(programName, dynamics) catch @panic("unknown");
mod.addImport("loadDynamics", loadDynamics);
} else {
mod.addImport("loadDynamics", self.nwdep.module("loadDynamicsStub"));
}
self.generatedApis.put(self.b.allocator, programName, mod) catch @panic("out of memory");
return mod;
}
pub fn generateRc(self: *@This(), programName: []const u8, iconPath: []const u8) !std.Build.LazyPath {
const run = self.b.addRunArtifact(self.rcGen);
const pfile = self.b.fmt("{s}.rc", .{programName});
const output = run.addOutputFileArg(pfile);
run.addArg(iconPath);
return output;
}
pub fn generateLoadDynamics(self: *@This(), programName: []const u8, dynamics: []const *DynamicModule) !*std.Build.Module {
const run = self.b.addRunArtifact(self.loadDynamicsGen);
const pfile = self.b.fmt("{s}LoadDynamics.zig", .{programName});
const output = run.addOutputFileArg(pfile);
if (self.staticBuild) {
run.addArg("static");
} else {
run.addArg("dynamic");
}
for (dynamics) |dyn| {
run.addArg(dyn.name);
}
const mod = self.b.addModule(pfile, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = output,
});
mod.addImport("core", self.nwdep.module("core"));
for (dynamics) |dyn| {
const dynmod = dyn.compileInstall();
mod.addImport(dyn.name, dynmod.root_module);
}
return mod;
}
pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, shadersPath: []const u8) !*std.Build.Module {
const run = self.b.addRunArtifact(self.shaderEmbedGen);
const pfile = self.b.fmt("{s}ShaderGen.zig", .{programName});
const output = run.addOutputFileArg(pfile);
run.addArg(shadersPath);
const b = self.b;
const mod = self.b.addModule(pfile, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = output,
});
mod.addImport("core", self.nwdep.module("core"));
var dir = try std.fs.cwd().openDir("content/_shaders", .{ .iterate = true });
defer dir.close();
var walker = dir.iterate();
while (try walker.next()) |shaderType| {
if (shaderType.kind == .directory) {
var d2 = try dir.openDir(shaderType.name, .{ .iterate = true });
defer d2.close();
var w2 = d2.iterate();
while (try w2.next()) |shaderName| {
const shaderPath = b.fmt("content/_shaders/{s}/{s}", .{ shaderType.name, shaderName.name });
mod.addAnonymousImport(shaderName.name, .{
.root_source_file = b.path(shaderPath),
});
}
}
}
return mod;
}

696
build.archive.zig Normal file
View File

@ -0,0 +1,696 @@
// MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1 -- use this if you're getting that odd crash on mac
b: *std.Build,
nw_builder: *std.Build,
target: std.Build.ResolvedTarget,
optimize: std.builtin.Mode,
nw_mod: *std.Build.Module,
spirvReflect: SpirvReflect.SpirvGenerator2,
gltf2ozz: ozz.GltfToOzz,
options: *std.Build.Step.Options,
cookShaders: bool,
backlogRoot: []const u8,
// list of all shaders discovered under
// content/_shaders/def
reflectShaderPathList: [][]u8 = undefined,
staticBuild: bool = false,
nwdep: *std.Build.Dependency,
apigen: *std.Build.Step.Compile,
shaderEmbedGen: *std.Build.Step.Compile,
loadDynamicsGen: *std.Build.Step.Compile,
rcGen: *std.Build.Step.Compile,
generatedApis: std.StringHashMapUnmanaged(*std.Build.Module) = .{},
const engineDepList = [_][]const u8{
"assets",
"audio",
"core",
"net",
"papyrus",
"platform",
"rend",
"ui",
"imgui",
"physics",
"sys",
};
const BuildSystem = @This();
const std = @import("std");
const Build = std.Build;
const LazyPath = Build.LazyPath;
const SpirvReflect = @import("SpirvReflect");
const ozz = @import("ozz");
pub const InitOptions = struct {
import_name: []const u8 = "Backlog",
backlogRoot: []const u8 = "./BacklogEngine",
staticBuild: bool = false,
target: Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
};
pub fn init(b: *std.Build, opts: InitOptions) BuildSystem {
var buildOpts = declareBuildOptions(b);
if (opts.target.result.os.tag == .linux) {
// using a static build for linux... object loading hell is not fun
std.debug.print("Important! only supporting static builds for linux", .{});
buildOpts.static_build = true;
}
const nwdep = b.dependency(opts.import_name, .{
.target = opts.target,
.optimize = opts.optimize,
.static_build = buildOpts.static_build,
});
var self = BuildSystem{
.b = b,
.nw_builder = nwdep.builder,
.target = opts.target,
.optimize = opts.optimize,
.nw_mod = nwdep.module("Backlog"),
.backlogRoot = opts.backlogRoot,
.spirvReflect = SpirvReflect.SpirvGenerator2.init(nwdep.builder, .{}),
.options = createGameOptions(b, buildOpts),
.gltf2ozz = ozz.GltfToOzz.init(nwdep.builder, .{}),
.cookShaders = b.option(bool, "cookShaders", "generates shaders and updates .json files before running the build. (needs to be done whenever shaders are updated, this just runs tools/scripts/cook-shaders.py)") orelse false,
.staticBuild = buildOpts.static_build,
.nwdep = nwdep,
.apigen = nwdep.artifact("backlog-apigen"),
.loadDynamicsGen = nwdep.artifact("backlog-generate-loadDynamics"),
.rcGen = nwdep.artifact("backlog-generate-rc"),
.shaderEmbedGen = nwdep.artifact("backlog-shaderEmbedGen"),
};
const exeList = [2]*std.Build.Step.Compile{ self.gltf2ozz.exe, self.spirvReflect.reflect };
const install_tools = b.step("tools", "installs tools needed to generate outputs for the engine");
for (exeList) |exe| {
const toolsInstall = b.addInstallArtifact(exe, .{
.dest_dir = .{ .override = .{ .custom = "tools" } },
});
install_tools.dependOn(&toolsInstall.step);
}
{
const runArtifact = b.addRunArtifact(self.gltf2ozz.exe);
if (b.args) |args| {
runArtifact.addArgs(args);
}
const run_exe = b.step("gltf2ozz", "runs the gltf animation converter.");
run_exe.dependOn(&runArtifact.step);
}
{
const runArtifact = b.addRunArtifact(self.spirvReflect.reflect);
if (b.args) |args| {
runArtifact.addArgs(args);
}
const run_exe = b.step("spv-reflect", "runs the gltf animation converter.");
run_exe.dependOn(&runArtifact.step);
}
self.addDependencyInstalls(self.b, .ReleaseFast);
return self;
}
pub const AddProgramOptions = struct {
name: []const u8,
desc: []const u8,
root_source_file: LazyPath,
imports: []const Build.Module.Import = &.{},
};
pub fn addProgram(self: *BuildSystem, opts: AddProgramOptions) *std.Build.Module {
const b = self.b;
const exe = self.nw_builder.addExecutable(.{
.name = opts.name,
.target = self.target,
.optimize = self.optimize,
.root_source_file = self.nw_builder.path("engine/main.zig"),
});
b.installArtifact(exe);
const runArtifact = b.addRunArtifact(exe);
if (b.args) |args| {
runArtifact.addArgs(args);
}
const run_exe = b.step(self.b.fmt("run-{s}", .{opts.name}), opts.desc);
run_exe.dependOn(&runArtifact.step);
// main path = name/main.zig
const mod = b.addModule(opts.name, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = opts.root_source_file,
.imports = opts.imports,
});
exe.root_module.addImport("main", mod);
// todo.. remove this one and see what happens
exe.root_module.addImport("core", self.nwdep.module("core"));
// mod.addImport("Backlog", self.nw_mod);
exe.root_module.addOptions("BacklogOptions", self.options);
if (self.cookShaders) {
const cookShadersScript = b.fmt("{s}/tools/scripts/cookShaders.py", .{self.backlogRoot});
const cookShadersCommand = b.addSystemCommand(&[_][]const u8{"python"});
cookShadersCommand.addArg(cookShadersScript);
run_exe.dependOn(&cookShadersCommand.step);
}
b.getInstallStep().dependOn(self.nw_builder.getInstallStep());
// run_exe.dependOn(b.getInstallStep());
return mod;
}
pub const BuildOptions = struct {
mutex_job_queue: bool,
static_build: bool,
zero_logging: bool,
slow_logging: bool,
force_mailbox: bool,
};
pub fn declareBuildOptions(b: *std.Build) BuildOptions {
return .{
.mutex_job_queue = b.option(bool, "mutex_job_queue", "temporary test, reverts to old mutex based queue behaviour in jobs.zig:JobManager") orelse false,
.static_build = b.option(bool, "static_build", "builds the entire game as a single executable") orelse false,
.zero_logging = b.option(bool, "zero_logging", "disables all logging, only intended for use on job dispatch testing") orelse false,
.slow_logging = b.option(bool, "slow_logging", "Disables buffered logging, takes a hit to performance but gain timing information on logging") orelse false,
.force_mailbox = b.option(bool, "force_mailbox", "forces mailbox mode for present mode. unlocks framerate to irresponsible levels") orelse false,
};
}
pub fn createGameOptions(b: *std.Build, options: BuildOptions) *std.Build.Step.Options {
const opts = b.addOptions();
inline for (@typeInfo(BuildOptions).@"struct".fields) |field| {
opts.addOption(bool, field.name, @field(options, field.name));
}
// build options for core.zig
// opts.addOption(
// bool,
// "mutex_job_queue",
// );
// opts.addOption(
// bool,
// "static_build",
// );
// opts.addOption(
// bool,
// "zero_logging",
// );
// opts.addOption(
// bool,
// "slow_logging",
// );
// opts.addOption(
// bool,
// "force_mailbox",
// );
return opts;
}
pub fn addExtraModule(self: *BuildSystem, mod: *std.Build.Module, moduleName: []const u8) void {
const dep = self.b.dependency(moduleName, .{ .target = self.target, .optimize = self.optimize, .static_build = self.staticBuild });
mod.addImport(moduleName, dep.module(moduleName));
}
pub fn addDependencyInstalls(self: *BuildSystem, b: *std.Build, optimize: std.builtin.OptimizeMode) void {
//if (self.staticBuild) {
//return;
// }
inline for (DynamicDepList) |d| {
b.installArtifact(b.dependency(
d.dep,
.{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
).artifact(d.artifact));
}
// b.installArtifact(b.dependency(
// "sdl3",
// .{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
// ).artifact("SDL3"));
}
const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } = &.{
.{ .dep = "sdl3", .artifact = "SDL3" },
.{ .dep = "spng", .artifact = "spng_c" },
.{ .dep = "lua", .artifact = "luac" },
// .{ .dep = "miniaudio", .artifact = "miniaudio_c" },
.{ .dep = "zphysics", .artifact = "joltc" },
// .{ .dep = "enet", .artifact = "enet_c" },
.{ .dep = "ozz", .artifact = "ozz_cpp" },
};
// all other modules are disabled by default
pub const defaultEnabledModules: []const []const u8 = &.{
"core",
"assets",
"platform",
"rend",
};
pub const moduleOrder: []const []const u8 = &.{
"core",
"sys",
"assets",
"platform",
"net",
"physics",
"audio",
"rend",
"ui",
"imgui",
"papyrus",
};
pub const DynamicModule = struct {
name: []const u8,
allocator: std.mem.Allocator,
buildSystem: *BuildSystem,
programName: []const u8,
opts: AddProgramOptions,
extras: std.ArrayListUnmanaged(GameModule) = .{},
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
library: ?*std.Build.Step.Compile = null,
pub fn addExtraModule(self: *@This(), module: []const u8) void {
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
}
pub fn init(name: []const u8, p: *Program) *@This() {
var self: *@This() = p.allocator.create(@This()) catch @panic("out of memory");
self.* = .{
.opts = p.opts,
.programName = p.opts.name,
.buildSystem = p.buildSystem,
.allocator = p.allocator,
.name = name,
};
for (p.gameModules.items) |module| {
self.gameModules.append(self.allocator, module) catch @panic("out of memory");
}
for (p.extras.items) |module| {
self.extras.append(self.allocator, module) catch @panic("out of memory");
}
return self;
}
pub fn compileInstall(self: *@This()) *std.Build.Step.Compile {
if (self.library) |lib| {
return lib;
}
const b = self.buildSystem.b;
const static = self.buildSystem.staticBuild;
const lib = if (static)
b.addStaticLibrary(.{
.root_source_file = self.opts.root_source_file,
.link_libc = true,
.optimize = self.buildSystem.optimize,
.target = self.buildSystem.target,
.name = self.name,
})
else
b.addSharedLibrary(.{
.root_source_file = self.opts.root_source_file,
.link_libc = true,
.optimize = self.buildSystem.optimize,
.target = self.buildSystem.target,
.name = self.name,
});
var modlist = std.ArrayList([]const u8).init(self.buildSystem.b.allocator);
for (self.gameModules.items) |mod| {
if (mod.enabled) {
modlist.append(mod.name) catch @panic("out of memory");
}
}
for (self.extras.items) |extra| {
self.buildSystem.addExtraModule(lib.root_module, extra.name);
}
lib.root_module.addImport("backlog", self.buildSystem.generateApi(self.name, modlist.items, null));
lib.root_module.addOptions("BacklogOptions", self.buildSystem.options);
if (static) {
// generateApi should create static callers for the main program
} else {
const installExtern = b.addInstallArtifact(lib, .{
.dest_dir = .{ .override = .{ .custom = "modules" } },
});
b.getInstallStep().dependOn(&installExtern.step);
}
return lib;
}
};
pub const GameModule = struct {
name: []const u8,
enabled: bool = true,
};
pub const Program = struct {
allocator: std.mem.Allocator,
opts: AddProgramOptions,
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
extras: std.ArrayListUnmanaged(GameModule) = .{},
dynamicModules: std.ArrayListUnmanaged(*DynamicModule) = .{},
buildSystem: *BuildSystem,
iconPath: ?std.Build.LazyPath = null,
pub fn setIconPath(self: *@This(), path: []const u8) void {
if (self.iconPath != null) {
return;
}
self.iconPath = self.buildSystem.generateRc(self.opts.name, path) catch return;
}
pub fn setModuleEnabled(self: *@This(), module: []const u8, enable: bool) void {
for (self.gameModules.items) |*m| {
if (std.mem.eql(u8, m.name, module)) {
m.enabled = enable;
return;
}
}
// module not found, add it here.
self.gameModules.append(self.allocator, .{ .name = module, .enabled = enable }) catch @panic("out of memory");
}
pub fn addExtraModule(self: *@This(), module: []const u8) void {
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
}
pub fn addDynamicModule(self: *@This(), module: []const u8, root_source_file: std.Build.LazyPath) *DynamicModule {
const dynamicModule = DynamicModule.init(module, self);
dynamicModule.opts.root_source_file = root_source_file;
self.dynamicModules.append(self.allocator, dynamicModule) catch @panic("out of memory");
return dynamicModule;
}
pub fn compileInstall(self: *@This()) *std.Build.Module {
const exe = self.buildSystem.addProgram(self.opts);
var modlist = std.ArrayList([]const u8).init(self.buildSystem.b.allocator);
for (self.gameModules.items) |mod| {
if (mod.enabled) {
modlist.append(mod.name) catch @panic("out of memory");
}
}
for (self.extras.items) |extra| {
self.buildSystem.addExtraModule(exe, extra.name);
}
exe.addImport("backlog", self.buildSystem.generateApi(self.opts.name, modlist.items, self.dynamicModules.items));
if (self.buildSystem.target.result.os.tag == .windows) {
if (self.iconPath) |ip| {
exe.addWin32ResourceFile(.{
.file = ip,
.flags = &.{},
});
}
}
return exe;
}
};
pub fn program(self: *BuildSystem, opts: AddProgramOptions) *Program {
const prog = self.b.allocator.create(Program) catch unreachable;
prog.* = .{
.allocator = self.b.allocator,
.opts = opts,
.buildSystem = self,
};
for (moduleOrder) |module| {
prog.setModuleEnabled(module, false);
}
for (defaultEnabledModules) |module| {
prog.setModuleEnabled(module, true);
}
return prog;
}
// ========= standalone build instance =======
// maybe the default should be like an engine launcher/project launcher or something
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const spirvDep = b.dependency("SpirvReflect", .{
.target = target,
.optimize = optimize,
.static_build = static_build,
});
_ = spirvDep;
const fwdGeneratorExe = b.addExecutable(.{
.name = "backlog-generate-fwd",
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateFwd.zig"),
});
const generateExe = b.addExecutable(.{
.name = "backlog-apigen",
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateApi.zig"),
});
const generateShaders = b.addExecutable(.{
.name = "backlog-shaderEmbedGen",
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateEmbeddedShaders.zig"),
});
const generateRcExe = b.addExecutable(.{
.name = "backlog-generate-rc",
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateRc.zig"),
});
const generateLoadDynamicsExe = b.addExecutable(.{
.name = "backlog-generate-loadDynamics",
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateLoadDynamics.zig"),
});
b.installArtifact(generateLoadDynamicsExe);
b.installArtifact(generateExe);
b.installArtifact(generateShaders);
b.installArtifact(generateRcExe);
{
const loadDynamicsStub = b.addModule("loadDynamicsStub", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("engine/loadDynamicsStub.zig"),
});
_ = loadDynamicsStub;
const mod = b.addModule("Backlog", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("engine/backlog.zig"),
});
for (engineDepList) |depName| {
const dep = b.dependency(
depName,
.{
.target = target,
.optimize = optimize,
.static_build = static_build,
},
);
const run = b.addRunArtifact(fwdGeneratorExe);
const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName}));
const modFwd = b.addModule(depName, .{
.target = target,
.optimize = optimize,
.root_source_file = output,
});
mod.addImport(b.fmt("{s}", .{depName}), modFwd);
modFwd.addImport("module", dep.module(depName));
// mod.addImport(depName, dep.module(depName));
}
// link in large platform support functions... special case.
{
const dep = b.dependency("sdl3", .{
.target = target,
.optimize = optimize,
.static_build = static_build,
});
const lib = dep.module("SDL3");
mod.addImport("sdl3_fwd", lib);
}
}
}
pub fn generateApi(self: *@This(), programName: []const u8, moduleList: []const []const u8, dynamicModules: ?[]const *DynamicModule) *std.Build.Module {
// std.debug.print("GENERATE API:: {s}\n", .{programName});
for (moduleList) |mod| {
_ = mod;
// std.debug.print("{s}\n", .{mod});
}
//
if (self.generatedApis.get(programName)) |m| {
return m;
}
const run = self.b.addRunArtifact(self.apigen);
const pfile = self.b.fmt("{s}Api.zig", .{programName});
const output = run.addOutputFileArg(pfile);
for (moduleList) |modName| {
run.addArg(modName);
}
const mod = self.b.addModule(pfile, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = output,
});
for (moduleList) |modName| {
mod.addImport(modName, self.nwdep.module(modName));
}
const loadStatics = self.generateInstallStaticResources(programName, "content/_shaders") catch unreachable;
mod.addImport("staticShaderLoader", loadStatics);
// deal with dynamics
if (dynamicModules) |dynamics| {
const loadDynamics = self.generateLoadDynamics(programName, dynamics) catch @panic("unknown");
mod.addImport("loadDynamics", loadDynamics);
} else {
mod.addImport("loadDynamics", self.nwdep.module("loadDynamicsStub"));
}
self.generatedApis.put(self.b.allocator, programName, mod) catch @panic("out of memory");
return mod;
}
pub fn generateRc(self: *@This(), programName: []const u8, iconPath: []const u8) !std.Build.LazyPath {
const run = self.b.addRunArtifact(self.rcGen);
const pfile = self.b.fmt("{s}.rc", .{programName});
const output = run.addOutputFileArg(pfile);
run.addArg(iconPath);
return output;
}
pub fn generateLoadDynamics(self: *@This(), programName: []const u8, dynamics: []const *DynamicModule) !*std.Build.Module {
const run = self.b.addRunArtifact(self.loadDynamicsGen);
const pfile = self.b.fmt("{s}LoadDynamics.zig", .{programName});
const output = run.addOutputFileArg(pfile);
if (self.staticBuild) {
run.addArg("static");
} else {
run.addArg("dynamic");
}
for (dynamics) |dyn| {
run.addArg(dyn.name);
}
const mod = self.b.addModule(pfile, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = output,
});
mod.addImport("core", self.nwdep.module("core"));
for (dynamics) |dyn| {
const dynmod = dyn.compileInstall();
mod.addImport(dyn.name, dynmod.root_module);
}
return mod;
}
pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, shadersPath: []const u8) !*std.Build.Module {
const run = self.b.addRunArtifact(self.shaderEmbedGen);
const pfile = self.b.fmt("{s}ShaderGen.zig", .{programName});
const output = run.addOutputFileArg(pfile);
run.addArg(shadersPath);
const b = self.b;
const mod = self.b.addModule(pfile, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = output,
});
mod.addImport("core", self.nwdep.module("core"));
var dir = try std.fs.cwd().openDir("content/_shaders", .{ .iterate = true });
defer dir.close();
var walker = dir.iterate();
while (try walker.next()) |shaderType| {
if (shaderType.kind == .directory) {
var d2 = try dir.openDir(shaderType.name, .{ .iterate = true });
defer d2.close();
var w2 = d2.iterate();
while (try w2.next()) |shaderName| {
const shaderPath = b.fmt("content/_shaders/{s}/{s}", .{ shaderType.name, shaderName.name });
mod.addAnonymousImport(shaderName.name, .{
.root_source_file = b.path(shaderPath),
});
}
}
}
return mod;
}

584
build.zig
View File

@ -1,42 +1,27 @@
// MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1 -- use this if you're getting that odd crash on mac
b: *std.Build,
nw_builder: *std.Build,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
bEngine: *std.Build, // used to resolve executable paths from within the engine's root directory
opts: bh.Options,
nw_mod: *std.Build.Module,
gltf2ozz: ozz.GltfToOzz,
options: *std.Build.Step.Options,
cookShaders: bool,
backlogRoot: []const u8,
// list of all shaders discovered under
// content/_shaders/def
reflectShaderPathList: [][]u8 = undefined,
staticBuild: bool = false,
nwdep: *std.Build.Dependency,
apigen: *std.Build.Step.Compile,
// apigen: *std.Build.Step.Compile,
shaderEmbedGen: *std.Build.Step.Compile,
loadDynamicsGen: *std.Build.Step.Compile,
rcGen: *std.Build.Step.Compile,
specGen: *std.Build.Step.Compile,
generatedApis: std.StringHashMapUnmanaged(*std.Build.Module) = .{},
const engineDepList = [_][]const u8{
"assets",
"audio",
"core",
"net",
"papyrus",
"platform",
"rend",
"ui",
"imgui",
"physics",
"sys",
};
const BuildSystem = @This();
pub const BuildSystem = @This();
const std = @import("std");
const Build = std.Build;
const LazyPath = Build.LazyPath;
@ -46,41 +31,47 @@ const ozz = @import("ozz");
pub const InitOptions = struct {
import_name: []const u8 = "Backlog",
backlogRoot: []const u8 = "./BacklogEngine",
staticBuild: bool = false,
target: Build.ResolvedTarget,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
};
pub fn init(b: *std.Build, opts: InitOptions) BuildSystem {
var buildOpts = declareBuildOptions(b);
pub fn init(b: *std.Build, initOptions: InitOptions) BuildSystem {
const buildOpts = declareBuildOptions(b);
const opts = bh.Options{
.target = initOptions.target,
.optimize = initOptions.optimize,
.static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false,
.tracy = b.option(bool, "tracy", "builds with tracy support") orelse false,
};
if (opts.target.result.os.tag == .linux) {
// using a static build for linux... object loading hell is not fun
std.debug.print("Important! only supporting static builds for linux", .{});
buildOpts.static_build = true;
// using a static build for linux... object loading hell is not fun...
// i have skill issues in that realm right now
// std.debug.print("Important! only supporting static builds for linux", .{});
// opts.static_build = true;
}
const nwdep = b.dependency(opts.import_name, .{
const nwdep = b.dependency(initOptions.import_name, .{
.target = opts.target,
.optimize = opts.optimize,
.static_build = buildOpts.static_build,
.static_build = opts.static_build,
});
var self = BuildSystem{
.b = b,
.nw_builder = nwdep.builder,
.target = opts.target,
.optimize = opts.optimize,
.bEngine = nwdep.builder,
.opts = opts,
.nw_mod = nwdep.module("Backlog"),
.backlogRoot = opts.backlogRoot,
.options = createGameOptions(b, buildOpts),
.backlogRoot = initOptions.backlogRoot,
.options = createGameOptions(b, buildOpts, opts),
.gltf2ozz = ozz.GltfToOzz.init(nwdep.builder, .{}),
.cookShaders = b.option(bool, "cookShaders", "generates shaders and updates .json files before running the build. (needs to be done whenever shaders are updated, this just runs tools/scripts/cook-shaders.py)") orelse false,
.staticBuild = buildOpts.static_build,
.nwdep = nwdep,
.apigen = nwdep.artifact("backlog-apigen"),
// .apigen = nwdep.artifact("backlog-apigen"),
.loadDynamicsGen = nwdep.artifact("backlog-generate-loadDynamics"),
.specGen = nwdep.artifact("backlog-generate-spec"),
.rcGen = nwdep.artifact("backlog-generate-rc"),
.shaderEmbedGen = nwdep.artifact("backlog-shaderEmbedGen"),
};
@ -110,135 +101,55 @@ pub fn init(b: *std.Build, opts: InitOptions) BuildSystem {
return self;
}
pub const AddProgramOptions = struct {
name: []const u8,
desc: []const u8,
root_source_file: LazyPath,
imports: []const Build.Module.Import = &.{},
};
pub fn addProgram(self: *BuildSystem, opts: AddProgramOptions) *std.Build.Module {
const b = self.b;
const exe = self.nw_builder.addExecutable(.{
.name = opts.name,
.root_module = b.createModule(.{
.target = self.target,
.optimize = self.optimize,
.root_source_file = self.nw_builder.path("engine/main.zig"),
}),
});
b.installArtifact(exe);
const runArtifact = b.addRunArtifact(exe);
if (b.args) |args| {
runArtifact.addArgs(args);
}
const run_exe = b.step(self.b.fmt("run-{s}", .{opts.name}), opts.desc);
run_exe.dependOn(&runArtifact.step);
// main path = name/main.zig
const mod = b.addModule(opts.name, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = opts.root_source_file,
.imports = opts.imports,
});
exe.root_module.addImport("main", mod);
// todo.. remove this one and see what happens
exe.root_module.addImport("core", self.nwdep.module("core"));
// mod.addImport("Backlog", self.nw_mod);
exe.root_module.addOptions("BacklogOptions", self.options);
if (self.cookShaders) {
const cookShadersScript = b.fmt("{s}/tools/scripts/cookShaders.py", .{self.backlogRoot});
const cookShadersCommand = b.addSystemCommand(&[_][]const u8{"python"});
cookShadersCommand.addArg(cookShadersScript);
run_exe.dependOn(&cookShadersCommand.step);
}
b.getInstallStep().dependOn(self.nw_builder.getInstallStep());
// run_exe.dependOn(b.getInstallStep());
return mod;
}
pub const BuildOptions = struct {
// Build Options for the engine,
// should generally be written as false = default
// true = enabling something
const BuildOptions = struct {
mutex_job_queue: bool,
static_build: bool,
zero_logging: bool,
slow_logging: bool,
force_mailbox: bool,
};
pub fn declareBuildOptions(b: *std.Build) BuildOptions {
fn declareBuildOptions(b: *std.Build) BuildOptions {
return .{
.mutex_job_queue = b.option(bool, "mutex_job_queue", "temporary test, reverts to old mutex based queue behaviour in jobs.zig:JobManager") orelse false,
.static_build = b.option(bool, "static_build", "builds the entire game as a single executable") orelse false,
.zero_logging = b.option(bool, "zero_logging", "disables all logging, only intended for use on job dispatch testing") orelse false,
.slow_logging = b.option(bool, "slow_logging", "Disables buffered logging, takes a hit to performance but gain timing information on logging") orelse false,
.force_mailbox = b.option(bool, "force_mailbox", "forces mailbox mode for present mode. unlocks framerate to irresponsible levels") orelse false,
};
}
pub fn createGameOptions(b: *std.Build, options: BuildOptions) *std.Build.Step.Options {
fn createGameOptions(b: *std.Build, options: BuildOptions, bhopts: bh.Options) *std.Build.Step.Options {
const opts = b.addOptions();
inline for (@typeInfo(BuildOptions).@"struct".fields) |field| {
opts.addOption(bool, field.name, @field(options, field.name));
}
// build options for core.zig
// opts.addOption(
// bool,
// "mutex_job_queue",
// );
// opts.addOption(
// bool,
// "static_build",
// );
// opts.addOption(
// bool,
// "zero_logging",
// );
// opts.addOption(
// bool,
// "slow_logging",
// );
// opts.addOption(
// bool,
// "force_mailbox",
// );
// forward the options to the build options
opts.addOption(bool, "tracy", bhopts.tracy);
opts.addOption(bool, "static_build", bhopts.static_build);
return opts;
}
pub fn addExtraModule(self: *BuildSystem, mod: *std.Build.Module, moduleName: []const u8) void {
const dep = self.b.dependency(moduleName, .{ .target = self.target, .optimize = self.optimize, .static_build = self.staticBuild });
const dep = self.b.dependency(moduleName, .{ .target = self.opts.target, .optimize = self.opts.optimize, .static_build = self.opts.static_build });
mod.addImport(moduleName, dep.module(moduleName));
}
pub fn addDependencyInstalls(self: *BuildSystem, b: *std.Build, optimize: std.builtin.OptimizeMode) void {
//if (self.staticBuild) {
//return;
// }
fn addDependencyInstalls(self: *BuildSystem, b: *std.Build, optimize: std.builtin.OptimizeMode) void {
if (self.opts.static_build) {
return;
}
inline for (DynamicDepList) |d| {
b.installArtifact(b.dependency(
d.dep,
.{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
.{ .target = self.opts.target, .optimize = optimize, .static_build = self.opts.static_build },
).artifact(d.artifact));
}
// b.installArtifact(b.dependency(
// "sdl3",
// .{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
// ).artifact("SDL3"));
}
const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } = &.{
@ -251,365 +162,19 @@ const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } =
.{ .dep = "ozz", .artifact = "ozz_cpp" },
};
// all other modules are disabled by default
pub const defaultEnabledModules: []const []const u8 = &.{
"core",
"assets",
"platform",
"rend",
};
pub const moduleOrder: []const []const u8 = &.{
"core",
"sys",
"assets",
"platform",
"net",
"physics",
"audio",
"rend",
"ui",
"imgui",
"papyrus",
};
pub const DynamicModule = struct {
pub fn addProgram(
self: *@This(),
name: []const u8,
allocator: std.mem.Allocator,
buildSystem: *BuildSystem,
programName: []const u8,
opts: AddProgramOptions,
extras: std.ArrayListUnmanaged(GameModule) = .{},
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
library: ?*std.Build.Step.Compile = null,
pub fn addExtraModule(self: *@This(), module: []const u8) void {
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
}
pub fn init(name: []const u8, p: *Program) *@This() {
var self: *@This() = p.allocator.create(@This()) catch @panic("out of memory");
self.* = .{
.opts = p.opts,
.programName = p.opts.name,
.buildSystem = p.buildSystem,
.allocator = p.allocator,
.name = name,
};
for (p.gameModules.items) |module| {
self.gameModules.append(self.allocator, module) catch @panic("out of memory");
}
for (p.extras.items) |module| {
self.extras.append(self.allocator, module) catch @panic("out of memory");
}
return self;
}
pub fn compileInstall(self: *@This()) *std.Build.Step.Compile {
if (self.library) |lib| {
return lib;
}
const b = self.buildSystem.b;
const static = self.buildSystem.staticBuild;
const lib = b.addLibrary(.{
.name = self.name,
.linkage = if (static) .static else .dynamic,
.root_module = b.createModule(.{
.root_source_file = self.opts.root_source_file,
.link_libc = true,
.optimize = self.buildSystem.optimize,
.target = self.buildSystem.target,
}),
});
const allocator = self.buildSystem.b.allocator;
var modlist = std.ArrayList([]const u8){};
for (self.gameModules.items) |mod| {
if (mod.enabled) {
modlist.append(allocator, mod.name) catch @panic("out of memory");
}
}
for (self.extras.items) |extra| {
self.buildSystem.addExtraModule(lib.root_module, extra.name);
}
lib.root_module.addImport("backlog", self.buildSystem.generateApi(self.name, modlist.items, null));
lib.root_module.addOptions("BacklogOptions", self.buildSystem.options);
if (static) {
// generateApi should create static callers for the main program
} else {
const installExtern = b.addInstallArtifact(lib, .{
.dest_dir = .{ .override = .{ .custom = "modules" } },
});
b.getInstallStep().dependOn(&installExtern.step);
}
return lib;
}
};
pub const GameModule = struct {
name: []const u8,
enabled: bool = true,
};
pub const Program = struct {
allocator: std.mem.Allocator,
opts: AddProgramOptions,
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
extras: std.ArrayListUnmanaged(GameModule) = .{},
dynamicModules: std.ArrayListUnmanaged(*DynamicModule) = .{},
buildSystem: *BuildSystem,
iconPath: ?std.Build.LazyPath = null,
pub fn setIconPath(self: *@This(), path: []const u8) void {
if (self.iconPath != null) {
return;
}
self.iconPath = self.buildSystem.generateRc(self.opts.name, path) catch return;
}
pub fn setModuleEnabled(self: *@This(), module: []const u8, enable: bool) void {
for (self.gameModules.items) |*m| {
if (std.mem.eql(u8, m.name, module)) {
m.enabled = enable;
return;
}
}
// module not found, add it here.
self.gameModules.append(self.allocator, .{ .name = module, .enabled = enable }) catch @panic("out of memory");
}
pub fn addExtraModule(self: *@This(), module: []const u8) void {
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
}
pub fn addDynamicModule(self: *@This(), module: []const u8, root_source_file: std.Build.LazyPath) *DynamicModule {
const dynamicModule = DynamicModule.init(module, self);
dynamicModule.opts.root_source_file = root_source_file;
self.dynamicModules.append(self.allocator, dynamicModule) catch @panic("out of memory");
return dynamicModule;
}
pub fn compileInstall(self: *@This()) *std.Build.Module {
const exe = self.buildSystem.addProgram(self.opts);
const allocator = self.buildSystem.b.allocator;
var modlist = std.ArrayList([]const u8){};
for (self.gameModules.items) |mod| {
if (mod.enabled) {
modlist.append(allocator, mod.name) catch @panic("out of memory");
}
}
for (self.extras.items) |extra| {
self.buildSystem.addExtraModule(exe, extra.name);
}
exe.addImport("backlog", self.buildSystem.generateApi(self.opts.name, modlist.items, self.dynamicModules.items));
if (self.buildSystem.target.result.os.tag == .windows) {
if (self.iconPath) |ip| {
exe.addWin32ResourceFile(.{
.file = ip,
.flags = &.{},
});
}
}
return exe;
}
};
pub fn program(self: *BuildSystem, opts: AddProgramOptions) *Program {
const prog = self.b.allocator.create(Program) catch unreachable;
prog.* = .{
.allocator = self.b.allocator,
.opts = opts,
) *Program {
const p = self.b.allocator.create(Program) catch unreachable;
p.* = .{
.name = name,
.opts = self.opts,
.buildSystem = self,
.allocator = self.b.allocator,
};
for (moduleOrder) |module| {
prog.setModuleEnabled(module, false);
}
for (defaultEnabledModules) |module| {
prog.setModuleEnabled(module, true);
}
return prog;
}
// ========= standalone build instance =======
// maybe the default should be like an engine launcher/project launcher or something
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const fwdGeneratorExe = b.addExecutable(.{
.name = "backlog-generate-fwd",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateFwd.zig"),
}),
});
const generateExe = b.addExecutable(.{
.name = "backlog-apigen",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateApi.zig"),
}),
});
const generateShaders = b.addExecutable(.{
.name = "backlog-shaderEmbedGen",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateEmbeddedShaders.zig"),
}),
});
const generateRcExe = b.addExecutable(.{
.name = "backlog-generate-rc",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateRc.zig"),
}),
});
const generateLoadDynamicsExe = b.addExecutable(.{
.name = "backlog-generate-loadDynamics",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("build/generateLoadDynamics.zig"),
}),
});
b.installArtifact(generateLoadDynamicsExe);
b.installArtifact(generateExe);
b.installArtifact(generateShaders);
b.installArtifact(generateRcExe);
{
const loadDynamicsStub = b.addModule("loadDynamicsStub", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("engine/loadDynamicsStub.zig"),
});
_ = loadDynamicsStub;
const mod = b.addModule("Backlog", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("engine/backlog.zig"),
});
for (engineDepList) |depName| {
const dep = b.dependency(
depName,
.{
.target = target,
.optimize = optimize,
.static_build = static_build,
},
);
const run = b.addRunArtifact(fwdGeneratorExe);
const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName}));
const modFwd = b.addModule(depName, .{
.target = target,
.optimize = optimize,
.root_source_file = output,
});
mod.addImport(b.fmt("{s}", .{depName}), modFwd);
modFwd.addImport("module", dep.module(depName));
// mod.addImport(depName, dep.module(depName));
}
// link in large platform support functions... special case.
{
const dep = b.dependency("sdl3", .{
.target = target,
.optimize = optimize,
.static_build = static_build,
});
const lib = dep.module("SDL3");
mod.addImport("sdl3_fwd", lib);
}
}
}
pub fn generateApi(self: *@This(), programName: []const u8, moduleList: []const []const u8, dynamicModules: ?[]const *DynamicModule) *std.Build.Module {
// std.debug.print("GENERATE API:: {s}\n", .{programName});
for (moduleList) |mod| {
_ = mod;
// std.debug.print("{s}\n", .{mod});
}
//
if (self.generatedApis.get(programName)) |m| {
return m;
}
const run = self.b.addRunArtifact(self.apigen);
const pfile = self.b.fmt("{s}Api.zig", .{programName});
const output = run.addOutputFileArg(pfile);
for (moduleList) |modName| {
run.addArg(modName);
}
const mod = self.b.addModule(pfile, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = output,
});
for (moduleList) |modName| {
mod.addImport(modName, self.nwdep.module(modName));
}
const loadStatics = self.generateInstallStaticResources(programName, "content/_shaders") catch unreachable;
mod.addImport("staticShaderLoader", loadStatics);
// deal with dynamics
if (dynamicModules) |dynamics| {
const loadDynamics = self.generateLoadDynamics(programName, dynamics) catch @panic("unknown");
mod.addImport("loadDynamics", loadDynamics);
} else {
mod.addImport("loadDynamics", self.nwdep.module("loadDynamicsStub"));
}
self.generatedApis.put(self.b.allocator, programName, mod) catch @panic("out of memory");
return mod;
return p;
}
pub fn generateRc(self: *@This(), programName: []const u8, iconPath: []const u8) !std.Build.LazyPath {
@ -621,35 +186,6 @@ pub fn generateRc(self: *@This(), programName: []const u8, iconPath: []const u8)
return output;
}
pub fn generateLoadDynamics(self: *@This(), programName: []const u8, dynamics: []const *DynamicModule) !*std.Build.Module {
const run = self.b.addRunArtifact(self.loadDynamicsGen);
const pfile = self.b.fmt("{s}LoadDynamics.zig", .{programName});
const output = run.addOutputFileArg(pfile);
if (self.staticBuild) {
run.addArg("static");
} else {
run.addArg("dynamic");
}
for (dynamics) |dyn| {
run.addArg(dyn.name);
}
const mod = self.b.addModule(pfile, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = output,
});
mod.addImport("core", self.nwdep.module("core"));
for (dynamics) |dyn| {
const dynmod = dyn.compileInstall();
mod.addImport(dyn.name, dynmod.root_module);
}
return mod;
}
pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, shadersPath: []const u8) !*std.Build.Module {
const run = self.b.addRunArtifact(self.shaderEmbedGen);
const pfile = self.b.fmt("{s}ShaderGen.zig", .{programName});
@ -658,8 +194,8 @@ pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, s
const b = self.b;
const mod = self.b.addModule(pfile, .{
.target = self.target,
.optimize = self.optimize,
.target = self.opts.target,
.optimize = self.opts.optimize,
.root_source_file = output,
});
mod.addImport("core", self.nwdep.module("core"));
@ -684,3 +220,15 @@ pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, s
return mod;
}
// ========= standalone build instance =======
// maybe the default should be like an engine launcher/project launcher or something
pub fn build(b: *std.Build) void {
const opts = bh.declareOptions(b);
engineDeps.buildGenerators(b, opts);
}
const bh = @import("bh");
const engineDeps = @import("build/engineDeps.zig");
const program = @import("build/program.zig");
const Program = program.Program;

View File

@ -1,28 +1,23 @@
.{
.name = .Backlog,
.version = "0.0.0",
.dependencies = .{
.assets = .{ .path = "engine/assets" },
.audio = .{ .path = "engine/audio" },
.core = .{ .path = "engine/core" },
.net = .{ .path = "engine/net" },
.papyrus = .{ .path = "engine/papyrus" },
.physics = .{ .path = "engine/physics" },
.platform = .{ .path = "engine/platform" },
.imgui = .{ .path = "engine/imgui" },
.ui = .{ .path = "engine/ui" },
.sys = .{ .path = "engine/sys" },
.rend = .{.path = "engine/rend" },
.{ .name = .Backlog, .version = "0.0.0", .dependencies = .{
.assets = .{ .path = "engine/assets" },
.audio = .{ .path = "engine/audio" },
.core = .{ .path = "engine/core" },
.net = .{ .path = "engine/net" },
.papyrus = .{ .path = "engine/papyrus" },
.physics = .{ .path = "engine/physics" },
.platform = .{ .path = "engine/platform" },
.imgui = .{ .path = "engine/imgui" },
.ui = .{ .path = "engine/ui" },
.sys = .{ .path = "engine/sys" },
.rend = .{ .path = "engine/rend" },
.ozz = .{ .path = "lib/ozz" },
.spng = .{ .path = "lib/spng" },
.zphysics = .{ .path = "lib/zphysics" },
.ozz = .{ .path = "lib/ozz" },
.spng = .{ .path = "lib/spng" },
.zphysics = .{ .path = "lib/zphysics" },
.sdl3 = .{ .path = "lib/sdl3" },
.enet = .{ .path = "lib/enet" },
},
.paths = .{
"",
},
.fingerprint = 0xcf9bab998abe37e3
}
.sdl3 = .{ .path = "lib/sdl3" },
.enet = .{ .path = "lib/enet" },
.bh = .{ .path = "lib/bh" },
}, .paths = .{
"",
}, .fingerprint = 0xcf9bab998abe37e3 }

84
build/Program-old.zig Normal file
View File

@ -0,0 +1,84 @@
pub const AddProgramOptions = struct {
name: []const u8,
desc: []const u8,
root_source_file: LazyPath,
imports: []const Build.Module.Import = &.{},
};
pub const Program = struct {
allocator: std.mem.Allocator,
opts: AddProgramOptions,
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
extras: std.ArrayListUnmanaged(GameModule) = .{},
dynamicModules: std.ArrayListUnmanaged(*DynamicModule) = .{},
buildSystem: *BuildSystem,
iconPath: ?std.Build.LazyPath = null,
pub fn setIconPath(self: *@This(), path: []const u8) void {
if (self.iconPath != null) {
return;
}
self.iconPath = self.buildSystem.generateRc(self.opts.name, path) catch return;
}
pub fn setModuleEnabled(self: *@This(), module: []const u8, enable: bool) void {
for (self.gameModules.items) |*m| {
if (std.mem.eql(u8, m.name, module)) {
m.enabled = enable;
return;
}
}
// module not found, add it here.
self.gameModules.append(self.allocator, .{ .name = module, .enabled = enable }) catch @panic("out of memory");
}
pub fn addExtraModule(self: *@This(), module: []const u8) void {
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
}
pub fn addDynamicModule(self: *@This(), module: []const u8, root_source_file: std.Build.LazyPath) *DynamicModule {
const dynamicModule = DynamicModule.init(module, self);
dynamicModule.opts.root_source_file = root_source_file;
self.dynamicModules.append(self.allocator, dynamicModule) catch @panic("out of memory");
return dynamicModule;
}
pub fn compileInstall(self: *@This()) *std.Build.Module {
const exe = self.buildSystem.addProgram(self.opts);
const allocator = self.buildSystem.b.allocator;
var modlist = std.ArrayList([]const u8){};
for (self.gameModules.items) |mod| {
if (mod.enabled) {
modlist.append(allocator, mod.name) catch @panic("out of memory");
}
}
for (self.extras.items) |extra| {
self.buildSystem.addExtraModule(exe, extra.name);
}
exe.addImport("backlog", self.buildSystem.generateApi(self.opts.name, modlist.items, self.dynamicModules.items));
if (self.buildSystem.target.result.os.tag == .windows) {
if (self.iconPath) |ip| {
exe.addWin32ResourceFile(.{
.file = ip,
.flags = &.{},
});
}
}
return exe;
}
};
const std = @import("std");
const Build = std.Build;
const LazyPath = Build.LazyPath;

138
build/engineDeps.zig Normal file
View File

@ -0,0 +1,138 @@
const engineDepList = [_][]const u8{
"assets",
"audio",
"core",
"net",
"papyrus",
"platform",
"rend",
"ui",
"imgui",
"physics",
"sys",
};
pub fn depList() []const []const u8 {
return &engineDepList;
}
pub fn buildGenerators(b: *std.Build, opts: bh.Options) void {
const target = opts.target;
const optimize = opts.optimize;
const static_build = opts.static_build;
const fwdGeneratorExe = b.addExecutable(.{
.name = "backlog-generate-fwd",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateFwd.zig"),
}),
});
const generateModApiExe = b.addExecutable(.{
.name = "backlog-generate-modapi",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateModApi.zig"),
}),
});
const generateProgramSpecExe = b.addExecutable(.{
.name = "backlog-generate-spec",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateProgramSpec.zig"),
}),
});
const generateShaders = b.addExecutable(.{
.name = "backlog-shaderEmbedGen",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateEmbeddedShaders.zig"),
}),
});
const generateRcExe = b.addExecutable(.{
.name = "backlog-generate-rc",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateRc.zig"),
}),
});
const generateLoadDynamicsExe = b.addExecutable(.{
.name = "backlog-generate-loadDynamics",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateLoadDynamics.zig"),
}),
});
b.installArtifact(fwdGeneratorExe);
b.installArtifact(generateLoadDynamicsExe);
b.installArtifact(generateProgramSpecExe);
b.installArtifact(generateShaders);
b.installArtifact(generateRcExe);
b.installArtifact(generateModApiExe);
{
const loadDynamicsStub = b.addModule("loadDynamicsStub", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("engine/loadDynamicsStub.zig"),
});
_ = loadDynamicsStub;
const mod = b.addModule("Backlog", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("engine/backlog.zig"),
});
for (depList()) |depName| {
const dep = b.dependency(
depName,
.{
.target = target,
.optimize = optimize,
.static_build = static_build,
},
);
const run = b.addRunArtifact(fwdGeneratorExe);
const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName}));
const modFwd = b.addModule(depName, .{
.target = target,
.optimize = optimize,
.root_source_file = output,
});
mod.addImport(b.fmt("{s}", .{depName}), modFwd);
modFwd.addImport("module", dep.module(depName));
}
// link in large platform support functions... special case.
{
const dep = b.dependency("sdl3", .{
.target = target,
.optimize = optimize,
.static_build = static_build,
});
const lib = dep.module("SDL3");
mod.addImport("sdl3_fwd", lib);
}
}
}
const std = @import("std");
const bh = @import("bh");

182
build/modules-old.zig Normal file
View File

@ -0,0 +1,182 @@
// legacy code, kept here as reference
pub const GameModule = struct {
name: []const u8,
enabled: bool = true,
};
pub fn program(self: *BuildSystem, opts: AddProgramOptions) *Program {
const prog = self.b.allocator.create(Program) catch unreachable;
prog.* = .{
.allocator = self.b.allocator,
.opts = opts,
.buildSystem = self,
};
for (moduleOrder) |module| {
prog.setModuleEnabled(module, false);
}
for (defaultEnabledModules) |module| {
prog.setModuleEnabled(module, true);
}
return prog;
}
pub const DynamicModule = struct {
name: []const u8,
allocator: std.mem.Allocator,
buildSystem: *BuildSystem,
programName: []const u8,
opts: Program.AddProgramOptions,
extras: std.ArrayListUnmanaged(Program.GameModule) = .{},
gameModules: std.ArrayListUnmanaged(Program.GameModule) = .{},
library: ?*std.Build.Step.Compile = null,
pub fn addExtraModule(self: *@This(), module: []const u8) void {
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
}
pub fn init(name: []const u8, p: *Program) *@This() {
var self: *@This() = p.allocator.create(@This()) catch @panic("out of memory");
self.* = .{
.opts = p.opts,
.programName = p.opts.name,
.buildSystem = p.buildSystem,
.allocator = p.allocator,
.name = name,
};
for (p.gameModules.items) |module| {
self.gameModules.append(self.allocator, module) catch @panic("out of memory");
}
for (p.extras.items) |module| {
self.extras.append(self.allocator, module) catch @panic("out of memory");
}
return self;
}
pub fn compileInstall(self: *@This()) *std.Build.Step.Compile {
if (self.library) |lib| {
return lib;
}
const b = self.buildSystem.b;
const static = self.buildSystem.staticBuild;
const lib = b.addLibrary(.{
.name = self.name,
.linkage = if (static) .static else .dynamic,
.root_module = b.createModule(.{
.root_source_file = self.opts.root_source_file,
.link_libc = true,
.optimize = self.buildSystem.optimize,
.target = self.buildSystem.target,
}),
});
const allocator = self.buildSystem.b.allocator;
var modlist = std.ArrayList([]const u8){};
for (self.gameModules.items) |mod| {
if (mod.enabled) {
modlist.append(allocator, mod.name) catch @panic("out of memory");
}
}
for (self.extras.items) |extra| {
self.buildSystem.addExtraModule(lib.root_module, extra.name);
}
lib.root_module.addImport("backlog", self.buildSystem.generateApi(self.name, modlist.items, null));
lib.root_module.addOptions("BacklogOptions", self.buildSystem.options);
if (!static) {
const installExtern = b.addInstallArtifact(lib, .{
.dest_dir = .{ .override = .{ .custom = "modules" } },
});
b.getInstallStep().dependOn(&installExtern.step);
}
return lib;
}
};
pub fn generateApi(self: *@This(), programName: []const u8, moduleList: []const []const u8, dynamicModules: ?[]const *DynamicModule,) *std.Build.Module {
// std.debug.print("GENERATE API:: {s}\n", .{programName});
for (moduleList) |mod| {
_ = mod;
// std.debug.print("{s}\n", .{mod});
}
//
if (self.generatedApis.get(programName)) |m| {
return m;
}
const run = self.b.addRunArtifact(self.apigen);
const pfile = self.b.fmt("{s}Api.zig", .{programName});
const output = run.addOutputFileArg(pfile);
for (moduleList) |modName| {
run.addArg(modName);
}
const mod = self.b.addModule(pfile, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = output,
});
for (moduleList) |modName| {
mod.addImport(modName, self.nwdep.module(modName));
}
const loadStatics = self.generateInstallStaticResources(programName, "content/_shaders") catch unreachable;
mod.addImport("staticShaderLoader", loadStatics);
// deal with dynamics
if (dynamicModules) |dynamics| {
const loadDynamics = self.generateLoadDynamics(programName, dynamics) catch @panic("unknown");
mod.addImport("loadDynamics", loadDynamics);
} else {
mod.addImport("loadDynamics", self.nwdep.module("loadDynamicsStub"));
}
self.generatedApis.put(self.b.allocator, programName, mod) catch @panic("out of memory");
return mod;
}
pub fn generateLoadDynamics(self: *@This(), programName: []const u8, dynamics: []const *DynamicModule) !*std.Build.Module {
const run = self.b.addRunArtifact(self.loadDynamicsGen);
const pfile = self.b.fmt("{s}LoadDynamics.zig", .{programName});
const output = run.addOutputFileArg(pfile);
if (self.staticBuild) {
run.addArg("static");
} else {
run.addArg("dynamic");
}
for (dynamics) |dyn| {
run.addArg(dyn.name);
}
const mod = self.b.addModule(pfile, .{
.target = self.target,
.optimize = self.optimize,
.root_source_file = output,
});
mod.addImport("core", self.nwdep.module("core"));
for (dynamics) |dyn| {
const dynmod = dyn.compileInstall();
mod.addImport(dyn.name, dynmod.root_module);
}
return mod;
}

227
build/program.zig Normal file
View File

@ -0,0 +1,227 @@
pub const AddProgramOptions = struct {
name: []const u8,
opt: bh.Options,
root_source_file: std.Build.LazyPath,
};
// all other modules are disabled by default
pub const defaultEnabledModules: []const []const u8 = &.{
"core",
"assets",
"platform",
"rend",
};
pub const moduleOrder: []const []const u8 = &.{
"core",
"sys",
"assets",
"platform",
"net",
"physics",
"audio",
"rend",
"ui",
"imgui",
"papyrus",
};
pub const GameModule = struct {
name: []const u8,
enabled: bool = true,
};
pub const Program = struct {
name: []const u8,
opts: bh.Options,
// root_path: not used yet, we will create a second module that dynamically loads in to that root_path
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
gameModulesMap: std.StringHashMapUnmanaged(bool) = .{},
buildSystem: *backlog.BuildSystem,
iconPath: ?std.Build.LazyPath = null,
allocator: std.mem.Allocator, // just set this to the build allocator
pub fn setModuleEnabled(self: *@This(), name: []const u8, enabled: bool) void {
const r = self.gameModulesMap.getOrPut(self.allocator, name) catch unreachable;
r.value_ptr.* = enabled;
}
fn finalizeModules(self: *@This()) void {
self.gameModules.clearRetainingCapacity();
for (moduleOrder) |mod| {
var enabled: bool = false;
for (defaultEnabledModules) |default| {
if (std.mem.eql(u8, default, mod)) {
enabled = true;
}
}
if (self.gameModulesMap.get(mod)) |value| {
enabled = value;
}
if (enabled) {
self.gameModules.append(self.allocator, .{ .name = mod, .enabled = enabled }) catch unreachable;
}
}
}
pub fn setIconPath(self: *@This(), path: []const u8) void {
if (self.iconPath != null) {
return;
}
self.iconPath = self.buildSystem.generateRc(self.name, path) catch return;
}
pub fn makeSpec(self: *@This()) *std.Build.Module {
const b = self.buildSystem.b;
const run = b.addRunArtifact(self.buildSystem.specGen);
const pfile = run.addOutputFileArg(b.fmt("{s}-spec.zig", .{self.name}));
run.addArg(self.name);
for (self.gameModules.items) |mod| {
if (mod.enabled)
run.addArg(mod.name);
}
const mod = b.createModule(.{
.target = self.opts.target,
.optimize = self.opts.optimize,
.root_source_file = pfile,
});
const core = self.buildSystem.nwdep.module("core");
mod.addImport("core", core);
return mod;
}
pub fn makeGameApi(self: *@This()) *std.Build.Module {
const b = self.buildSystem.b;
const apigen = self.buildSystem.nwdep.artifact("backlog-generate-modapi");
const run = b.addRunArtifact(apigen);
const pfile = run.addOutputFileArg(b.fmt("{s}-api.zig", .{self.name}));
run.addArg(self.name);
for (self.gameModules.items) |mod| {
if (mod.enabled) {
run.addArg(mod.name);
}
}
const api = b.createModule(.{
.target = self.opts.target,
.optimize = self.opts.optimize,
.root_source_file = pfile,
});
for (self.gameModules.items) |mod| {
if (mod.enabled) {
api.addImport(mod.name, self.buildSystem.nwdep.module(mod.name));
}
}
return api;
}
pub fn makeGameModule(self: *@This()) *std.Build.Step.Compile {
const b = self.buildSystem.b;
const bEngine = self.buildSystem.bEngine;
const opts = self.opts;
// 1. generate the main launch codeset.
const lib = b.addLibrary(.{
.name = b.fmt("{s}-mod", .{self.name}),
.linkage = if (opts.static_build) .static else .dynamic,
.root_module = b.createModule(.{
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = bEngine.path("engine/modulelaunch.zig"),
}),
});
if (opts.static_build) {
// b.installArtifact(lib);
} else {
const installExtern = b.addInstallArtifact(lib, .{
.dest_dir = .{ .override = .{ .custom = "modules" } },
});
b.getInstallStep().dependOn(&installExtern.step);
}
return lib;
}
pub fn generateStaticShaders(self: *@This()) *std.Build.Module {
const loadStatics = self.buildSystem.generateInstallStaticResources(self.name, "content/_shaders") catch unreachable;
return loadStatics;
}
// spec is linked in both the base trampoline
pub fn compileInstall(self: *@This()) *std.Build.Step.Compile {
const bEngine = self.buildSystem.bEngine;
const b = self.buildSystem.b;
const core = self.buildSystem.nwdep.module("core");
self.finalizeModules();
// 1. create the loader
const exe = bEngine.addExecutable(.{
.name = self.name,
.root_module = bEngine.createModule(.{
.target = self.opts.target,
.optimize = self.opts.optimize,
.root_source_file = bEngine.path("engine/main2.zig"),
}),
});
// link core
const spec = self.makeSpec();
exe.root_module.addImport("gamespec", spec);
exe.root_module.addImport("core", core);
exe.root_module.addOptions("BacklogOptions", self.buildSystem.options);
if (!self.opts.static_build) {
const platform = self.buildSystem.nwdep.module("platform");
exe.root_module.addImport("platform", platform);
}
if (self.opts.static_build) {
exe.root_module.addImport("staticShaderLoader", self.generateStaticShaders());
}
const gameModule = self.makeGameModule();
const gameApi = self.makeGameApi();
gameModule.root_module.addImport("backlog", gameApi);
gameModule.root_module.addImport("gamespec", spec);
if (self.opts.static_build) {
exe.root_module.addImport("backlog", gameApi);
}
// self.buildSystem.b.installArtifact(exe);
const installed = self.buildSystem.b.addInstallArtifact(exe, .{});
{
const run = b.addSystemCommand(&.{b.fmt("zig-out/bin/{s}", .{self.name})});
run.step.dependOn(&installed.step);
if (b.args) |args| {
run.addArgs(args);
}
const run_exe = b.step(b.fmt("run-{s}", .{self.name}), "runs the program");
run_exe.dependOn(&run.step);
}
return exe;
}
};
const std = @import("std");
const bh = @import("bh");
const backlog = @import("../build.zig");

3
build/resources.zig Normal file
View File

@ -0,0 +1,3 @@
const std = @import("std");
const Build = std.Build;
const LazyPath = Build.LazyPath;

View File

@ -1,19 +1,114 @@
pub fn loadFileAlloc(filename: []const u8, comptime alignment: usize, allocator: std.mem.Allocator) ![]u8 {
var file = try std.fs.cwd().openFile(filename, .{});
defer file.close();
const filesize = (try file.stat()).size + 1; // add null byte
const buffer: []align(alignment) u8 = try allocator.alignedAlloc(u8, alignment, filesize);
errdefer allocator.free(buffer);
try file.reader().readNoEof(buffer[0 .. buffer.len - 1]);
buffer[buffer.len - 1] = 0;
return buffer;
pub fn buildGenerators(b: *std.Build, opts: bh.Options) void {
const target = opts.target;
const optimize = opts.optimize;
const static_build = opts.static_build;
const fwdGeneratorExe = b.addExecutable(.{
.name = "backlog-generate-fwd",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateFwd.zig"),
}),
});
const generateExe = b.addExecutable(.{
.name = "backlog-apigen",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateApi.zig"),
}),
});
const generateShaders = b.addExecutable(.{
.name = "backlog-shaderEmbedGen",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateEmbeddedShaders.zig"),
}),
});
const generateRcExe = b.addExecutable(.{
.name = "backlog-generate-rc",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateRc.zig"),
}),
});
const generateLoadDynamicsExe = b.addExecutable(.{
.name = "backlog-generate-loadDynamics",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateLoadDynamics.zig"),
}),
});
b.installArtifact(fwdGeneratorExe);
b.installArtifact(generateLoadDynamicsExe);
b.installArtifact(generateExe);
b.installArtifact(generateShaders);
b.installArtifact(generateRcExe);
{
const loadDynamicsStub = b.addModule("loadDynamicsStub", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("engine/loadDynamicsStub.zig"),
});
_ = loadDynamicsStub;
const mod = b.addModule("Backlog", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("engine/backlog.zig"),
});
for (depList()) |depName| {
const dep = b.dependency(
depName,
.{
.target = target,
.optimize = optimize,
.static_build = static_build,
},
);
const run = b.addRunArtifact(fwdGeneratorExe);
const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName}));
const modFwd = b.addModule(depName, .{
.target = target,
.optimize = optimize,
.root_source_file = output,
});
mod.addImport(b.fmt("{s}", .{depName}), modFwd);
modFwd.addImport("module", dep.module(depName));
// mod.addImport(depName, dep.module(depName));
}
// link in large platform support functions... special case.
{
const dep = b.dependency("sdl3", .{
.target = target,
.optimize = optimize,
.static_build = static_build,
});
const lib = dep.module("SDL3");
mod.addImport("sdl3_fwd", lib);
}
}
}
pub fn checkAndFormatAst(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(input)), .zig);
const out = try ast.render(allocator);
return out;
}
const std = @import("std");
const bh = @import("bh");

View File

@ -73,10 +73,10 @@ pub fn main() !void {
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(writer.items[0 .. writer.items.len - 1])), .zig);
// std.debug.print("output=\n{s}", .{content.items[0 .. content.items.len - 1]});
defer ast.deinit(allocator);
const out = try ast.renderAlloc(allocator);
std.debug.print("output=\n{s}", .{out});
// Write the content to the file
try file.writeAll(out);
}

View File

@ -0,0 +1,49 @@
const std = @import("std");
pub fn usage() void {
std.debug.print("generates a loader module which calls the start_modules for all the modules that the game module depends on.\ngenerate-mod-api <output file name> <module_name> <module list>\n", .{});
}
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
// Get output filename from build system
const args = try std.process.argsAlloc(allocator);
if (args.len < 3) {
usage();
@panic("Missing output filename\n");
}
const out_path = args[1];
const module_name = args[2];
const module_list = args[3..];
var writer = std.ArrayList(u8){};
try writer.print(allocator, "pub const moduleName:[]const u8 = \"{s}\";\n", .{module_name});
try writer.print(allocator, "pub const moduleList:[]const []const u8 = &.{{\n", .{});
for (module_list) |mod| {
try writer.print(allocator, "\"{s}\",\n", .{mod});
}
try writer.print(allocator, "}};\n", .{});
for (module_list) |mod| {
try writer.print(allocator, "pub const {s} = @import(\"{s}\").module;\n", .{ mod, mod });
}
try writer.append(allocator, 0);
const file = try std.fs.cwd().createFile(out_path, .{});
defer file.close();
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(writer.items[0 .. writer.items.len - 1])), .zig);
// std.debug.print("output=\n{s}", .{writer.items[0 .. writer.items.len - 1]});
defer ast.deinit(allocator);
const out = try ast.renderAlloc(allocator);
// Write the content to the file
try file.writeAll(out);
}

View File

@ -0,0 +1,67 @@
const std = @import("std");
pub fn usage() void {
std.debug.print("generate-program-spec <output file name> <spec_name> <module list>\n", .{});
}
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
// Get output filename from build system
const args = try std.process.argsAlloc(allocator);
if (args.len < 3) {
usage();
@panic("Missing output filename\n");
}
const out_path = args[1];
const programName = args[2];
const modules = args[3..];
// Generate Zig code content
var writer = std.ArrayList(u8){};
_ = try writer.appendSlice(allocator,
\\const core = @import("core").module;
\\
\\ const std = @import("std");
\\ pub fn getSpec() !*core.SpecVariantMap {
\\ const spec = try std.heap.smp_allocator.create(core.SpecVariantMap);
\\ spec.* = try core.createSpecVariant(.{
\\ .useGPA = true,
);
try writer.print(allocator, ".name = \"{s}\",\n", .{programName});
try writer.print(allocator, ".moduleName = \"{s}-mod\",\n", .{programName});
for (modules) |mod| {
try writer.print(allocator, ".{s} = true,\n", .{mod});
}
_ = try writer.appendSlice(allocator,
\\ }, std.heap.smp_allocator);
\\
\\ return spec;
\\ }
\\
);
_ = try writer.print(allocator, "pub const programName = \"{s}\";", .{programName});
try writer.append(allocator, 0);
// Write to specified output file
// Open or create the file for writing (overwrites if it exists)
const file = try std.fs.cwd().createFile(out_path, .{});
defer file.close();
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(writer.items[0 .. writer.items.len - 1])), .zig);
// std.debug.print("output=\n{s}", .{content.items[0 .. content.items.len - 1]});
defer ast.deinit(allocator);
const out = try ast.renderAlloc(allocator);
// Write the content to the file
try file.writeAll(out);
}

View File

@ -0,0 +1,11 @@
// templated file
//
// should still be a formattable zig file
// even if it is not compile-able
//
// definitions marked with // TEMPLATE_DEFINITION
// are removed during the templating step
const programName = "__program_name"; // TEMPLATE_DEFINITION
export fn loadModule() void {}

View File

@ -0,0 +1,26 @@
// templated file
//
// should still be a formattable zig file
// even if it is not compile-able
//
// definitions marked with // TEMPLATE_DEFINITION
// are removed during the templating step
const core = @import("core");
const programName = "__program_name"; // TEMPLATE_DEFINITION
pub export fn startup_module(p_allocator: *anyopaque, p_a: ?*anyopaque) bool {
const allocator = core.modulePreamble(p_allocator, p_a) catch return false;
_ = allocator;
// imgui.setupFromModule();
// platform.setupFromModule();
// sys.setupFromModule();
// rend.setupFromModule();
// backlog.physics.setupFromModule();
core.engine_logs("creating externgame");
// start_module(core.startup_getArgs(p_a.?)) catch return false;
return true;
}

View File

@ -0,0 +1,14 @@
pub export fn startup_module(p_allocator: *anyopaque, p_a: ?*anyopaque) bool {
const allocator = core.modulePreamble(p_allocator, p_a) catch return false;
_ = allocator;
core.engine_logs("module started");
return true;
}
pub export fn shutdown_module() void {}
// const backlog = @import("backlog");
// const core = backlog.core;
const core = @import("core").module;

19
buildgen/utils.zig Normal file
View File

@ -0,0 +1,19 @@
pub fn loadFileAlloc(filename: []const u8, comptime alignment: usize, allocator: std.mem.Allocator) ![]u8 {
var file = try std.fs.cwd().openFile(filename, .{});
defer file.close();
const filesize = (try file.stat()).size + 1; // add null byte
const buffer: []align(alignment) u8 = try allocator.alignedAlloc(u8, alignment, filesize);
errdefer allocator.free(buffer);
try file.reader().readNoEof(buffer[0 .. buffer.len - 1]);
buffer[buffer.len - 1] = 0;
return buffer;
}
pub fn checkAndFormatAst(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(input)), .zig);
const out = try ast.render(allocator);
return out;
}
const std = @import("std");

View File

@ -21,7 +21,8 @@ pub fn tick(self: *@This(), dt: f64) void {
}
pub fn deinit(self: *@This()) void {
self.allocator.destroy(self);
// Engine handles memory deallocation
_ = self;
}
pub fn main() anyerror!void {

View File

@ -120,11 +120,6 @@ pub const AssetLoaderInterface = struct {
unreachable;
}
if (!@hasDecl(TargetType, "destroy")) {
@compileLog("Tried to generate AssetLoaderInterface for type ", TargetType, "but it's missing func destroy.");
unreachable;
}
const self = @This(){
.typeName = @typeName(TargetType),
.typeSize = @sizeOf(TargetType),
@ -159,15 +154,15 @@ pub const AssetReferenceSys = struct {
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "AssetReference");
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = @This(){
.loaders = .{},
.allocator = allocator,
.outstandingAssetJobs = std.atomic.Value(i32).init(0),
};
return self;
}
pub fn registerLoader(self: *@This(), loader: anytype) !void {
@ -210,6 +205,5 @@ pub const AssetReferenceSys = struct {
// i.destroy(self.allocator);
// }
self.loaders.deinit(self.allocator);
self.allocator.destroy(self);
}
};

View File

@ -73,8 +73,10 @@ pub const SoundEngine = struct {
allocator: std.mem.Allocator,
volume: f32 = 1.0,
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = @This(){
.engine = allocator.create(ma.ma_engine) catch unreachable,
.sounds = .{},
@ -83,8 +85,6 @@ pub const SoundEngine = struct {
};
_ = ma.ma_engine_init(null, self.engine);
return self;
}
pub fn shutdown(self: *@This()) void {

View File

@ -0,0 +1,7 @@
pub const std = @import("std");
const core = @import("core");
const impl = core;
pub const inputs = struct {
pub const getInputStack = inputs.getInputStack;
};

View File

@ -28,8 +28,10 @@ pub fn build(b: *std.Build) void {
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libc = true,
.root_source_file = b.path("tests/tests.zig"),
}),
.use_llvm = true,
});
const sampleGameExtern = b.addLibrary(.{
@ -40,6 +42,7 @@ pub fn build(b: *std.Build) void {
.target = target,
}),
.linkage = .dynamic,
.use_llvm = true,
.name = "external",
});
sampleGameExtern.root_module.addImport("core", mod);

View File

@ -1,17 +1,16 @@
pub const ConfigRegistry = struct {
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.ConfigRegistry");
allocator: std.mem.Allocator,
allocator: std.mem.Allocator = undefined,
configMap: ?ConfigMap = null,
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.allocator = allocator,
};
return self;
}
// by convention this should be in the root
@ -38,11 +37,10 @@ pub const ConfigRegistry = struct {
}
pub fn destroy(self: *@This()) void {
pub fn deinit(self: *@This()) void {
if (self.configMap) |*map| {
map.deinit();
}
self.allocator.destroy(self);
}
};

View File

@ -8,21 +8,22 @@ pub const ConsoleCommand = struct {
pub const Console = struct {
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.Console");
allocator: std.mem.Allocator,
arena: std.heap.ArenaAllocator,
allocator: std.mem.Allocator = undefined,
arena: std.heap.ArenaAllocator = undefined,
commandMap: std.StringHashMapUnmanaged(ConsoleCommand) = .{},
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first) {
return;
}
self.* = .{
.arena = std.heap.ArenaAllocator.init(allocator),
.allocator = allocator,
};
core.engine_logs("console system created");
return self;
}
pub fn addConsoleCommand(self: *@This(), funcName: []const u8, func: ConsoleFunc) !void {
@ -56,10 +57,9 @@ pub const Console = struct {
}
}
pub fn destroy(self: *@This()) void {
pub fn deinit(self: *@This()) void {
self.arena.deinit();
self.commandMap.deinit(self.allocator);
self.allocator.destroy(self);
}
};

View File

@ -29,6 +29,8 @@ pub const debugLine = debug_draw.debugLine;
pub const engineTime = @import("engineTime.zig");
pub const engineObject = @import("engineObject.zig");
pub const EngineObjectOpts = engineObject.EngineObjectOpts;
pub const ObjectOpts = engineObject.EngineObjectOpts;
pub const EngineObjectVTable = engineObject.EngineObjectVTable;
pub const MakeTypeName = engineObject.MakeTypeName;
pub const PatchStruct = engineObject.PatchStruct;
@ -170,7 +172,7 @@ pub const packer = @import("packer");
pub const StackCompactor = stacks.StackCompactor;
var staticsInitialized = false;
pub var staticsInitialized = false;
var gEngine: *Engine = undefined;
pub const PackerFS = packer.PackerFS;
var gPackerFS: *PackerFS = undefined;
@ -272,8 +274,6 @@ pub fn maybeInitPackerFs(allocator: std.mem.Allocator) !void {
}
pub fn start_module_(map: *SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void {
staticsInitialized = true;
if (map.get("utility")) |x| {
if (x.boolean == true) {
engine_logs("utility mode - no gui");
@ -297,8 +297,7 @@ pub fn start_module_(map: *SpecVariantMap, args: anytype, allocator: std.mem.All
gEngine = try allocator.create(Engine);
gEngine.* = try Engine.init(allocator);
_ = try createObject(ModuleLoader, .{});
try console.start();
staticsInitialized = true;
const engineName = try std.fmt.allocPrint(allocator, "{s}Engine.ini", .{name});
defer allocator.free(engineName);
@ -309,14 +308,15 @@ pub fn start_module_(map: *SpecVariantMap, args: anytype, allocator: std.mem.All
try logging.setupLogging(gEngine);
}
try ecs.setup(allocator);
_ = try gEngine.createObject(scene.SceneSystem, .{ .can_tick = true });
try algorithm.string_pool.setup(allocator);
gEngine.stringContext = algorithm.string_pool.gStringContext;
_ = try createObject(ModuleLoader, .{});
_ = try createObject(ecs.EcsRegistry, .{ .can_tick = true, .isCore = true });
_ = try createObject(scene.SceneSystem, .{ .can_tick = true });
_ = try createObject(GameObjectSystem, .{ .can_tick = true });
_ = try inputs.initInputStack();
_ = try createObject(inputs.InputStack, .{});
_ = try createObject(console.Console, .{});
// components define
try ecs.defineComponentList(ComponentList, allocator);
@ -328,6 +328,7 @@ pub fn setupFromModule(__args: ModuleLoaderArgs) !void {
gEngine = __args.engine;
gPackerFS = __args.packerFS;
algorithm.names.gRegistry = __args.nameRegistry;
algorithm.string_pool.gStringContext = gEngine.stringContext;
logging.setupLoggingFromModule();
staticsInitialized = true;
@ -525,7 +526,11 @@ pub fn startup_getArgs(p_allocator: *anyopaque) ModuleLoaderArgs {
pub fn modulePreamble(p_allocator: *anyopaque, p_a: ?*anyopaque) !std.mem.Allocator {
const args = startup_getArgs(p_a.?);
const allocator = startup_getAllocator(p_allocator);
try setupFromModule(args);
if (comptime !BuildOption("static_build")) {
try setupFromModule(args);
}
return allocator;
}
@ -609,3 +614,7 @@ pub fn itof32(i: anytype) f32 {
pub fn itof64(i: anytype) f32 {
return @as(f32, @floatFromInt(i));
}
pub fn setShutdownModule(shutdownFunction: *const fn () callconv(.c) void) void {
getEngine().shutdownModuleFunction = shutdownFunction;
}

View File

@ -210,15 +210,15 @@ pub const EcsRegistry = struct {
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "core.EcsRegistry");
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first) {
return;
}
self.* = .{
.allocator = allocator,
.baseSet = BaseSet.init(allocator),
};
return self;
}
pub fn registerContainer(self: *@This(), ref: EcsContainerRef, _containerName: core.Name) !void {
@ -279,13 +279,11 @@ pub const EcsRegistry = struct {
}
pub fn deinit(self: *@This()) void {
self.destroy();
}
// this should never work... wtf?
// for (self.containers.items) |ref| {
// ref.vtable.evictFromRegistry(ref.ptr);
// }
pub fn destroy(self: *@This()) void {
for (self.containers.items) |ref| {
ref.vtable.evictFromRegistry(ref.ptr);
}
for (self.systems.items) |ref| {
ref.vtable.destroy(ref.ptr);
}
@ -300,7 +298,6 @@ pub const EcsRegistry = struct {
self.containers.deinit(self.allocator);
self.containerNames.deinit(self.allocator);
self.containersByName.deinit(self.allocator);
self.allocator.destroy(self);
}
};

View File

@ -5,6 +5,7 @@ const time = @import("engineTime.zig");
const core = @import("core.zig");
const jobs = @import("jobs.zig");
const math = @import("math.zig");
const builtin = @import("builtin");
const pscopes = core.algorithm.pscopes;
const tracy = @import("tracy").t;
@ -91,6 +92,9 @@ pub const Engine = struct {
calibrationPeriod: f64 = 1.0, // in seconds
first: bool = true,
shutdownModuleFunction: ?*const fn () callconv(.c) void = null,
stringContext: *core.algorithm.string_pool.StringContext = undefined,
pub fn init(allocator: std.mem.Allocator) !@This() {
const rv = Engine{
.allocator = allocator,
@ -126,9 +130,7 @@ pub const Engine = struct {
var i: i32 = @intCast(self.destroyListCore.items.len - 1);
while (i >= 0) : (i -= 1) {
const item = self.destroyListCore.items[@as(usize, @intCast(i))];
if (item.vtable.deinit_func) |deinitFn| {
deinitFn(item.ptr);
}
self.destroyObject(item);
}
}
self.destroyListCore.deinit(self.allocator);
@ -159,6 +161,10 @@ pub const Engine = struct {
return @ptrCast(@alignCast(rv));
}
const DebugSlack = struct {
slack: [1024 * 64]u8 align(16) = undefined,
};
// creates an engine object using the engine's allocator.
pub fn createObjectVTable(self: *@This(), vtable: *core.EngineObjectVTable, params: NeonObjectParams) !*anyopaque {
if (self.createObjectLock) {
@ -170,7 +176,17 @@ pub const Engine = struct {
self.createObjectLock = true;
defer self.createObjectLock = false;
const newIndex = self.engineObjects.items.len;
const newObjectPtr = try vtable.init_func(self.allocator); // call this thing with the special allocator that adds vtable. slackSize to it.
var newObjectPtr: *anyopaque = undefined; //self.allocator.create(DebugSlack);
if (comptime core.BuildOption("static_build")) {
newObjectPtr = @ptrCast(@alignCast((try self.allocator.alignedAlloc(u8, .@"16", vtable.typeSize))));
} else {
newObjectPtr = @ptrCast(@alignCast((try self.allocator.create(DebugSlack))));
}
try vtable.init_func(newObjectPtr, self.allocator, true);
// try vtable.init_func(self.allocator); // call this thing with the special allocator that adds vtable. slackSize to it.
const newObjectRef = EngineObjectRef{
.ptr = @as(*anyopaque, @ptrCast(newObjectPtr)),
@ -356,14 +372,29 @@ pub const Engine = struct {
self.destroyDependents();
}
fn destroyObject(self: *@This(), item: EngineObjectRef) void {
core.engine_log("destroying object {s}", .{item.vtable.typeName});
if (item.vtable.deinit_func) |deinitFn| {
deinitFn(item.ptr);
}
if (comptime core.BuildOption("static_build")) {
var slice: []u8 = undefined;
slice.ptr = @ptrCast(@alignCast(item.ptr));
slice.len = item.vtable.typeSize;
self.allocator.rawFree(slice, .@"16", @returnAddress());
} else {
const asStruct: *DebugSlack = @ptrCast(@alignCast(item.ptr));
self.allocator.destroy(asStruct);
}
}
fn destroyDependents(self: *@This()) void {
if (self.destroyListSimple.items.len > 0) {
var i: i32 = @intCast(self.destroyListSimple.items.len - 1);
while (i >= 0) : (i -= 1) {
const item = self.destroyListSimple.items[@as(usize, @intCast(i))];
if (item.vtable.deinit_func) |deinitFn| {
deinitFn(item.ptr);
}
self.destroyObject(item);
}
}
self.dependentsDestroyed.store(true, .seq_cst);

View File

@ -68,10 +68,6 @@ pub fn updateEngineVTable(comptime T: type) void {
vtable.* = T.NeonObjectTable;
vtable.version = version + 1;
if (@hasDecl(T, "objectReload")) {
core.get(T).objectReload();
}
}
pub fn PatchStruct(comptime T: type, p: *T, old: []const FieldInfo) void {
@ -167,7 +163,8 @@ pub const EngineObjectVTable = struct {
singletonName: ?[]const u8 = null,
init_func: *const fn (std.mem.Allocator) EngineDataEventError!*anyopaque,
// new init_function passes in an already created object
init_func: *const fn (*anyopaque, std.mem.Allocator, bool) EngineDataEventError!void,
tick_func: ?*const fn (*anyopaque, f64) void = null,
engineDraw_func: ?*const fn (*anyopaque, f64) void = null,
preTick_func: ?*const fn (*anyopaque, f64) EngineDataEventError!void = null,
@ -271,11 +268,10 @@ pub const EngineObjectVTable = struct {
if (@hasDecl(TargetType, "init")) {
const wrappedInit = struct {
const funcFind: @TypeOf(@field(TargetType, "init")) = @field(TargetType, "init");
pub fn func(allocator: std.mem.Allocator) EngineDataEventError!*anyopaque {
const newObject = funcFind(allocator) catch return error.BadInit;
return @as(*anyopaque, @ptrCast(newObject));
pub fn func(p: *anyopaque, allocator: std.mem.Allocator, first: bool) EngineDataEventError!void {
const newObject: *TargetType = @ptrCast(@alignCast(p)); // funcFind(allocator) catch return error.BadInit;
newObject.init(allocator, first) catch return error.BadInit;
// return @as(*anyopaque, @ptrCast(newObject));
}
};
@ -284,11 +280,10 @@ pub const EngineObjectVTable = struct {
if (@hasDecl(TargetType, "create")) {
const wrappedInit = struct {
const funcFind: @TypeOf(@field(TargetType, "create")) = @field(TargetType, "create");
pub fn func(allocator: std.mem.Allocator) EngineDataEventError!*anyopaque {
const newObject = funcFind(allocator) catch return error.BadInit;
return @as(*anyopaque, @ptrCast(newObject));
pub fn func(p: *anyopaque, allocator: std.mem.Allocator, first: bool) EngineDataEventError!void {
const newObject: *TargetType = @ptrCast(@alignCast(p)); // funcFind(allocator) catch return error.BadInit;
newObject.create(allocator, first) catch return error.BadInit;
// return @as(*anyopaque, @ptrCast(newObject));
}
};

View File

@ -5,8 +5,12 @@ const pscopes = core.algorithm.pscopes;
// returns time since engine started in nanoseconds
pub fn getEngineTime() f64 {
const read = core.getEngine().rootTimer.read();
return @as(f64, @floatFromInt(read)) / std.time.ns_per_s;
if (core.staticsInitialized) {
const read = core.getEngine().rootTimer.read();
return @as(f64, @floatFromInt(read)) / std.time.ns_per_s;
}
return 0;
}
// returns a pscopes.TimingScope for the current time.

View File

@ -121,22 +121,23 @@ fn dllChangedCallback(pathChanged: []const u8, ctx: ?*anyopaque) void {
}
pub const ModuleLoader = struct {
backingAllocator: std.mem.Allocator,
arena: std.heap.ArenaAllocator,
backingAllocator: std.mem.Allocator = undefined,
arena: std.heap.ArenaAllocator = undefined,
loadedModules: std.ArrayListUnmanaged(*LoadedModule) = .{},
watchInitialized: bool = false,
watchInitializeFn: ?*const fn () void = null,
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "core.ModuleLoader");
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first) {
return;
}
self.* = .{
.backingAllocator = allocator,
.arena = std.heap.ArenaAllocator.init(allocator),
};
return self;
}
pub fn addModule(self: *@This(), moduleName: []const u8) !void {
@ -169,6 +170,7 @@ pub const ModuleLoader = struct {
}
try core.fs().addFileChangedCallback(libFileName, dllChangedCallback, loaded);
core.engine_log("[ModuleLoader]: addFileChangedCallback '{s}'", .{libFileName});
try self.loadedModules.append(self.arena.allocator(), loaded);
}
@ -214,10 +216,9 @@ pub const ModuleLoader = struct {
}
}
pub fn destroy(self: *@This()) void {
pub fn deinit(self: *@This()) void {
// std.fs.cwd().deleteTree(".modulecache") catch {};
self.arena.deinit();
self.backingAllocator.destroy(self);
}
};

View File

@ -71,21 +71,20 @@ pub const GameObjectSystem = struct {
// this is the new one, GameObjectList should be deleted after this passes initial usability
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "core.GameObjectSystem");
allocator: std.mem.Allocator,
allocator: std.mem.Allocator = undefined,
objectDefinitions: std.AutoHashMapUnmanaged(u32, GameObjectInterfaceVTable) = .{},
typesArena: std.heap.ArenaAllocator,
typesArena: std.heap.ArenaAllocator = undefined,
objectSpawnEvents: std.ArrayListUnmanaged(SpawnEvent) = .{},
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.allocator = allocator,
.typesArena = std.heap.ArenaAllocator.init(self.allocator),
};
return self;
}
pub fn spawnObject(self: *@This(), comptime T: type, objectName: []const u8, parameters: SpawnParameters) !*T {
@ -177,9 +176,8 @@ pub const GameObjectSystem = struct {
_ = dt;
}
pub fn destroy(self: *@This()) void {
pub fn deinit(self: *@This()) void {
self.typesArena.deinit();
self.allocator.destroy(self);
}
};

View File

@ -574,11 +574,11 @@ pub const BindingLayer = struct {
// not gonna actually deal with layers right now
pub const InputStack = struct {
allocator: std.mem.Allocator,
allocator: std.mem.Allocator = undefined,
active: ?*BindingLayer,
active: ?*BindingLayer = undefined,
bindingStack: std.ArrayListUnmanaged(*BindingLayer) = .{},
arena: std.heap.ArenaAllocator,
arena: std.heap.ArenaAllocator = undefined,
keysDown: std.AutoHashMapUnmanaged(Key, bool) = .{},
@ -591,8 +591,10 @@ pub const InputStack = struct {
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.InputStack");
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first) {
return;
}
self.* = .{
.allocator = allocator,
@ -601,8 +603,6 @@ pub const InputStack = struct {
};
core.EngineObject(@This()).gInstance = self;
return self;
}
pub fn updatePreviousInputs(self: *@This()) void {
@ -716,7 +716,6 @@ pub const InputStack = struct {
if (self.active) |active| {
active.destroy();
}
self.allocator.destroy(self);
}
};

View File

@ -192,13 +192,13 @@ pub const FileLog = struct {
pub const LoggerSys = struct {
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.LoggerSys");
writeOutBuffer: std.ArrayList(u8),
flushBuffer: std.ArrayList(u8),
allocator: std.mem.Allocator,
logFilePath: []const u8,
logFile: std.fs.File,
consoleFile: std.fs.File,
writerBuffer: []u8,
writeOutBuffer: std.ArrayList(u8) = .{},
flushBuffer: std.ArrayList(u8) = .{},
allocator: std.mem.Allocator = undefined,
logFilePath: []const u8 = "none",
logFile: std.fs.File = undefined,
consoleFile: std.fs.File = undefined,
writerBuffer: []u8 = undefined,
lock: std.Thread.Mutex = .{},
flushing: std.atomic.Value(bool) = std.atomic.Value(bool).init(false),
@ -306,12 +306,14 @@ pub const LoggerSys = struct {
}
}
pub fn init(allocator: std.mem.Allocator) !*@This() {
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first) {
return;
}
const cwd = std.fs.cwd();
const ofile = std.fmt.allocPrint(allocator, core.DefaultSavePath ++ "/{s}", .{"Session_Log.txt"}) catch unreachable;
cwd.makePath(core.DefaultSavePath) catch unreachable;
const self = try allocator.create(@This());
self.* = @This(){
.allocator = allocator,
.writeOutBuffer = std.ArrayList(u8).initCapacity(allocator, LogBufferSize) catch unreachable,
@ -321,8 +323,6 @@ pub const LoggerSys = struct {
.logFile = cwd.createFile(ofile, .{}) catch unreachable,
.consoleFile = std.fs.File.stdout(),
};
return self;
}
pub fn deinit(self: *@This()) void {
@ -333,8 +333,6 @@ pub const LoggerSys = struct {
self.writeOutBuffer.deinit(self.allocator);
self.flushBuffer.deinit(self.allocator);
self.allocator.destroy(self);
}
pub fn processEvents(self: *@This(), frameNumber: u64) core.EngineDataEventError!void {

View File

@ -296,9 +296,9 @@ fn childAllocator() std.mem.Allocator {
pub const SceneSystem = struct {
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.SceneSystem");
allocator: std.mem.Allocator,
allocator: std.mem.Allocator = undefined,
dynamicObjects: ArrayListUnmanaged(core.ObjectHandle) = .{},
childrenArena: std.heap.ArenaAllocator,
childrenArena: std.heap.ArenaAllocator = undefined,
tickCount: u32 = 0,
sceneObjectContainer: *SceneObjectSet = undefined,
@ -385,8 +385,11 @@ pub const SceneSystem = struct {
pub const MaxWorkerCount = 24;
// ----- NeonObject interace ----
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first) {
return;
}
self.* = .{
.allocator = allocator,
.childrenArena = std.heap.ArenaAllocator.init(allocator),
@ -401,8 +404,6 @@ pub const SceneSystem = struct {
try self.cachedOutputs.append(self.allocator, .{});
try self.writeOutList.append(self.allocator, .{});
}
return self;
}
pub fn getOutputList(self: *@This(), threadId: u32) !*std.ArrayList(usize) {
@ -446,7 +447,6 @@ pub const SceneSystem = struct {
Scene.SceneObjectContainer.destroy();
self.cachedOutputs.deinit(self.allocator);
self.writeOutList.deinit(self.allocator);
self.allocator.destroy(self);
}
};

View File

@ -1,22 +1,17 @@
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "testing.sampleSubsystem");
allocator: std.mem.Allocator,
scene: *anyopaque,
setPositionPtr: *const anyopaque,
allocator: std.mem.Allocator = undefined,
scene: *anyopaque = undefined,
setPositionPtr: *const anyopaque = undefined,
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first) {
return;
}
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
self.* = .{
.allocator = allocator,
.scene = undefined,
.setPositionPtr = undefined,
};
return self;
}
pub fn destroy(self: *@This()) void {
self.allocator.destroy(self);
}
const exampleScene = @import("exampleScene.zig");

View File

@ -15,14 +15,13 @@ pub const Impl = struct {
};
// renderer plugin
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.allocator = allocator,
};
return self;
}
const ImguiArgs = struct { imguiIni: []const u8 = "imgui.ini" };
@ -109,11 +108,6 @@ pub const Impl = struct {
_ = ig.dockSpaceOverViewport(ig.getMainViewport(), .{ .passthru_central_node = true }, null);
_ = dt;
}
// renderer plugin
pub fn destroy(self: *@This()) void {
self.allocator.destroy(self);
}
};
const c = @import("cimgui").c;
const ig = @import("cimgui");

View File

@ -1,5 +1,4 @@
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "game.TopBar");
pub const Slack = core.SlackStruct(@This(), 256);
allocator: std.mem.Allocator,
arena: std.heap.ArenaAllocator,
@ -7,8 +6,10 @@ windowsMenu: std.ArrayListUnmanaged(*MenuEntry) = .{},
entriesByName: std.AutoHashMapUnmanaged(u32, *MenuEntry) = .{},
menuOpen: bool = false,
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try Slack.create(allocator);
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.allocator = allocator,
.arena = std.heap.ArenaAllocator.init(allocator),
@ -21,8 +22,6 @@ pub fn create(allocator: std.mem.Allocator) !*@This() {
.ctx = self,
.windowFunction = windowOpen,
});
return self;
}
pub fn setEntryOpen(self: *@This(), name: []const u8, open: ?bool) void {
@ -108,7 +107,6 @@ pub fn tick(self: *@This(), dt: f64) void {
pub fn destroy(self: *@This()) void {
self.arena.deinit();
self.allocator.destroy(Slack.fromPtr(self));
}
pub const MenuEntry = struct {

View File

@ -6,16 +6,16 @@ consolePressedEnter: bool = false,
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "extras.consoleWindow");
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.allocator = allocator,
.buffer = core.logging.LogBuffer.init(allocator),
};
self.setup();
return self;
}
pub fn setup(self: *@This()) void {
@ -65,7 +65,6 @@ pub fn windowOpen(entry: *imgui.utils.MenuEntry, dt: f64) void {
pub fn destroy(self: *@This()) void {
self.buffer.deinit();
self.allocator.destroy(self);
}
const imgui = @import("../imgui.zig");

161
engine/main2.zig Normal file
View File

@ -0,0 +1,161 @@
const std = @import("std");
const core = @import("core").module;
const panickers = core.panickers;
// const realMain = @import("main");
pub const gamespec = @import("gamespec");
pub const options = @import("BacklogOptions");
pub const std_options = std.Options{
.enable_segfault_handler = true,
};
//pub const build_options = @import("build_options");
//pub const tracy_enabled = build_options.tracy_enabled;
// pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, x: ?usize) noreturn {
// core.forceFlush();
// core.script.lua.takeDump();
// std.debug.defaultPanic(error_return_trace, x, msg);
// }
pub const NwArgs = struct {
useGPA: bool = false, // slower zig based memory allocator, provides detailed tracking of leaks and memory violations
vulkanValidation: bool = true,
fastTest: bool = false,
dmt: bool = false, // detailed memory tracking, implements a timeline for tracking all memory allocations
fatDump: bool = false, // takes a full fat minidump on crash, very large files are produced
};
pub fn getArgs() !NwArgs {
const a = try core.ParseArgs(NwArgs);
return a;
}
fn fileExists(path: []const u8) bool {
std.fs.cwd().access(path, .{}) catch return false;
return true;
}
pub fn run() !void {
core.engine_logs("calling gEngine.run");
try core.getEngine().run();
while (!core.getEngine().exitFinished()) {
const z = core.tracy.ZoneN(@src(), "shutdown poll");
z.End();
}
}
pub fn startEngine(spec: *core.SpecVariantMap) bool {
const args = getArgs() catch return false;
var backingAllocator: std.mem.Allocator = std.heap.smp_allocator;
var gpa: std.heap.GeneralPurposeAllocator(.{
.stack_trace_frames = 20,
}) = .{};
defer {
const cleanupStatus = gpa.deinit();
if (cleanupStatus == .leak) {
std.debug.print("gpa cleanup leaked memory\n", .{});
}
}
if (spec.get("useGPA")) |arg| {
if (arg.boolean == true) {
backingAllocator = gpa.allocator();
}
}
const memory = core.MemoryTracker;
memory.MTSetup(backingAllocator, .{ .timeline = args.dmt });
defer memory.MTShutdown();
var tracker = memory.MTGet().?;
const allocator = tracker.allocator();
_ = core.createNameRegistry(allocator) catch return false;
core.maybeInitPackerFs(allocator) catch return false;
if (comptime core.BuildOption("static_build")) {
core.engine_log("static build, using embedded shaders", .{});
const loader = @import("staticShaderLoader");
loader.installStaticResources() catch return false;
}
core.start_module(spec, args, allocator) catch return false;
const moduleName = spec.get("moduleName").?.string;
if (comptime core.BuildOption("static_build")) {
core.engine_logs("static build");
const modlaunch = @import("modulelaunch.zig");
var modargs = core.externModule.getModuleLoaderArgs(true);
var modalloc = allocator;
_ = modlaunch.startup_module(&modalloc, &modargs);
} else {
core.engine_logs("using hot reloading");
const platform = @import("platform").module;
platform.watchModules();
//if (comptime @hasDecl(backlog, "platform")) {
//backlog.platform.watchModules();
// }
core.loadModule(moduleName, true) catch return false;
}
// load the shared object and call startup()
// core.beginLoading("");
// if (!start_modules(spec, args, allocator)) return false;
// defer shutdown_modules(allocator);
run() catch return false;
if (core.getEngine().shutdownModuleFunction) |shutdownFunc| {
shutdownFunc();
} else {
core.shutdown_module(allocator);
}
return true;
}
pub fn main() !void {
if (!core.BuildOption("RootDeploymentOnly")) {
// if we don't see a content/ folder or a
// content.pak file in the current directory,
// walk up the directory tree until we see one, then change dirs to that before doing anything else
var iterations: u32 = 0;
var BUFFER: [8192]u8 = undefined;
while (iterations < 8) : (iterations += 1) {
if (fileExists("content") or fileExists("content.pak")) {
break;
}
var dir = try std.fs.cwd().openDir("..", .{});
defer dir.close();
core.engine_log("content not found scanning dir {s}", .{try dir.realpath(".", &BUFFER)});
try dir.setAsCwd();
}
core.engine_log("Working Dir set: {s}", .{try std.fs.cwd().realpath(".", &BUFFER)});
}
const spec = try gamespec.getSpec();
_ = startEngine(spec);
// panickers.attachSegfaultHandler();
// try realMain.main();
shutdown_hook();
}
pub fn shutdown_hook() void {
std.debug.print("[engine] shutting down now! goodbye!", .{});
}

83
engine/modulelaunch.zig Normal file
View File

@ -0,0 +1,83 @@
pub const NwArgs = struct {
useGPA: bool = false, // slower zig based memory allocator, provides detailed tracking of leaks and memory violations
vulkanValidation: bool = true,
fastTest: bool = false,
dmt: bool = false, // detailed memory tracking, implements a timeline for tracking all memory allocations
fatDump: bool = false, // takes a full fat minidump on crash, very large files are produced
};
pub fn getArgs() !NwArgs {
const a = try core.ParseArgs(NwArgs);
return a;
}
var shutdownList: std.ArrayListUnmanaged(*const fn (std.mem.Allocator) void) = .{};
var shutdownModuleNames: std.ArrayListUnmanaged([]const u8) = .{};
var gAllocator: std.mem.Allocator = undefined;
pub export fn startup_module(p_allocator: *anyopaque, p_a: ?*anyopaque) bool {
const allocator = core.modulePreamble(p_allocator, p_a) catch return false;
gAllocator = allocator;
core.engine_log("module started {s}", .{backlog.moduleName});
const spec = gamespec.getSpec() catch return false;
const args = getArgs() catch NwArgs{};
const moduleArgs = core.startup_getArgs(p_a.?);
if (moduleArgs.firstLoad) {
inline for (backlog.moduleList) |feature| {
if (@hasDecl(backlog, feature) and !std.mem.eql(u8, "core", feature)) {
const Struct = @field(backlog, feature);
if (core.isModuleEnabled(Struct.Module, spec)) {
var z1 = core.tracy.ZoneN(@src(), @ptrCast("Initializing Module"));
defer z1.End();
core.engine_logs("starting module >>>> " ++ feature ++ " <<<<");
core.tracy.Message(Struct.Module.name);
Struct.start_module(spec, args, allocator) catch @panic("start_module failed");
if (core.MemoryTracker.MTGet()) |_| {
core.MemoryTracker.MTPrintStatsDelta();
}
shutdownList.append(allocator, Struct.shutdown_module) catch return false;
shutdownModuleNames.append(allocator, feature) catch return false;
}
}
}
core.setShutdownModule(shutdown_module);
} else {
inline for (backlog.moduleList) |feature| {
if (@hasDecl(backlog, feature)) {
core.engine_log("reloading module: {s}", .{feature});
}
}
}
return true;
}
pub export fn shutdown_module() void {
var i: usize = shutdownList.items.len;
while (i > 0) {
const j = i - 1;
shutdownList.items[j](gAllocator);
i -= 1;
}
shutdownList.deinit(gAllocator);
shutdownModuleNames.deinit(gAllocator);
core.shutdown_module(gAllocator);
}
const gamespec = @import("gamespec");
const backlog = @import("backlog");
const core = backlog.core;
const std = @import("std");

View File

@ -159,8 +159,9 @@ const ENetSessionData = struct {
}
};
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn create(self: *@This(), allocator: std.mem.Allocator, first: bool) !*@This() {
if (!first)
return;
self.* = .{
.allocator = allocator,
@ -399,7 +400,6 @@ pub fn destroy(self: *@This()) void {
self.deadSessions.deinit(self.allocator);
enet_mod.deinitialize();
self.allocator.destroy(self);
}
const core = @import("core");

View File

@ -28,15 +28,14 @@ pub const NetEngine = struct {
arena: std.heap.ArenaAllocator,
transport: ?TransportRef = null,
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !*@This() {
if (!first)
return;
self.* = @This(){
.allocator = allocator,
.arena = std.heap.ArenaAllocator.init(allocator),
};
return self;
}
pub fn arenaAllocator(self: *@This()) std.mem.Allocator {

View File

@ -139,8 +139,11 @@ pub const PhysicsRuntime = struct {
try self.idToEntity.put(self.allocator, bodyId, entity);
}
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first) {
return;
}
try zphysics.init(std.heap.smp_allocator, .{});
//try zphysics.init(allocator, .{});
@ -162,11 +165,6 @@ pub const PhysicsRuntime = struct {
);
self.system = system;
//try core.defineComponent(PhysicsCharacter, self.allocator);
// try core.defineComponent(PhysicsCollider, self.allocator);
return self;
}
pub fn tick(self: *@This(), dt: f64) void {
@ -230,7 +228,6 @@ pub const PhysicsRuntime = struct {
}
pub fn deinit(self: *@This()) void {
const allocator = self.allocator;
self.system.optimizeBroadPhase();
for (PhysicsCharacter.BaseContainer.list.items) |physChar| {
physChar.deinit();
@ -266,8 +263,6 @@ pub const PhysicsRuntime = struct {
self.system.destroy();
zphysics.deinit();
allocator.destroy(self);
}
pub fn createShape(self: *@This(), name: *core.Name, settings: ShapeSettings) !void {

View File

@ -1,308 +0,0 @@
const std = @import("std");
const zphysics = @import("zphysics");
const core = @import("core");
const zm = core.zm;
pub const ObjectLayers = struct {
pub const non_moving: zphysics.ObjectLayer = 0;
pub const moving: zphysics.ObjectLayer = 1;
pub const len: u32 = 2;
};
pub const BroadPhaseLayers = struct {
pub const non_moving: zphysics.BroadPhaseLayer = 0;
pub const moving: zphysics.BroadPhaseLayer = 1;
pub const len: u32 = 2;
};
const BroadPhaseLayerInterface = extern struct {
usingnamespace zphysics.BroadPhaseLayerInterface.Methods(@This());
__v: *const zphysics.BroadPhaseLayerInterface.VTable = &vtable,
object_to_broad_phase: [ObjectLayers.len]zphysics.BroadPhaseLayer = undefined,
const vtable = zphysics.BroadPhaseLayerInterface.VTable{
.getNumBroadPhaseLayers = _getNumBroadPhaseLayers,
.getBroadPhaseLayer = _getBroadPhaseLayer,
};
fn init() BroadPhaseLayerInterface {
var layer_interface: BroadPhaseLayerInterface = .{};
layer_interface.object_to_broad_phase[ObjectLayers.non_moving] = BroadPhaseLayers.non_moving;
layer_interface.object_to_broad_phase[ObjectLayers.moving] = BroadPhaseLayers.moving;
return layer_interface;
}
fn _getNumBroadPhaseLayers(_: *const zphysics.BroadPhaseLayerInterface) callconv(.c) u32 {
return BroadPhaseLayers.len;
}
fn _getBroadPhaseLayer(
interface_self: *const zphysics.BroadPhaseLayerInterface,
object_layer: zphysics.ObjectLayer,
) callconv(.c) zphysics.BroadPhaseLayer {
const self: *const BroadPhaseLayerInterface = @ptrCast(interface_self);
return self.object_to_broad_phase[object_layer];
}
};
const ObjectVsBroadPhaseLayerFilter = extern struct {
usingnamespace zphysics.ObjectVsBroadPhaseLayerFilter.Methods(@This());
__v: *const zphysics.ObjectVsBroadPhaseLayerFilter.VTable = &vtable,
const vtable = zphysics.ObjectVsBroadPhaseLayerFilter.VTable{ .shouldCollide = _shouldCollide };
fn _shouldCollide(
_: *const zphysics.ObjectVsBroadPhaseLayerFilter,
object_layer: zphysics.ObjectLayer,
broad_phase_layer: zphysics.BroadPhaseLayer,
) callconv(.c) bool {
return switch (object_layer) {
ObjectLayers.non_moving => broad_phase_layer == BroadPhaseLayers.moving,
ObjectLayers.moving => true,
else => unreachable,
};
}
};
const ObjectLayerPairFilter = extern struct {
usingnamespace zphysics.ObjectLayerPairFilter.Methods(@This());
__v: *const zphysics.ObjectLayerPairFilter.VTable = &vtable,
const vtable = zphysics.ObjectLayerPairFilter.VTable{ .shouldCollide = _shouldCollide };
fn _shouldCollide(
_: *const zphysics.ObjectLayerPairFilter,
a: zphysics.ObjectLayer,
b: zphysics.ObjectLayer,
) callconv(.c) bool {
return switch (a) {
ObjectLayers.non_moving => b == ObjectLayers.moving,
ObjectLayers.moving => true,
else => unreachable,
};
}
};
pub const PhysicsRuntime = struct {
allocator: std.mem.Allocator,
bpli: BroadPhaseLayerInterface,
ovbplf: ObjectVsBroadPhaseLayerFilter,
olpf: ObjectLayerPairFilter,
max_bodies: u32,
system: *zphysics.PhysicsSystem = undefined,
primBoxSettings: *zphysics.BoxShapeSettings = undefined,
primBoxShape: *zphysics.Shape = undefined,
primSphereSettings: *zphysics.SphereShapeSettings = undefined,
primSphereShape: *zphysics.Shape = undefined,
floorShapeSettings: *zphysics.BoxShapeSettings = undefined,
floorShape: *zphysics.Shape = undefined,
spherePositions: std.ArrayList(core.Vectorf),
sphereRotations: std.ArrayList(core.Quat),
sphereIds: std.ArrayList(zphysics.BodyId),
newBallTime: f64 = 5,
offset: f32 = 0,
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
self.* = .{
.allocator = allocator,
.bpli = BroadPhaseLayerInterface.init(),
.ovbplf = .{},
.olpf = .{},
.spherePositions = std.ArrayList(core.Vectorf).init(allocator),
.sphereRotations = std.ArrayList(core.Quat).init(allocator),
.sphereIds = std.ArrayList(zphysics.BodyId).init(allocator),
.max_bodies = 8192,
};
const system = try zphysics.PhysicsSystem.create(
@as(*const zphysics.BroadPhaseLayerInterface, @ptrCast(&self.bpli)),
@as(*const zphysics.ObjectVsBroadPhaseLayerFilter, @ptrCast(&self.ovbplf)),
@as(*const zphysics.ObjectLayerPairFilter, @ptrCast(&self.olpf)),
.{
.max_bodies = self.max_bodies,
.num_body_mutexes = 0,
.max_body_pairs = 8192 * 2,
.max_contact_constraints = 8192 * 2,
},
);
self.system = system;
const bodyInterface = self.system.getBodyInterfaceMut();
// primBoxSettings: *zphysics.BoxShapeSettings = undefined,
// primBoxShape: *zphysics.Shape = undefined,
// primSphereSettings: *zphysics.SphereShapeSettings = undefined,
// primSphereShape: *zphysics.Shape = undefined,
// setup primitives for settings.
self.primBoxSettings = try zphysics.BoxShapeSettings.create(.{ 2.0, 2.0, 2.0 });
self.primBoxShape = try self.primBoxSettings.createShape();
self.primSphereSettings = try zphysics.SphereShapeSettings.create(0.5);
self.primSphereShape = try self.primSphereSettings.createShape();
self.floorShapeSettings = try zphysics.BoxShapeSettings.create(.{ 300, 1, 300 });
self.floorShape = try self.floorShapeSettings.createShape();
// create floor
_ = try bodyInterface.createAndAddBody(.{
.position = .{ 0, -1, 0, 1 },
.rotation = .{ 0, 0, 0, 1 },
.shape = self.floorShape,
.motion_type = .static,
.object_layer = ObjectLayers.non_moving,
}, .activate);
const roomSize = 7;
// create up and down walls
{
const rotation = zm.quatFromMat(zm.rotationZ(core.radians(90.0)));
_ = try bodyInterface.createAndAddBody(.{
.position = .{ roomSize, -1, 0, 1 },
.rotation = rotation,
.shape = self.floorShape,
.motion_type = .static,
.object_layer = ObjectLayers.non_moving,
}, .activate);
_ = try bodyInterface.createAndAddBody(.{
.position = .{ -roomSize, -1, 0, 1 },
.rotation = rotation,
.shape = self.floorShape,
.motion_type = .static,
.object_layer = ObjectLayers.non_moving,
}, .activate);
}
// create left and right walls
{
const rotation = zm.quatFromMat(zm.rotationX(core.radians(90.0)));
_ = try bodyInterface.createAndAddBody(.{
.position = .{ 0, -1, -roomSize, 1 },
.rotation = rotation,
.shape = self.floorShape,
.motion_type = .static,
.object_layer = ObjectLayers.non_moving,
}, .activate);
_ = try bodyInterface.createAndAddBody(.{
.position = .{ 0, -1, roomSize, 1 },
.rotation = rotation,
.shape = self.floorShape,
.motion_type = .static,
.object_layer = ObjectLayers.non_moving,
}, .activate);
}
for (0..2) |i| {
_ = try bodyInterface.createAndAddBody(
.{
.position = .{ 0, @as(f32, @floatFromInt(i)) * 1.1 + 1.0, 2, 1 },
.rotation = .{ 0, 0, 0, 1 },
.shape = self.primSphereShape,
.motion_type = .dynamic,
.object_layer = ObjectLayers.moving,
.restitution = 0.4,
.angular_velocity = .{ 0, 0, 0, 0 },
},
.activate,
);
_ = try bodyInterface.createAndAddBody(
.{
.position = .{ 5, @as(f32, @floatFromInt(i)) * 1.1 + 1.0, 2, 1 },
.rotation = .{ 0, 0, 0, 1 },
.shape = self.primSphereShape,
.motion_type = .dynamic,
.restitution = 0.4,
.object_layer = ObjectLayers.moving,
.angular_velocity = .{ 0, 0, 0, 0 },
},
.activate,
);
}
self.system.optimizeBroadPhase();
return self;
}
pub fn updateSpherePositions(self: *@This()) !void {
try self.system.getBodyIds(&self.sphereIds);
try self.spherePositions.resize(self.sphereIds.items.len);
try self.sphereRotations.resize(self.sphereIds.items.len);
const lockInterface = self.system.getBodyLockInterface();
for (self.sphereIds.items, 0..) |bodyId, i| {
var readLock: zphysics.BodyLockRead = .{};
readLock.lock(lockInterface, bodyId);
defer readLock.unlock();
if (readLock.body) |body| {
self.spherePositions.items[i] = core.Vectorf.fromArray(body.position);
self.sphereRotations.items[i] = body.rotation;
}
}
}
// todo... schedule physics timers
pub fn tick(self: *@This(), dt: f64) void {
self.system.update(@floatCast(dt), .{}) catch unreachable;
self.updateSpherePositions() catch unreachable;
// self.newBallTime -= dt;
// if (self.newBallTime < 0) {
// const bodyInterface = self.system.getBodyInterfaceMut();
// self.newBallTime = 5.0;
// self.offset += 0.01;
// _ = bodyInterface.createAndAddBody(
// .{
// .position = .{ 0 + self.offset, 15, 0, 1 },
// .rotation = .{ 0, 0, 0, 1 },
// .shape = self.primSphereShape,
// .motion_type = .dynamic,
// .object_layer = ObjectLayers.moving,
// .restitution = 0.4,
// .angular_velocity = .{ 0, 0, 0, 0 },
// .inertia_multiplier = 30,
// },
// .activate,
// ) catch unreachable;
// self.system.optimizeBroadPhase();
// }
}
pub fn deinit(self: *@This()) void {
const allocator = self.allocator;
self.primSphereShape.release();
self.primSphereSettings.release();
self.floorShape.release();
self.floorShapeSettings.release();
self.primBoxShape.release();
self.primBoxSettings.release();
self.system.destroy();
self.sphereIds.deinit();
self.spherePositions.deinit();
self.sphereRotations.deinit();
allocator.destroy(self);
}
};

View File

@ -1,22 +0,0 @@
const std = @import("std");
const core = @import("core");
const windowing = @import("windowing.zig");
// GameInput implements the RawInputListenerInterface
// This is a data driven input system where mappings are defined,
// and keys are assigned to mapping contexts
pub const GameInputSystem = struct {
pub const RawInputListenerVTable = windowing.RawInputListenerInterface.from(@This());
stub: u32 = 0,
pub fn OnIoEvent(self: *@This(), event: windowing.IOEvent) windowing.InputListenerError!void {
_ = event;
_ = self;
}
pub fn deinit(self: *@This()) void {
_ = self;
}
};

View File

@ -89,7 +89,7 @@ pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.me
return;
}
core.getModuleLoader().watchInitializeFn = watchModules;
// core.getModuleLoader().watchInitializeFn = watchModules;
const parameters = windowing.PlatformParams.init();

View File

@ -191,8 +191,6 @@ pub const PlatformInstance = struct {
self.allocator.free(self.iconPath);
self.processFuncs.deinit(self.allocator);
self.platformRequests.deinit(self.allocator);
self.allocator.destroy(self);
// shutdown
}
pub fn onExitSignal(self: *@This()) !void {
@ -204,10 +202,10 @@ pub const PlatformInstance = struct {
return self.windowDestroyed;
}
pub fn init(
allocator: std.mem.Allocator,
) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.allocator = allocator,
.nfdRuntime = try nfd.NFDRuntime.create(allocator, .{}),
@ -217,8 +215,6 @@ pub const PlatformInstance = struct {
//.extent = .{ .x = @floatFromInt(params.extent.x), .y = @floatFromInt(params.extent.y) },
//.hasVideo = params.hasVideo,
};
return self;
}
pub fn setParams(self: *@This(), params: PlatformParams) !void {

View File

@ -417,8 +417,10 @@ pub const AnimationSystem = struct {
}
}
pub fn init(alloc: std.mem.Allocator) !*@This() {
const self = try alloc.create(@This());
pub fn init(self: *@This(), alloc: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.backingAllocator = alloc,
.arena = std.heap.ArenaAllocator.init(alloc),
@ -433,7 +435,6 @@ pub const AnimationSystem = struct {
Animator.allocator = alloc;
core.engine_logs("Animation System initialized");
return self;
}
pub fn deinit(self: *@This()) void {
@ -466,7 +467,6 @@ pub const AnimationSystem = struct {
self.arena.deinit();
self.skeletons.deinit(self.backingAllocator);
self.animTracks.deinit(self.backingAllocator);
self.backingAllocator.destroy(self);
}
};

View File

@ -19,19 +19,14 @@ pub const AnimationLoader = struct {
self.sys.newAnimTrack(assetRef.name, animation) catch return error.UnableToLoad;
}
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.sys = animation_system.gAnimationSys,
.allocator = allocator,
};
return self;
}
pub fn destroy(self: *@This()) void {
self.allocator.destroy(self);
}
};
@ -56,19 +51,14 @@ pub const SkeletonLoader = struct {
self.sys.newSkeleton(assetRef.name, sk) catch return error.UnableToLoad;
}
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.sys = animation_system.gAnimationSys,
.allocator = allocator,
};
return self;
}
pub fn destroy(self: *@This()) void {
self.allocator.destroy(self);
}
};

View File

@ -410,8 +410,9 @@ pub const ParticleSystem = struct {
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "rend.ParticleSystem");
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.particleArena = std.heap.ArenaAllocator.init(allocator),
@ -420,8 +421,6 @@ pub const ParticleSystem = struct {
ParticleRandRangef.randomEngine = std.Random.DefaultPrng.init(0x1234);
ParticleRandRangef.randomFunc = ParticleRandRangef.randomEngine.random();
return self;
}
pub fn tick(self: *@This(), dt: f64) void {
@ -437,7 +436,6 @@ pub const ParticleSystem = struct {
pub fn destroy(self: *@This()) void {
self.particleArena.deinit();
self.allocator.destroy(self);
}
};

View File

@ -35,8 +35,10 @@ const assetReferences = [_]assets.AssetImportReference{
),
};
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.debugDraws = try core.RingQueueU(DebugPrimitive).init(allocator, MaxObjectCount),
.allocator = allocator,
@ -50,8 +52,6 @@ pub fn create(allocator: std.mem.Allocator) !*@This() {
try assets.loadList(assetReferences);
gDebugDrawSys = self;
return self;
}
pub fn updateMeshes(self: *@This()) void {
@ -243,7 +243,6 @@ pub fn setup(self: *@This(), device: *gpu.GPUDevice) !void {
pub fn destroy(self: *@This()) void {
self.debugDraws.deinit(self.allocator);
self.drawsThisFrame.deinit(self.allocator);
self.allocator.destroy(self);
}
// ==================== Primitives ===================

View File

@ -5,23 +5,19 @@ allocator: std.mem.Allocator,
pub var LoaderInterfaceVTable = assets.AssetLoaderInterface.from("Mesh", @This());
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "rend.MeshAssetLoader");
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.allocator = allocator,
};
return self;
}
pub fn discardAll(self: *@This()) void {
_ = self;
}
pub fn destroy(self: *@This()) void {
self.allocator.destroy(self);
}
// unfortunately this one is blocking
pub fn loadAsset(self: *@This(), assetRef: assets.AssetRef, propertiesBag: ?assets.AssetPropertiesBag) assets.AssetLoaderError!void {
_ = self;

View File

@ -15,8 +15,10 @@ const SgpuParticleRenderInfo = struct {
texture: *rend.Texture,
};
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.allocator = allocator,
};
@ -39,8 +41,6 @@ pub fn create(allocator: std.mem.Allocator) !*@This() {
.size = MaxParticleCount * @sizeOf(meshes_vert.Scene),
.props = 0,
});
return self;
}
pub fn uploadSsbos(self: *@This(), copyPass: *gpu.GPUCopyPass) !void {
@ -121,10 +121,9 @@ pub fn setup(self: *@This(), device: *gpu.GPUDevice) !void {
_ = device;
}
pub fn destroy(self: *@This()) void {
pub fn deinit(self: *@This()) void {
self.spans.deinit(self.allocator);
self.renderInfo.deinit(self.allocator);
self.allocator.destroy(self);
}
const assets = @import("assets");

View File

@ -16,11 +16,11 @@ brightnessFactor: f32 = 4.0,
sampler: *gpu.GPUSampler = undefined,
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
self.* = .{ .allocator = allocator };
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
return self;
self.* = .{ .allocator = allocator };
}
pub fn setup(self: *@This(), device: *gpu.GPUDevice) !void {
@ -87,10 +87,6 @@ fn createPipeline(self: *@This()) !void {
}));
}
pub fn destroy(self: *@This()) void {
self.allocator.destroy(self);
}
pub fn render(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
const targetInfo: [2]gpu.GPUColorTargetInfo = .{
std.mem.zeroInit(gpu.GPUColorTargetInfo, .{

View File

@ -9,19 +9,19 @@
pub var LoaderInterfaceVTable = assets.AssetLoaderInterface.from("Texture", @This());
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "rend.TextureList");
allocator: std.mem.Allocator,
allocator: std.mem.Allocator = undefined,
device: *gpu.GPUDevice = undefined,
map: std.AutoHashMapUnmanaged(u32, *Texture) = .{},
requestMap: std.AutoHashMapUnmanaged(u32, bool) = .{},
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.allocator = allocator,
};
return self;
}
pub fn setup(self: *@This(), device: *gpu.GPUDevice) !void {
@ -339,14 +339,13 @@ pub fn discardAll(self: *@This()) void {
_ = self;
}
pub fn destroy(self: *@This()) void {
pub fn deinit(self: *@This()) void {
var iter = self.map.valueIterator();
while (iter.next()) |x| {
self.allocator.destroy(x.*);
}
self.requestMap.deinit(self.allocator);
self.map.deinit(self.allocator);
self.allocator.destroy(self);
}
const std = @import("std");

View File

@ -99,15 +99,14 @@ pub const Renderer = struct {
pub const MaxObjectCount = 50000;
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.allocator = allocator,
};
self.hdrTextureFormat = .textureformatR16g16b16a16Float;
return self;
}
pub fn imageExtents(self: @This()) core.Vectorf {
@ -1178,7 +1177,6 @@ pub const Renderer = struct {
self.uploads.deinit(self.allocator);
self.destroys.deinit(self.allocator);
self.allocator.destroy(self);
}
};

View File

@ -21,14 +21,13 @@ enable: bool = true,
// float bias; // = 0.025;
// int numSamples; // up to 64
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
if (!first)
return;
self.* = .{
.allocator = allocator,
};
return self;
}
pub fn setup(self: *@This(), device: *gpu.GPUDevice) !void {
@ -216,10 +215,6 @@ pub fn createPipeline(self: *@This()) !void {
self.ssaoPipeline = ctx.device.createGPUGraphicsPipeline(&pci);
}
pub fn destroy(self: *@This()) void {
self.allocator.destroy(self);
}
const core = @import("core");
const rend = @import("../rend.zig");
const std = @import("std");

9
engine/trampoline.zig Normal file
View File

@ -0,0 +1,9 @@
const core = @import("core");
const modules = @import("modtree");
pub fn launch() void {}
pub fn shutdown() void {}
pub fn loadModule() void {}

11
lib/.claude/settings.local.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"permissions": {
"allow": [
"Bash(cat:*)",
"Bash(git log:*)",
"Bash(zig build:*)"
],
"deny": [],
"ask": []
}
}

17
lib/bh/build.zig vendored
View File

@ -48,6 +48,23 @@ pub fn MakeModlib(b: *std.Build, o: ModLibOptions) ModLib {
};
}
pub const Options = struct {
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
static_build: bool,
tracy: bool,
};
// standard set of options that all backlog modules and dependenices shall use.
pub fn declareOptions(b: *std.Build) Options {
return .{
.target = b.standardTargetOptions(.{}),
.optimize = b.standardOptimizeOption(.{}),
.static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false,
.tracy = b.option(bool, "tracy", "builds with tracy support") orelse false,
};
}
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

20
lib/cimgui/build.zig vendored
View File

@ -1,15 +1,13 @@
const std = @import("std");
const bh = @import("bh");
// very tiny, not intended to build anything just to run tests linked with libc
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
_ = static_build;
const opts = bh.declareOptions(b);
const mod = b.addModule("cimgui", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.link_libc = true,
.root_source_file = b.path("src/cimgui.zig"),
});
@ -22,14 +20,14 @@ pub fn build(b: *std.Build) void {
const cimgui = b.addLibrary(.{
.name = "cimgui",
.root_module = b.createModule(.{
.optimize = optimize,
.target = target,
.optimize = opts.optimize,
.target = opts.target,
}),
});
cimgui.linkLibC();
if (target.result.abi != .msvc)
if (opts.target.result.abi != .msvc)
cimgui.linkLibCpp();
cimgui.addIncludePath(b.path("cimgui"));
@ -71,8 +69,8 @@ pub fn build(b: *std.Build) void {
const test_step = b.step("test", "run unit tests for imgui");
const tests = b.addTest(.{
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("tests/tests.zig"),
}),
});

28
lib/enet/build.zig vendored
View File

@ -1,10 +1,8 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
_ = static_build;
const opts = bh.declareOptions(b);
// am i good to always have enet as static?
// const enet = if (true) b.addStaticLibrary(.{
@ -21,8 +19,8 @@ pub fn build(b: *std.Build) void {
.name = "enet_c",
.linkage = .static,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
}),
});
@ -47,7 +45,7 @@ pub fn build(b: *std.Build) void {
enet.addIncludePath(b.path("enet-1.3.18/include"));
// Platform-specific configuration
switch (target.result.os.tag) {
switch (opts.target.result.os.tag) {
.windows => {
enet.linkSystemLibrary("ws2_32");
enet.linkSystemLibrary("winmm");
@ -62,8 +60,8 @@ pub fn build(b: *std.Build) void {
b.installArtifact(enet);
const mod = b.addModule("enet", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/enet.zig"),
.link_libc = true,
});
@ -75,8 +73,8 @@ pub fn build(b: *std.Build) void {
const tests = b.addTest(.{
.root_module = b.createModule(.{
.link_libc = true,
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/tests.zig"),
}),
});
@ -91,8 +89,8 @@ pub fn build(b: *std.Build) void {
.name = "test-server",
.root_module = b.createModule(.{
.root_source_file = b.path("src/test_server.zig"),
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
}),
});
test_server.root_module.addImport("enet", mod);
@ -103,8 +101,8 @@ pub fn build(b: *std.Build) void {
.name = "test-client",
.root_module = b.createModule(.{
.root_source_file = b.path("src/test_client.zig"),
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
}),
});
test_client.root_module.addImport("enet", mod);

23
lib/lua/build.zig vendored
View File

@ -1,23 +1,22 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const opts = bh.declareOptions(b);
const mod = b.addModule("lua", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/lua.zig"),
.link_libc = true,
});
const luac = b.addLibrary(.{
.name = "luac",
.linkage = if (static_build) .static else .dynamic,
.linkage = if (opts.static_build) .static else .dynamic,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.link_libc = true,
}),
});
@ -64,9 +63,9 @@ pub fn build(b: *std.Build) void {
luac.addCSourceFile(.{ .file = b.path("src/limited_io.c") });
if (target.result.os.tag == .windows) {
if (opts.target.result.os.tag == .windows) {
luac.addCSourceFile(.{ .file = b.path("src/minidumpsetup.cpp") });
if (target.result.abi != .msvc)
if (opts.target.result.abi != .msvc)
luac.linkLibCpp();
luac.linkLibC();
} else {
@ -85,8 +84,8 @@ pub fn build(b: *std.Build) void {
const tests = b.addExecutable(.{
.name = "run-lua",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("test/test-lua.zig"),
.link_libc = true,
}),

View File

@ -1,16 +1,15 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const opts = bh.declareOptions(b);
const miniaudio_c = b.addLibrary(.{
.name = "miniaudio_c",
.linkage = if (static_build) .static else .dynamic,
.linkage = if (opts.static_build) .static else .dynamic,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.link_libc = true,
}),
});
@ -19,7 +18,7 @@ pub fn build(b: *std.Build) void {
miniaudio_c.addCSourceFile(.{ .file = b.path("src/miniaudio.cpp"), .flags = &.{"-fno-sanitize=all"}, .language = .c });
miniaudio_c.addIncludePath(b.path("include"));
const mod = b.addModule("miniaudio", .{ .target = target, .optimize = optimize, .root_source_file = b.path("src/miniaudio.zig") });
const mod = b.addModule("miniaudio", .{ .target = opts.target, .optimize = opts.optimize, .root_source_file = b.path("src/miniaudio.zig") });
mod.linkLibrary(miniaudio_c);
mod.addIncludePath(b.path("./include"));
@ -28,8 +27,8 @@ pub fn build(b: *std.Build) void {
const test_step = b.step("test", "");
const tests = b.addTest(.{
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/miniaudio-test.zig"),
.link_libc = true,
}),

21
lib/nfd/build.zig vendored
View File

@ -1,13 +1,12 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const opts = bh.declareOptions(b);
const mod = b.addModule("nfd", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/nfd.zig"),
.link_libc = true,
});
@ -19,19 +18,19 @@ pub fn build(b: *std.Build) void {
mod.addIncludePath(b.path("include"));
if (target.result.os.tag == .macos) {
if (opts.target.result.os.tag == .macos) {
mod.addCSourceFile(.{
.file = b.path("src/nfd_cocoa.m"),
.flags = &.{},
});
mod.linkFramework("AppKit", .{});
} else if (target.result.os.tag == .windows) {
} else if (opts.target.result.os.tag == .windows) {
mod.addCSourceFile(.{
.file = b.path("src/nfd_win.cpp"),
.flags = &.{},
});
mod.linkSystemLibrary("ole32", .{});
} else if (target.result.os.tag == .linux) {
} else if (opts.target.result.os.tag == .linux) {
// mod.addCSourceFile(.{
// .file = b.path("src/nfd_gtk.c"),
// .flags = &.{},
@ -47,7 +46,7 @@ pub fn build(b: *std.Build) void {
// mod.linkSystemLibrary("gobject-2.0", .{});
}
const p2dep = b.dependency("p2", .{ .target = target, .optimize = optimize, .static_build = static_build });
const p2dep = b.dependency("p2", .{ .target = opts.target, .optimize = opts.optimize, .static_build = opts.static_build });
const p2mod = p2dep.module("p2");
mod.addImport("p2", p2mod);
@ -55,8 +54,8 @@ pub fn build(b: *std.Build) void {
const test_step = b.step("test", "");
const tests = b.addTest(.{
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/nfd.zig"),
.link_libc = true,
}),

View File

@ -1,22 +1,20 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
_ = static_build;
const opts = bh.declareOptions(b);
const mod = b.addModule("objLoader", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/obj_loader.zig"),
});
const test_step = b.step("test", "");
const tests = b.addTest(.{
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/obj_loader.zig"),
.link_libc = true,
}),

17
lib/ozz/build.zig vendored
View File

@ -21,6 +21,7 @@
// ozz_animation_offline_fbx -- fbx importing, requires linking wiht fbx sdk... maybe i dont want this... fuck adobe
const std = @import("std");
const bh = @import("bh");
const Build = std.Build;
const LazyPath = LazyPath;
@ -142,16 +143,14 @@ pub const GltfToOzz = struct {
};
pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const target = b.standardTargetOptions(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const opts = bh.declareOptions(b);
const ozz_cpp = b.addLibrary(.{
.linkage = if (static_build) .static else .dynamic,
.linkage = if (opts.static_build) .static else .dynamic,
.name = "ozz_cpp",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
}),
});
@ -161,7 +160,7 @@ pub fn build(b: *std.Build) void {
ozz_cpp.addIncludePath(b.path("ozz-animation/src"));
ozz_cpp.linkLibC();
if (target.result.abi != .msvc)
if (opts.target.result.abi != .msvc)
ozz_cpp.linkLibCpp();
const src_dir = "ozz-animation/src/";
@ -208,8 +207,8 @@ pub fn build(b: *std.Build) void {
.name = "ozz-tests",
.root_module = b.createModule(.{
.root_source_file = b.path("tests/test.zig"),
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
}),
});
b.installArtifact(tests);

14
lib/p2/build.zig vendored
View File

@ -1,22 +1,20 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse true;
_ = static_build;
const opts = bh.declareOptions(b);
const mod = b.addModule("p2", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/p2.zig"),
});
const test_step = b.step("test", "test p2");
const tests = b.addTest(.{
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/p2.zig"),
}),
// .link_libc = true,

View File

@ -42,6 +42,8 @@ pub fn SparseMultiSetAdvanced(comptime T: type, comptime SparseSize: u32) type {
return struct {
pub const SetType = std.MultiArrayList(T);
pub const InnerType = T;
allocator: std.mem.Allocator,
denseIndices: ArrayListUnmanaged(SetHandle),
dense: SetType,
@ -311,6 +313,7 @@ pub fn SparseSetAdvanced(comptime T: type, comptime SparseSize: u32) type {
opCount: u32 = 0,
pub const StableReferences = false;
pub const InnerType = T;
pub fn getStateCount(self: @This()) u32 {
return self.opCount;
@ -596,6 +599,7 @@ pub fn SparseMap(comptime T: type) type {
containerListener: ?ContainerListener = null,
opCount: u32 = 0,
pub const InnerType = T;
pub const StableReferences = true;
pub fn create(backingAllocator: std.mem.Allocator) !*@This() {
@ -720,6 +724,7 @@ const interface = @import("interface.zig");
pub const EcsContainerInterface = interface.MakeInterface("EcsContainerInterfaceVTable", struct {
containerTypeName: []const u8,
componentName: []const u8,
handleExists: *const fn (*const anyopaque, SetHandle) bool,
get: *const fn (*const anyopaque, SetHandle) ?*anyopaque,
createWithHandle: *const fn (*anyopaque, SetHandle) *anyopaque,
@ -787,6 +792,7 @@ pub const EcsContainerInterface = interface.MakeInterface("EcsContainerInterface
return .{
.containerTypeName = TargetType.ContainerTypeName,
.componentName = @typeName(TargetType.InnerType),
.handleExists = Wrap.handleExists,
.get = Wrap.get,
.createWithHandle = Wrap.createWithHandle,

View File

@ -17,7 +17,7 @@ const std = @import("std");
// main purpose of this string-pool is to provide an RC-ableinterface for interface
// with GC'ed systems such as lua
var gStringContext: *StringContext = undefined;
pub var gStringContext: *StringContext = undefined;
pub const String = struct {
index: u24,

16
lib/packer/build.zig vendored
View File

@ -1,16 +1,14 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const opts = bh.declareOptions(b);
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const p2dep = b.dependency("p2", .{ .target = target, .optimize = optimize, .static_build = static_build });
const p2dep = b.dependency("p2", .{ .target = opts.target, .optimize = opts.optimize, .static_build = opts.static_build });
const mod = b.addModule("packer", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/packer.zig"),
});
@ -19,8 +17,8 @@ pub fn build(b: *std.Build) void {
const test_exe = b.addTest(.{
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("tests/test.zig"),
}),
});

View File

@ -174,6 +174,7 @@ pub const PackerFS = struct {
}
for (self.anyWatchCallbacks.items) |*watch| {
// std.debug.print("anywatch callback: {s}\n", .{watch.path});
watch.call(std.mem.span(path));
}
}
@ -341,6 +342,8 @@ pub const PackerFS = struct {
}
pub fn installFileBytesMount(self: *@This(), path: []const u8, fileBytes: []align(8) u8, embedded: bool) !?PackerBytesMapping {
// std.debug.print("mounting file path {s}\n", .{path});
const pakMountIndex = self.pakMountings.items.len;
try self.pakMountings.append(self.allocator, .{
.filePath = try self.stringAlloc().dupe(u8, path),

38
lib/sdl3/build.zig vendored
View File

@ -1,4 +1,5 @@
const std = @import("std");
const bh = @import("bh");
pub fn addShaderDefinition(
b: *std.Build,
@ -48,38 +49,35 @@ pub fn shaderDefintion(
}
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const opts = bh.declareOptions(b);
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const preferred_linkage: std.builtin.LinkMode = if (static_build) .static else .dynamic;
const preferred_linkage: std.builtin.LinkMode = if (opts.static_build) .static else .dynamic;
const sdl_dep = b.dependency("sdl", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.preferred_linkage = preferred_linkage,
});
const sdl3_lib = sdl_dep.artifact("SDL3");
const sdl3_fwd = b.addModule("SDL3", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/sdl3_lib_fwd.zig"),
});
sdl3_fwd.linkLibrary(sdl3_lib);
const mod = b.addModule("sdl3", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/sdl3.zig"),
});
const shaderTypes = b.dependency("shaderTypes", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
});
mod.addImport("shaderTypes", shaderTypes.module("shaderTypes"));
@ -90,8 +88,8 @@ pub fn build(b: *std.Build) void {
const tests2 = b.addExecutable(.{
.name = "hello-sdl",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/samples/compiletest.zig"),
.link_libc = true,
}),
@ -101,8 +99,8 @@ pub fn build(b: *std.Build) void {
const tests = b.addExecutable(.{
.name = "hello-triangle",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/samples/hello-triangle.zig"),
.link_libc = true,
}),
@ -112,8 +110,8 @@ pub fn build(b: *std.Build) void {
const hello_window_exe = b.addExecutable(.{
.name = "hello-window",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/samples/hello-window.zig"),
.link_libc = true,
}),
@ -124,7 +122,7 @@ pub fn build(b: *std.Build) void {
tests.root_module.addImport("sdl3", mod);
const vertexDefinitions = addShaderDefinition(b, ".", target, optimize, "hello-triangle.vert", b.path("content/hello-triangle.vert.json"));
const vertexDefinitions = addShaderDefinition(b, ".", opts.target, opts.optimize, "hello-triangle.vert", b.path("content/hello-triangle.vert.json"));
tests.root_module.addImport("hello-triangle.vert", vertexDefinitions);
const runArtifact = b.addRunArtifact(tests);

8033
lib/sdl3/gpu.ast.json vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
{
"functions": {}
}

View File

@ -1,15 +1,12 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
_ = static_build;
const opts = bh.declareOptions(b);
const mod = b.addModule("shaderTypes", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("shaderTypes.zig"),
});

View File

@ -1,7 +1,9 @@
.{
.name = .shaderTypes,
.version = "0.0.0",
.dependencies = .{},
.dependencies = .{
.bh = .{ .path = "../../bh" },
},
.paths = .{
"",
},

View File

@ -1,15 +1,15 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const opts = bh.declareOptions(b);
const exe = b.addExecutable(.{
.name = "spvReflect2",
.root_module = b.createModule(.{
.root_source_file = b.path("spvReflect2.zig"),
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
}),
});

11
lib/sdl3/spvreflect/build.zig.zon vendored Normal file
View File

@ -0,0 +1,11 @@
.{
.name = .spvreflect,
.version = "0.0.0",
.dependencies = .{
.bh = .{ .path = "../../bh" },
},
.paths = .{
"",
},
.fingerprint = 0x77801c18119671a4,
}

20
lib/spng/build.zig vendored
View File

@ -1,17 +1,15 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const opts = bh.declareOptions(b);
const spng_c = b.addLibrary(.{
.linkage = if (static_build) .static else .dynamic,
.linkage = if (opts.static_build) .static else .dynamic,
.name = "spng_c",
.root_module = b.createModule(.{
.optimize = optimize,
.target = target,
.optimize = opts.optimize,
.target = opts.target,
.link_libc = true,
}),
});
@ -24,8 +22,8 @@ pub fn build(b: *std.Build) void {
spng_c.root_module.addCMacro("SPNG_USE_MINIZ", "1");
const mod = b.addModule("spng", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/spng.zig"),
});
@ -38,8 +36,8 @@ pub fn build(b: *std.Build) void {
const test_step = b.step("test", "run unit tests for spng");
const tests = b.addTest(.{
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/spng.zig"),
.link_libc = true,
}),

View File

@ -1,22 +1,22 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const opts = bh.declareOptions(b);
const theorafile = b.addModule(
"theorafile",
.{
.optimize = optimize,
.target = target,
.optimize = opts.optimize,
.target = opts.target,
.root_source_file = b.path("theorafile.zig"),
.link_libc = true,
},
);
const sdl_dep = b.dependency("sdl", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
});
const sdl_lib = sdl_dep.artifact("SDL3");
@ -99,8 +99,8 @@ pub fn build(b: *std.Build) void {
const tests = b.addExecutable(.{
.name = "test",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.link_libc = true,
.root_source_file = b.path("sdl3test/sdl3test.zig"),
}),

22
lib/tracy/build.zig vendored
View File

@ -1,13 +1,11 @@
const std = @import("std");
const bh = @import("bh");
const tracy_path = "tracy-0.10/public";
const tracy_path_include = tracy_path ++ "/tracy";
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
_ = static_build;
const opts = bh.declareOptions(b);
//const tracy_enabled = b.option(bool, "tracy", "Enables tracy integration") orelse false;
@ -18,8 +16,8 @@ pub fn build(b: *std.Build) void {
// std.debug.print("tracy enabled {s}\n", .{if (tracy_enabled) "true" else "false"});
const mod = b.addModule("tracy", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("tracy.zig"),
.link_libc = tracy_enabled,
.link_libcpp = tracy_enabled,
@ -39,7 +37,7 @@ pub fn build(b: *std.Build) void {
},
});
if (target.result.os.tag == .windows) {
if (opts.target.result.os.tag == .windows) {
mod.linkSystemLibrary("Advapi32", .{});
mod.linkSystemLibrary("User32", .{});
mod.linkSystemLibrary("Ws2_32", .{});
@ -47,16 +45,16 @@ pub fn build(b: *std.Build) void {
}
}
const opts = b.addOptions();
opts.addOption(bool, "tracy_enabled", tracy_enabled);
mod.addOptions("build_options", opts);
const build_opts = b.addOptions();
build_opts.addOption(bool, "tracy_enabled", tracy_enabled);
mod.addOptions("build_options", build_opts);
// ========== tests =============
const test_step = b.step("test", "run unit tests for tracy");
const tests = b.addTest(.{
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("tracy_test.zig"),
}),
});

17
lib/watcher/build.zig vendored
View File

@ -1,15 +1,12 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
_ = static_build;
const opts = bh.declareOptions(b);
const mod = b.addModule("watcher", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("src/watcher.zig"),
.link_libc = true,
.link_libcpp = true,
@ -17,7 +14,7 @@ pub fn build(b: *std.Build) void {
mod.addCSourceFile(.{ .file = b.path("src/watcher.cpp") });
if (target.result.os.tag == .macos) {
if (opts.target.result.os.tag == .macos) {
mod.linkFramework("CoreFoundation", .{});
mod.linkFramework("CoreServices", .{});
}
@ -26,8 +23,8 @@ pub fn build(b: *std.Build) void {
const test_exe = b.addTest(.{
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("tests/test.zig"),
}),
});

11
lib/zgltf/build.zig vendored
View File

@ -1,16 +1,13 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
_ = static_build;
const opts = bh.declareOptions(b);
const mod = b.addModule("zgltf", .{
.root_source_file = b.path("src/zgltf.zig"),
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
});
const tests = b.addTest(.{

14
lib/zmath/build.zig vendored
View File

@ -1,22 +1,20 @@
const std = @import("std");
const bh = @import("bh");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
_ = static_build;
const opts = bh.declareOptions(b);
const mod = b.addModule("zmath", .{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("zmath.zig"),
});
const test_step = b.step("test", "runs tests for zmath");
const tests = b.addTest(.{
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
.root_source_file = b.path("zmath.zig"),
.link_libc = true,
}),

View File

@ -1,4 +1,5 @@
const std = @import("std");
const bh = @import("bh");
fn addMacros(module: *std.Build.Module, options: anytype) void {
if (options.enable_cross_platform_determinism)
@ -12,8 +13,7 @@ fn addMacros(module: *std.Build.Module, options: anytype) void {
}
pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const target = b.standardTargetOptions(.{});
const opts = bh.declareOptions(b);
const options = .{
.use_double_precision = b.option(
@ -25,7 +25,7 @@ pub fn build(b: *std.Build) void {
bool,
"enable_asserts",
"Enable assertions",
) orelse (optimize == .Debug),
) orelse (opts.optimize == .Debug),
.enable_cross_platform_determinism = b.option(
bool,
"enable_cross_platform_determinism",
@ -48,8 +48,6 @@ pub fn build(b: *std.Build) void {
) orelse true,
};
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse true;
const user_extensions = b.option(
[]const std.Build.LazyPath,
"user_extensions",
@ -73,14 +71,14 @@ pub fn build(b: *std.Build) void {
const joltc = b.addLibrary(.{
.name = "joltc",
.linkage = if (!static_build) .dynamic else .static,
.linkage = if (!opts.static_build) .dynamic else .static,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
}),
});
if (!static_build and target.result.os.tag == .windows)
if (!opts.static_build and opts.target.result.os.tag == .windows)
joltc.root_module.addCMacro("JPC_API", "extern __declspec(dllexport)");
b.installArtifact(joltc);
@ -88,7 +86,7 @@ pub fn build(b: *std.Build) void {
joltc.addIncludePath(b.path("libs"));
joltc.addIncludePath(b.path("libs/JoltC"));
joltc.linkLibC();
if (target.result.abi != .msvc) {
if (opts.target.result.abi != .msvc) {
joltc.linkLibCpp();
} else {
joltc.linkSystemLibrary("advapi32");
@ -257,14 +255,14 @@ pub fn build(b: *std.Build) void {
.name = "zphysics-tests",
.root_module = b.createModule(.{
.root_source_file = b.path("src/zphysics.zig"),
.target = target,
.optimize = optimize,
.target = opts.target,
.optimize = opts.optimize,
}),
});
b.installArtifact(tests);
// TODO: Problems with LTO on Windows.
if (target.result.os.tag == .windows) {
if (opts.target.result.os.tag == .windows) {
tests.want_lto = false;
}

Some files were not shown because too many files have changed in this diff Show More