Backlog/engine/core/src/core.zig

611 lines
18 KiB
Zig

// 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));
}