allocator: std.mem.Allocator, camera: core.Entity = undefined, cameraComponent: *rend.CameraComponent = undefined, cameraSpeed: f32 = 10.0, moveInput: *core.Axis2dBinding = undefined, moveVector: core.Vectorf = .{}, mouseMove: core.Vector2f = .{}, rotateAxis: f32 = 0.0, rotateAxisPitch: f32 = 0.0, sensitivity: f32 = 5.0, verticalMove: f32 = 0.0, centerDist: f32 = 2.0, centerDistMove: f32 = 2.0, yaw: f32 = 0.0, pitch: f32 = 0.0, mouseLook: bool = true, 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, }; return self; } const assetReferences = [_]assets.AssetImportReference{ assets.MakeImportRefOptions( "Mesh", "m_empire", .{ .path = "meshes/lost_empire.obj" }, ), assets.MakeImportRefOptions( "Mesh", "m_skybox", .{ .path = "meshes/skybox.obj" }, ), assets.MakeImportRefOptions( "Mesh", "m_fox", .{ .path = "gltf-samples/Fox/glTF/Fox.gltf" }, ), assets.MakeImportRefOptions( "Texture", "t_fox", .{ .path = "gltf-samples/Fox/glTF/Texture.png" }, ), assets.MakeImportRefOptions( "Texture", "t_empire", .{ .path = "textures/lost_empire-RGBA.png" }, ), }; pub fn prepare(self: *@This()) !void { core.engine_log(">>>>>>> game prepare", .{}); var z = core.tracy.ZoneN(@src(), "PREPARING GAME"); defer z.End(); try core.fs().addContentPath("sampleGame"); try script.loadTypes("scripts"); try script.runScriptFile("scripts/prepare.lua"); try assets.loadList(assetReferences); const exitInput = try core.ActionBinding.create(core.MakeName("exit")); exitInput.addKey(.escape, .keyDown); _ = exitInput.data.addListener(null, onExit); exitInput.activate(); { const inp = try core.ActionBinding.create(core.MakeName("slow")); inp.addKey(.lshift, .keyDown); inp.addKey(.lshift, .keyUp); _ = inp.data.addListener(self, slowDown); inp.activate(); } self.camera = try core.createEntity(); const cameraScene = self.camera.addComponent(core.Scene).?; cameraScene.setPosition(.{ .z = -15 }); self.cameraComponent = self.camera.addComponent(rend.CameraComponent).?; { const lostEmpire = try core.createEntity(); const scene = lostEmpire.addComponent(core.Scene).?; scene.setPosition(.{ .y = -20 }); const empireMesh = lostEmpire.addComponent(rend.MeshComponent).?; empireMesh.setMesh("m_empire"); empireMesh.setTexture("t_empire"); } { const fox = try core.createEntity(); const scene = fox.addComponent(core.Scene).?; _ = scene; // scene.setScale(); const mesh = fox.addComponent(rend.MeshComponent).?; mesh.setMesh("m_fox"); mesh.setTexture("t_fox"); } { const lightbox = try core.createEntity(); const scene = lightbox.addComponent(core.Scene).?; scene.setPosition(.{ .y = 2 }); scene.setScale(0.1, 0.1, 0.1); const mesh = lightbox.addComponent(rend.MeshComponent).?; mesh.setMesh("m_default_cube"); mesh.setTexture("t_default"); } rend.setActiveCamera(self.cameraComponent); self.moveInput = try core.Axis2dBinding.create(core.MakeName("movement")); self.moveInput.addKey(.w, 1.0, .y); self.moveInput.addKey(.s, -1.0, .y); self.moveInput.addKey(.d, 1.0, .x); self.moveInput.addKey(.a, -1.0, .x); _ = self.moveInput.data.addListener(self, onMove); self.moveInput.activate(); { const i = try core.Axis1dBinding.create(core.MakeName("rotPitch")); i.addKey(.f, 1.0); i.addKey(.v, -1.0); _ = i.data.addListener(self, distanceMove); i.activate(); } { const verticalInput = try core.Axis1dBinding.create(core.MakeName("movementVertical")); verticalInput.addKey(.e, 1.0); verticalInput.addKey(.q, -1.0); _ = verticalInput.data.addListener(self, verticalMovement); verticalInput.activate(); } { const mouseLook = try core.Axis2dBinding.create(core.MakeName("mouseLook")); mouseLook.enableMouseRelative(); _ = mouseLook.data.addListener(self, onMouseLook); mouseLook.activate(); } { const shaderReload = try core.ActionBinding.create(core.MakeName("shaderReload")); shaderReload.addKey(.r, .keyDown); _ = shaderReload.data.addListener(self, onShaderReload); shaderReload.activate(); } { const input = try core.ActionBinding.create(core.MakeName("toggleMouseLook")); input.addKey(.t, .keyDown); _ = input.data.addListener(self, toggleMouseLook); input.activate(); } self.updateMouseLook(); } fn onMouseLook(ctx: ?*anyopaque, axis: core.Vector2f) void { const self: *@This() = @ptrCast(@alignCast(ctx)); if (self.mouseLook) self.mouseMove = axis; } fn toggleMouseLook(ctx: ?*anyopaque, action: core.ActionEvent) void { const self: *@This() = @ptrCast(@alignCast(ctx)); _ = action; self.mouseLook = !self.mouseLook; self.updateMouseLook(); } fn updateMouseLook(self: *@This()) void { platform.setMouseRelativeMode(self.mouseLook); platform.setImguiVisible(!self.mouseLook); } fn onShaderReload(ctx: ?*anyopaque, action: core.ActionEvent) void { _ = ctx; _ = action; core.engine_log("reloading shaders, this is gonna cause some leaks but thats ok", .{}); rend.renderer.reloadShaders() catch unreachable; } fn slowDown(ctx: ?*anyopaque, action: core.ActionEvent) void { const self: *@This() = @ptrCast(@alignCast(ctx)); if (action == .keyUp) { self.cameraSpeed = 10.0; } if (action == .keyDown) { self.cameraSpeed = 4.0; } } fn distanceMove(ctx: ?*anyopaque, axis: f32) void { const self: *@This() = @ptrCast(@alignCast(ctx)); self.centerDistMove = axis; } fn cameraRotate(ctx: ?*anyopaque, axis: f32) void { const self: *@This() = @ptrCast(@alignCast(ctx)); self.rotateAxis = axis; } fn verticalMovement(ctx: ?*anyopaque, axis: f32) void { const self: *@This() = @ptrCast(@alignCast(ctx)); self.verticalMove = axis; } fn onMove(ctx: ?*anyopaque, axis: core.Vector2f) void { const self: *@This() = @ptrCast(@alignCast(ctx)); self.moveVector = .{ .x = axis.x, .z = axis.y, .y = 0.0 }; } pub fn onExit(ctx: ?*anyopaque, action: core.ActionEvent) void { _ = ctx; _ = action; core.exitNow(); } pub fn getMouseMovement(self: *@This()) core.Vector2f { const rv = self.mouseMove; self.mouseMove = .{}; return rv; } pub fn tick(self: *@This(), dt: f64) void { const fdt: f32 = @floatCast(dt); if (self.camera.fetch(core.Scene)) |scene| { const vector = core.Vectorf{ .x = self.moveVector.x, .z = self.moveVector.z, .y = self.verticalMove }; const posRot = scene.getPosRot(); self.yaw += self.rotateAxis * fdt * 20; self.pitch += self.rotateAxisPitch * fdt * 20; const mouseMovement = self.getMouseMovement(); self.yaw += core.radians(mouseMovement.x * self.sensitivity); self.pitch -= core.radians(mouseMovement.y * self.sensitivity); self.pitch = std.math.clamp(self.pitch, -90.0, 90.0); self.cameraComponent.pitch = core.radians(self.pitch); posRot.rotation = core.Rotation.eulerY(core.radians(self.yaw)); const movement = posRot.rotation.rotateVector(vector.fmul(self.cameraSpeed * fdt)); posRot.position = posRot.position.add(movement); self.cameraComponent.resolve(); self.centerDist += self.centerDistMove * fdt; const forward = self.cameraComponent.forward(); //posRot.rotation.forward(); const debugCenter = posRot.position.add(forward.fmul(self.centerDist)); core.debugSphere(debugCenter, 0.3, .{}); core.debugSphere(debugCenter, 0.1, .{ .color = .{ .x = 1.0 } }); rend.context().lightPosition = debugCenter; } var show: bool = true; ig.showDemoWindow(&show); } pub fn deinit(self: *@This()) void { self.allocator.destroy(self); } pub fn main() anyerror!void { try backlog.initializeAndRunStandardProgram(@This(), .{ .name = "SampleGame", .enabledModules = .{ .imgui = true, .physics = true, }, }); } const std = @import("std"); const backlog = @import("Backlog"); const assets = backlog.assets; const platform = backlog.platform; const core = backlog.core; const ig = backlog.imgui.api; const rend = backlog.rend; const script = core.script;