// main public facing root file for core const std = @import("std"); pub const gameObjectList = @import("utils/gameObjectList.zig"); pub const GameObjectList = gameObjectList.GameObjectList; pub const GameObjectInterface = gameObjectList.GameObjectInterface; pub const GameObjectData = gameObjectList.GameObjectData; pub const inputs = @import("inputs/inputStack.zig"); pub const getInputStack = inputs.getInputStack; pub const ActionEvent = inputs.ActionEvent; pub const Axis1dBinding = inputs.Axis1dBinding; pub const Axis2dBinding = inputs.Axis2dBinding; pub const ActionBinding = inputs.ActionBinding; pub const IOEvent = inputs.IOEvent; pub const debug_draw = @import("debug_draw.zig"); pub const debugTextLog = debug_draw.debugTextLog; pub const DebugDrawParams = debug_draw.DebugDrawParams; pub const DebugDrawInterface = debug_draw.DebugDrawInterface; pub const installDebugDrawInterface = debug_draw.installDebugDrawInterface; pub const debugSphere = debug_draw.debugSphere; pub const debugSphereTransform = debug_draw.debugSphereTransform; pub const debugBox = debug_draw.debugBox; pub const debugLine = debug_draw.debugLine; // pub const script_bindings = script.script_bindings; pub const misc = @import("misc.zig"); pub const engineTime = @import("engineTime.zig"); pub const engineObject = @import("engineObject.zig"); pub const EngineObjectVTable = engineObject.EngineObjectVTable; pub const MakeTypeName = engineObject.MakeTypeName; pub const PatchStruct = engineObject.PatchStruct; pub const InterfaceRef = engineObject.InterfaceRef; pub const updateEngineVTable = engineObject.updateEngineVTable; pub const EngineDataEventError = engineObject.EngineDataEventError; pub const EngineObjectDelegate = engineObject.EngineObjectDelegate; pub const FieldInfo = engineObject.FieldInfo; pub const jobs = @import("jobs.zig"); pub const JobContext = jobs.JobContext; pub const JobManager = jobs.JobManager; pub const JobWorker = jobs.JobWorker; pub const file_utils = @import("file_utils.zig"); pub const string_utils = @import("string_utils.zig"); pub const type_utils = @import("type_utils.zig"); pub const engine = @import("engine.zig"); pub const tracy = @import("tracy").t; pub const png = @import("png.zig"); pub const colors = @import("colors.zig"); pub const zgltf = @import("zgltf"); pub const zm = @import("zmath"); pub const p2 = @import("p2"); pub const assert = p2.assert; pub const asserts = p2.asserts; pub const assertf = p2.assertf; pub const stringStrip = p2.stringStrip; pub const MakeInterface = p2.MakeInterface; pub const Reference = p2.Reference; pub const names = p2.names; pub const BumpArena = p2.BumpArena; pub const ObjectHandle = p2.ObjectHandle; pub const RingQueue = p2.RingQueue; pub const RingQueueU = p2.RingQueueU; pub const ConcurrentQueueU = p2.ConcurrentQueueU; pub const Name = p2.Name; pub const StaticVector = p2.StaticVector; pub const SparseSet = p2.SparseSet; pub const SparseMap = p2.SparseMap; pub const SparseMultiSet = p2.SparseMultiSet; pub const SparseSetAdvanced = p2.SparseSetAdvanced; pub const SparseMultiSetAdvanced = p2.SparseMultiSetAdvanced; pub const SetHandle = p2.SetHandle; pub const EcsContainerInterface = p2.EcsContainerInterface; pub const IndexPoolHandle = p2.IndexPoolHandle; pub const PagedVector = p2.PagedVector; pub const IndexPool = p2.IndexPool; pub const MakeName = p2.MakeName; pub const DefineName = p2.DefineName; pub const createNameRegistry = p2.createNameRegistry; pub const destroyNameRegistry = p2.destroyNameRegistry; pub const setNameRegistry = p2.setNameRegistry; pub const NameRegistry = p2.NameRegistry; pub const NameInvalid = p2.NameInvalid; pub const getFileExtension = p2.getFileExtension; pub const getBasePath = p2.getBasePath; pub const getDir = p2.getDir; pub const getFolder = p2.getFolder; pub const MergedSpans = p2.MergedSpans; pub const Span = p2.Span; pub const shell = p2.shell; pub const algorithm = @import("p2"); pub const math = @import("math.zig"); pub const Rayf = math.Rayf; pub const f32x4 = math.f32x4; // __m128_int pub const f32x8 = math.f32x8; // __m256_int pub const f32x16 = math.f32x16; // __m512_int pub const f32x4_zero = math.f32x4_zero; pub const f32x8_zero = math.f32x8_zero; pub const f32x16_zero = math.f32x16_zero; // pub const radians = math.radians; pub const Mat = math.Mat; pub const Transform = math.Transform; pub const Quat = math.Quat; pub const Vector2i = math.Vector2i; pub const Vectorf = math.Vectorf; pub const Vector = math.Vector; pub const Vector4 = math.Vector4; pub const Vector4f = math.Vector4f; pub const Vector2 = math.Vector2; pub const Vector2c = math.Vector2c; pub const Vector2u = math.Vector2u; pub const Vector2f = math.Vector2f; pub const Rotation = math.Rotation; pub const launchArgs = @import("args.zig"); pub const ParseArgs = launchArgs.ParseArgs; pub const panickers = @import("panickers.zig"); pub const scene = @import("scene.zig"); pub const ScenePosRot = scene.ScenePosRot; pub const SceneSystem = scene.SceneSystem; pub const Engine = engine.Engine; pub const spng = @import("spng"); pub const MemoryTracker = @import("MemoryTracker.zig"); pub const DefaultSavePath = "Saved"; pub const logging = @import("logging.zig"); pub const logDisplay = logging.logDisplay; pub const LoggerSys = logging.LoggerSys; const c = @This(); pub const getLogger = logging.getLogger; pub const console_log = logging.console_log; pub const console_logs = logging.console_logs; pub const engine_logs = logging.engine_logs; pub const engine_log = logging.engine_log; pub const graphics_logs = logging.graphics_logs; pub const graphics_log = logging.graphics_log; pub const engine_err = logging.engine_err; pub const engine_errs = logging.engine_errs; pub const printInner = logging.printInner; pub const errorHighlight = logging.errorHighlight; pub const defaultHighlight = logging.defaultHighlight; pub const packer = @import("packer"); pub const FileSystem = packer.PackerFS; pub const PackerFS = packer.PackerFS; pub const StackCompactor = stacks.StackCompactor; var staticsInitialized = false; var gEngine: *Engine = undefined; var gPackerFS: *PackerFS = undefined; var fsInitialized: bool = false; pub fn EngineObject(comptime T: type) type { return struct { pub var gInstance: ?*T = null; pub fn get() *T { if (gInstance == null) { gInstance = getEngineObject(T); } return gInstance.?; } }; } pub fn getModuleLoader() *ModuleLoader { return EngineObject(ModuleLoader).get(); } var gIsUtility: bool = false; pub const Scene = scene.Scene; pub const externModule = @import("extern/externModule.zig"); pub const ModuleLoader = externModule.ModuleLoader; pub const ModuleLoaderArgs = externModule.ModuleLoaderArgs; pub const ecs = @import("ecs.zig"); pub const defineComponentList = ecs.defineComponentList; pub const undefineComponentList = ecs.undefineComponentList; pub const Entity = ecs.Entity; pub const createEntity = ecs.createEntity; // pub const script = @import("script.zig"); pub const stacks = @import("stacks.zig"); pub const walkAndPrintStack = stacks.walkAndPrintStack; pub const gameObject = @import("gameObject.zig"); pub const SpawnParameters = gameObject.SpawnParameters; pub const GameObject = gameObject.GameObject; pub const GameObjectSystem = gameObject.GameObjectSystem; pub const MessageInfo = gameObject.MessageInfo; pub fn registerObject(comptime T: type, name: []const u8) !void { try get(GameObjectSystem).registerObject(name, T); } pub fn registerObjectAdvanced(comptime T: type, name: []const u8, comptime funcName: []const u8) !void { try get(GameObjectSystem).registerObjectAdvanced(name, T, funcName); } pub fn fs() *PackerFS { return gPackerFS; } pub const Module = ModuleDescription{ .name = "core", .enabledByDefault = true, }; pub fn isUtility() bool { return gIsUtility; } pub fn checkArgBool(args: anytype, comptime field: []const u8) bool { if (@hasField(@TypeOf(args), "fatDump")) { return @field(args, field); } return false; } pub fn getSessionStamp() i64 { return gEngine.sessionStamp; } // a struct can be used like a list of types in this way pub const ComponentList = struct { pub const Scene = scene.Scene; pub const GameObject = gameObject.GameObject; }; pub const ModuleStartupError = error{StartupFailed}; pub fn start_module(map: *SpecVariantMap, args: anytype, allocator: std.mem.Allocator) ModuleStartupError!void { start_module_(map, args, allocator) catch return error.StartupFailed; } pub fn maybeInitPackerFs(allocator: std.mem.Allocator) !void { if (fsInitialized == false) { gPackerFS = try PackerFS.init(allocator, .{}); fsInitialized = true; } } 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"); gIsUtility = true; } } var fatDump: bool = false; if (checkArgBool(args, "fatDump")) { fatDump = true; } // script.lua.setupMiniDump(fatDump); _ = try algorithm.createNameRegistry(allocator); // LUA BEGIN -- what if i want to make the scripting integration optional? // try script.start_lua(allocator); // LUA END try maybeInitPackerFs(allocator); // load configs. //const name = if (@hasField(@TypeOf(programSpec), "configName")) programSpec.configName else programSpec.name; var name = map.get("name").?.string; if (map.get("configName")) |x| { name = x.string; } gEngine = try allocator.create(Engine); gEngine.* = try Engine.init(allocator); _ = try createObject(ModuleLoader, .{}); try console.start(); const engineName = try std.fmt.allocPrint(allocator, "{s}Engine.ini", .{name}); defer allocator.free(engineName); try configVars.setupConfigs(engineName); if (@hasField(@TypeOf(args), "unitTest") and args.unitTest) {} else { try logging.setupLogging(gEngine); } try ecs.setup(allocator); _ = try gEngine.createObject(scene.SceneSystem, .{ .can_tick = true }); try algorithm.string_pool.setup(allocator); // _ = try gEngine.createObject(script_bindings.ScriptTicks, .{ .can_tick = true }); _ = try createObject(GameObjectSystem, .{ .can_tick = true }); _ = try inputs.initInputStack(); // components define try ecs.defineComponentList(ComponentList, allocator); return; } pub fn setupFromModule(__args: ModuleLoaderArgs) !void { gEngine = __args.engine; gPackerFS = __args.packerFS; // script.setupLuaFromModule(__args.luaState, __args.luaAllocator); algorithm.names.gRegistry = __args.nameRegistry; logging.setupLoggingFromModule(); staticsInitialized = true; // walk through and patch all ecs containers ecs.patchComponentList(ComponentList); debug_draw.gDebugDrawInterface = __args.debugDrawInterface; if (getEngineObject(SceneSystem)) |system| { scene.Scene.SceneObjectContainer = system.sceneObjectContainer; } } pub fn shutdown_module(_: std.mem.Allocator) void { MemoryTracker.MTPrintStatsDelta(); ecs.undefineComponentList(ComponentList); logging.shutdownLogging(); debug_draw.shutdownDrawInterface(); ecs.shutdown(); algorithm.destroyNameRegistry(); gEngine.deinit(); gPackerFS.destroy(); // LUA BEGIN // script.shutdown_lua(); // LUA END console.shutdown(); algorithm.string_pool.shutdown(); return; } pub fn dispatchJob(capture: anytype) !void { try gEngine.jobManager.newJob(capture); } pub fn createObject(comptime T: type, params: engine.NeonObjectParams) !*T { return gEngine.createObject(T, params); } pub fn createObjectVTable(vtable: *engineObject.EngineObjectVTable, params: engine.NeonObjectParams) !*anyopaque { return gEngine.createObjectVTable(vtable, params); } pub fn registerRendererSetup(ctx: *anyopaque, setup: engine.SetupFuncFn) void { gEngine.rendererCtx = ctx; gEngine.rendererSetupFunc = setup; } pub fn setupEnginePlatform(ctx: *anyopaque, poll: engine.PollFuncFn, proc: engine.ProcEventsFn) void { gEngine.platformCtx = ctx; gEngine.platformPollFunc = poll; gEngine.platformProcEventsFunc = proc; } pub fn exitNow() void { signalShutdown(); } pub fn signalShutdown() void { // destroy all ecs entities first ecs.destroyAllEntities(); gEngine.exit(); } pub fn getEngine() *Engine { return gEngine; } pub fn BuildOption(comptime option: []const u8) bool { if (@hasDecl(@import("root"), "options")) { const r = @import("root").options; if (@hasDecl(r, option)) { return @field(r, option); } else { return false; } } return false; } const EngineDelegates = @import("EngineDelegates.zig"); // binds a function + a context to pub fn addEngineDelegateBinding(comptime event: []const u8, func: anytype, ctx: *anyopaque) !usize { if (!@hasField(EngineDelegates, event)) { @compileError("Engine does not have delegate " ++ event); } const handle = @field(gEngine.delegates, event).items.len; try @field(gEngine.delegates, event).append(gEngine.delegates.allocator, .{ .func = func, .ctx = ctx }); return handle; } pub const getEngineTime = @import("engineTime.zig").getEngineTime; pub fn getEngineUptime() f64 { return getEngineTime() - gEngine.engineStartTime; } pub const modules = @import("modules.zig"); pub const isModuleEnabled = modules.isModuleEnabled; pub const ModuleDescription = modules.ModuleDescription; pub const console = @import("console.zig"); pub const configVars = @import("configVars.zig"); pub const loopDelay = engine.loopDelay; pub const getConfigVar = configVars.getConfigVar; pub const configVar = configVars.configVar; pub const SpecVariantMap = std.StringHashMap(SpecVariant); pub const SpecVariant = union(enum(u8)) { boolean: bool, string: []const u8, }; pub fn createSpecVariant(comptime spec: anytype, allocator: std.mem.Allocator) !SpecVariantMap { var variantMap = std.StringHashMap(SpecVariant).init(allocator); inline for (@typeInfo(@TypeOf(spec)).@"struct".fields) |s| { switch (@typeInfo(s.type)) { .pointer => { try variantMap.put(s.name, .{ .string = @field(spec, s.name) }); }, .bool => { try variantMap.put(s.name, .{ .boolean = @field(spec, s.name) }); }, else => {}, } } return variantMap; } pub const EngineObjectRef = engineObject.EngineObjectRef; pub fn getEngineObjectRef(comptime T: type) ?engineObject.EngineObjectRef { if (T.NeonObjectTable.singletonName) |name| { if (getEngine().engineObjectsByName.get(name)) |ref| { return ref; } } return null; } pub fn getEngineObject(comptime T: type) ?*T { if (T.NeonObjectTable.singletonName) |name| { if (getEngine().engineObjectsByName.get(name)) |ref| { return @ptrCast(@alignCast(ref.ptr)); } } return null; } pub fn get(comptime T: type) *T { return EngineObject(T).get(); } pub fn loadModule(moduleName: []const u8, watch: bool) !void { if (watch == false) unreachable; // not implemented try getModuleLoader().addModule(moduleName); } pub fn startup_getAllocator(p_allocator: *anyopaque) std.mem.Allocator { return @as(*std.mem.Allocator, @ptrCast(@alignCast(p_allocator))).*; } pub fn startup_getArgs(p_allocator: *anyopaque) ModuleLoaderArgs { return @as(*ModuleLoaderArgs, @ptrCast(@alignCast(p_allocator))).*; } 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); return allocator; } // a wrapper around a struct // which adds slack up to a specific size // // engine objects must be allocated with this if they support hot patching // // if pub const Slack is a decl in the struct- EngineObjectVTable will generate with a // fields remapping list. pub fn SlackStruct(comptime T: type, comptime SlackSize: usize) type { return struct { inner: T, slack: [SlackSize - @sizeOf(T)]u8 = undefined, pub fn create(allocator: std.mem.Allocator) !*T { return (try allocator.create(@This())).getInner(); } pub fn getInner(self: *@This()) *T { return &self.inner; } pub fn fromPtr(inner: *T) *@This() { const p: *anyopaque = inner; return @as(*@This(), @ptrCast(@alignCast(p))); } }; } pub fn cast(comptime T: type, p: *anyopaque) T { return @ptrCast(@alignCast(p)); } pub fn MakeNameFmt(comptime fmt: []const u8, args: anytype) Name { var makeNameBuf: [256]u8 = undefined; return algorithm.MakeName(std.fmt.bufPrint(&makeNameBuf, fmt, args) catch unreachable); } pub fn PatchOrCreateObject(comptime T: type, args: engine.NeonObjectParams) void { if (getEngineObject(T) != null) { engineObject.updateEngineVTable(T); return; } logging.engine_log("spawning object {s}", .{T.NeonObjectTable.typeName}); _ = createObject(T, args) catch { logging.engine_err("Unable to create object", .{}); }; } pub const u32a = std.atomic.Value(u32); pub const i32a = std.atomic.Value(u32); var gBarrierCount: u32a = u32a.init(0); pub fn setBarrierCount(count: u32) void { gBarrierCount.store(count, .seq_cst); } pub fn getBarrierCount() u32 { return gBarrierCount.load(.acquire); } pub fn jobCount() u32 { return getEngine().jobManager.numWorkers; } pub fn waitSeconds(wait: f64) void { const start = getEngineTime(); while (getEngineTime() - start < wait) { std.Thread.sleep(10_000_000); } } pub fn itof32(i: anytype) f32 { return @as(f32, @floatFromInt(i)); } pub fn itof64(i: anytype) f32 { return @as(f32, @floatFromInt(i)); }