diff --git a/engine/core/src/engine.zig b/engine/core/src/engine.zig index ac0e15f..1b3e667 100644 --- a/engine/core/src/engine.zig +++ b/engine/core/src/engine.zig @@ -166,13 +166,18 @@ pub const Engine = struct { try self.destroyListSimple.append(self.allocator, newObjectRef); } - if (params.can_tick) { - if (!@hasDecl(T, "tick")) { - return error.RequestedTickNotAvailable; // tried to register a tickable for an object which does not implement tick + if (params.can_tick) |t| { + if (t and !@hasDecl(T, "tick")) { + return error.RequestedTickNotAvailable; } - // register to tick table - try self.tickables.append(self.allocator, newIndex); + if (t) { + try self.tickables.append(self.allocator, newIndex); + } + } else { + if (@hasDecl(T, "tick")) { + try self.tickables.append(self.allocator, newIndex); + } } if (@hasDecl(T, "engineDraw")) { @@ -379,7 +384,7 @@ pub const Engine = struct { }; pub const NeonObjectParams = struct { - can_tick: bool = false, + can_tick: ?bool = null, responds_to_events: bool = false, isCore: bool = false, }; diff --git a/engine/core/src/scene.zig b/engine/core/src/scene.zig index 6f5b0e5..96bece4 100644 --- a/engine/core/src/scene.zig +++ b/engine/core/src/scene.zig @@ -135,7 +135,6 @@ pub const Scene = struct { pub fn setPosition(self: @This(), position: core.Vectorf) void { if (SceneObjectContainer.get(self.handle, .posRot)) |posRot| { posRot.*.position = position; - // core.engine_log("setposition scucess handle.index = 0x{x}", .{self.handle.index}); } else { core.engine_log("setposition failed handle.index = 0x{x} generation = {d} alive={any}", .{ self.handle.index, self.handle.generation, self.handle.alive }); } diff --git a/engine/rend/shaders/meshes.vert.hlsl b/engine/rend/shaders/meshes.vert.hlsl index b07b386..850f667 100644 --- a/engine/rend/shaders/meshes.vert.hlsl +++ b/engine/rend/shaders/meshes.vert.hlsl @@ -37,8 +37,8 @@ Output main(Input input) float4 pos = float4(input.Position, 1.0); - pos.x += 0.2 * sin(time * 0.5 ) * pos.y * 0.5; - pos.y += 0.2 * cos(time * 0.5 ) * pos.z * 0.5; + // pos.x += 0.2 * sin(time * 0.5 ) * pos.y * 0.5; + // pos.y += 0.2 * cos(time * 0.5 ) * pos.z * 0.5; output.Position = mul(ViewProjection, mul(scene[input.Instance].Model, pos)); diff --git a/engine/rend/shaders/meshes.vert.json b/engine/rend/shaders/meshes.vert.json index 553384c..279e031 100644 --- a/engine/rend/shaders/meshes.vert.json +++ b/engine/rend/shaders/meshes.vert.json @@ -6,7 +6,7 @@ } ], "types" : { - "_9" : { + "_8" : { "name" : "Scene", "members" : [ { @@ -18,12 +18,12 @@ } ] }, - "_8" : { + "_7" : { "name" : "type.StructuredBuffer.Scene", "members" : [ { "name" : "_m0", - "type" : "_9", + "type" : "_8", "array" : [ 0 ], @@ -35,7 +35,7 @@ } ] }, - "_11" : { + "_10" : { "name" : "type.Uniforms", "members" : [ { @@ -74,7 +74,7 @@ ], "ssbos" : [ { - "type" : "_8", + "type" : "_7", "name" : "scene", "readonly" : true, "block_size" : 0, @@ -84,7 +84,7 @@ ], "ubos" : [ { - "type" : "_11", + "type" : "_10", "name" : "type.Uniforms", "block_size" : 68, "set" : 1, diff --git a/engine/rend/src/rend.zig b/engine/rend/src/rend.zig index a385351..4118561 100644 --- a/engine/rend/src/rend.zig +++ b/engine/rend/src/rend.zig @@ -30,6 +30,9 @@ pub const setActiveCamera = renderer.setActiveCamera; pub const createRendererObject = renderer.createRendererObject; pub const registerRendererObject = renderer.registerRendererObject; +pub const getTexture = renderer.getTexture; +pub const texture = @import("texture/texture.zig"); + var rendAllocator: std.mem.Allocator = undefined; pub fn getAllocator() std.mem.Allocator { return rendAllocator; diff --git a/engine/rend/src/sgpu/TextureList.zig b/engine/rend/src/sgpu/TextureList.zig new file mode 100644 index 0000000..559fb09 --- /dev/null +++ b/engine/rend/src/sgpu/TextureList.zig @@ -0,0 +1,128 @@ +// not to be confused with a real texture pool +// but this texture list is just a container where all +// textures are installed into the renderer +// +// this thing also servers as both the asset loader +// as well as the engine interface +// + +pub var LoaderInterfaceVTable = assets.AssetLoaderInterface.from("Texture", @This()); +pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); + +allocator: std.mem.Allocator, +device: *gpu.GPUDevice = undefined, + +map: std.AutoHashMapUnmanaged(u32, *Texture) = .{}, + +pub fn create(allocator: std.mem.Allocator) !*@This() { + const self = try allocator.create(@This()); + self.* = .{ + .allocator = allocator, + }; + + return self; +} + +pub fn setup(self: *@This(), device: *gpu.GPUDevice) !void { + core.engine_log("Texture List Added", .{}); + try assets.gAssetSys.registerLoader(self); + self.device = device; +} + +pub fn loadAsset(self: *@This(), assetRef: assets.AssetRef, propertiesBag: ?assets.AssetPropertiesBag) assets.AssetLoaderError!void { + var name = assetRef.name; + core.engine_log("loading texture {s}", .{name.utf8()}); + if (propertiesBag) |bag| { + const installed = self.uploadTextureFromPath(name, bag.path) catch return error.UnableToLoad; + self.map.put(self.allocator, name.handle(), installed) catch return error.UnableToLoad; + } +} + +pub fn uploadTextureFromPath(self: *@This(), name: core.Name, path: []const u8) !*Texture { + var png = try core.png.PngContents.initFromFS(core.fs(), self.allocator, path); + defer png.deinit(); + + const cmd = self.device.acquireGPUCommandBuffer(); + + const gpuTexture = self.device.createGPUTexture(&std.mem.zeroInit(gpu.GPUTextureCreateInfo, .{ + .type = .texturetype2d, + .format = .textureformatR8g8b8a8UnormSrgb, + .usage = .{ .textureusageSampler = true }, + .width = png.size.x, + .height = png.size.y, + .layer_count_or_depth = 1, + .num_levels = 1, + })); + + const transferBuffer = self.device.createGPUTransferBuffer(&.{ + .usage = .transferbufferusageUpload, + .size = png.size.x * png.size.y * @sizeOf(u32), + .props = 0, + }); + + { + const data: [*]u8 = @ptrCast(self.device.mapGPUTransferBuffer(transferBuffer, false)); + for (png.pixels, 0..) |pixel, i| { + data[i] = pixel; + } + } + + self.device.unmapGPUTransferBuffer(transferBuffer); + + const copyPass = cmd.beginGPUCopyPass(); + // copyPass.uploadToGPUTexture(source: [*c]const GPUTextureTransferInfo, destination: [*c]const GPUTextureRegion, cycle: bool) + copyPass.uploadToGPUTexture( + &.{ + .transfer_buffer = transferBuffer, + .offset = 0, + .pixels_per_row = png.size.x, + .rows_per_layer = png.size.y, + }, + &std.mem.zeroInit(gpu.GPUTextureRegion, .{ + .texture = gpuTexture, + .w = png.size.x, + .h = png.size.y, + .d = 1, + }), + false, + ); + + copyPass.endGPUCopyPass(); + if (!cmd.submitGPUCommandBuffer()) { + return error.CopyFailed; + } + self.device.releaseGPUTransferBuffer(transferBuffer); + + const tex = try self.allocator.create(Texture); + tex.* = .{ + .texture = gpuTexture, + .id = 0, + .format = .f32_rgba, + .usage = .{}, + .size = png.size, + .name = name, + }; + return tex; +} + +pub fn discardAll(self: *@This()) void { + _ = self; +} + +pub fn destroy(self: *@This()) void { + var iter = self.map.valueIterator(); + while (iter.next()) |x| { + self.allocator.destroy(x.*); + } + self.map.deinit(self.allocator); + self.allocator.destroy(self); +} + +const std = @import("std"); +const core = @import("core"); +const rend = @import("../rend.zig"); +const texture = rend.texture; +const Texture = texture.Texture; +const sdl3 = @import("sdl3"); +const gpu = sdl3.gpu; +const assets = @import("assets"); diff --git a/engine/rend/src/sgpu/mesh-pool.zig b/engine/rend/src/sgpu/mesh-pool.zig index bf90cec..26c219b 100644 --- a/engine/rend/src/sgpu/mesh-pool.zig +++ b/engine/rend/src/sgpu/mesh-pool.zig @@ -68,10 +68,12 @@ pub const MeshPool = struct { while (self.meshUpdates.popFromUnlocked()) |u| { switch (u) { .new => |new| { + var name = new.name; + core.engine_log("uploading mesh => {s}", .{name.utf8()}); + const indexSpan = try self.addTransfer(copyPass, self.indexBuffer, u32, &self.indexSpans, new.indices); const vertexSpan = try self.addTransfer(copyPass, self.vertexBuffer, meshes.MeshVertex, &self.vertexSpans, new.vertices); - var name = new.name; core.graphics_log("uploading {d} vertices and {d} indices", .{ vertexSpan.size, indexSpan.size }); core.engine_log("install mesh by name {d}", .{name.handle()}); @@ -79,7 +81,7 @@ pub const MeshPool = struct { .vertex = vertexSpan, .index = indexSpan, .name = new.name, - .jointRemap = null, // joint remaps... parse the installed skeletal meshes to generate this remap + .jointRemap = null, // joint remaps... TODO parse the installed skeletal meshes to generate this remap }); }, .free => |free| { @@ -118,17 +120,19 @@ pub const MeshPool = struct { var mappedSlice: []T = undefined; mappedSlice.ptr = @ptrCast(@alignCast(self.device.mapGPUTransferBuffer(upload, false))); - defer self.device.unmapGPUTransferBuffer(upload); mappedSlice.len = uploadSlice.len; std.mem.copyForwards(T, mappedSlice, uploadSlice); + self.device.unmapGPUTransferBuffer(upload); //copyPass.uploadToGPUBuffer(source: [*c]const GPUTransferBufferLocation, destination: [*c]const GPUBufferRegion, cycle: bool) copyPass.uploadToGPUBuffer( &.{ .transfer_buffer = upload, .offset = 0 }, - &.{ .buffer = destBuffer, .offset = newSpan.start, .size = newSpan.size * @sizeOf(T) }, + &.{ .buffer = destBuffer, .offset = newSpan.start * @sizeOf(T), .size = newSpan.size * @sizeOf(T) }, false, ); + core.engine_log("uploading {s} buffer span {d}[{d}] ({d} bytes)", .{ @typeName(T), newSpan.start, newSpan.size, newSpan.size * @sizeOf(T) }); + return newSpan; } diff --git a/engine/rend/src/sgpu/renderer.zig b/engine/rend/src/sgpu/renderer.zig index 08b824d..f7a8ed7 100644 --- a/engine/rend/src/sgpu/renderer.zig +++ b/engine/rend/src/sgpu/renderer.zig @@ -37,6 +37,8 @@ pub const Renderer = struct { depthTexture: *gpu.GPUTexture = undefined, + textureList: *TextureList = undefined, + // transients DO NOT TOUCH swapchainTexture: *gpu.GPUTexture = undefined, @@ -57,8 +59,6 @@ pub const Renderer = struct { return self; } - // pub fn createRendererObjectArgs(self: *@This(), T: type) !*T { - // registers a pre-existing render object, does not add to destroys pub fn registerRendererObject(self: *@This(), T: type, object: *anyopaque) !void { if (@hasDecl(T, "onUpload")) { @@ -78,6 +78,13 @@ pub const Renderer = struct { } } + pub fn createRendererEngineObject(self: *@This(), T: type) !*T { + const object = try core.createObject(T, .{}); + try object.setup(self.device); + + return object; + } + pub fn createRendererObject(self: *@This(), T: type) !*T { const object = try T.create(self.device, self.allocator, .{}); @@ -123,6 +130,7 @@ pub const Renderer = struct { try self.createDepthTexture(); self.meshPool = try self.createRendererObject(MeshPool); + self.textureList = try self.createRendererEngineObject(TextureList); } pub fn discoverFormats(self: *@This()) !void { @@ -473,6 +481,8 @@ const ShaderLoadArgs = sdl3.shaderTypes.ShaderLoadArgs; pub const mesh_pool = @import("mesh-pool.zig"); pub const MeshPool = mesh_pool.MeshPool; +pub const TextureList = @import("TextureList.zig"); + // debug api pub fn reloadShaders() !void { @@ -515,3 +525,5 @@ pub const getMesh = mesh_pool.getMesh; pub const getMeshByName = mesh_pool.getMeshByName; pub const pushMeshUpdate = mesh_pool.pushMeshUpdate; + +pub const GPUTextureType = gpu.GPUTexture; diff --git a/engine/rend/src/texture/texture.zig b/engine/rend/src/texture/texture.zig new file mode 100644 index 0000000..07b7e37 --- /dev/null +++ b/engine/rend/src/texture/texture.zig @@ -0,0 +1,22 @@ +pub const TextureFormat = enum(u8) { + f32_rgba, + u8_rgba, +}; +pub const TextureUsage = struct { + mesh: bool = false, +}; + +// handle to a texture resource in the engine. +pub const Texture = struct { + id: u32 = 0, // 0 is unknown texture. + format: TextureFormat = .f32_rgba, // format of the texture + usage: TextureUsage = .{}, + size: core.Vector2u, + name: core.Name, + texture: *GPUTextureType, +}; + +const core = @import("core"); +const rend = @import("../rend.zig"); +const renderer = rend.renderer; +const GPUTextureType = renderer.GPUTextureType; diff --git a/projects/content/_shaders/dxil/meshes.vert.dxil b/projects/content/_shaders/dxil/meshes.vert.dxil index baf4ad6..f401411 100644 Binary files a/projects/content/_shaders/dxil/meshes.vert.dxil and b/projects/content/_shaders/dxil/meshes.vert.dxil differ diff --git a/projects/content/_shaders/msl/meshes.vert.msl b/projects/content/_shaders/msl/meshes.vert.msl index 9d5d848..88a175b 100644 --- a/projects/content/_shaders/msl/meshes.vert.msl +++ b/projects/content/_shaders/msl/meshes.vert.msl @@ -34,12 +34,8 @@ struct main0_in vertex main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], const device type_StructuredBuffer_Scene& scene [[buffer(1)]], uint gl_InstanceIndex [[instance_id]]) { main0_out out = {}; - float4 _44 = float4(in.in_var_TEXCOORD0, 1.0); - float _47 = Uniforms.time * 0.5; - _44.x = in.in_var_TEXCOORD0.x + (((0.20000000298023223876953125 * sin(_47)) * in.in_var_TEXCOORD0.y) * 0.5); - _44.y = in.in_var_TEXCOORD0.y + (((0.20000000298023223876953125 * cos(_47)) * in.in_var_TEXCOORD0.z) * 0.5); out.out_var_TEXCOORD0 = in.in_var_TEXCOORD3; - out.gl_Position = Uniforms.ViewProjection * (scene._m0[gl_InstanceIndex].Model * _44); + out.gl_Position = Uniforms.ViewProjection * (scene._m0[gl_InstanceIndex].Model * float4(in.in_var_TEXCOORD0, 1.0)); return out; } diff --git a/projects/content/_shaders/spv/meshes.vert.spv b/projects/content/_shaders/spv/meshes.vert.spv index 9bac178..2290eda 100644 Binary files a/projects/content/_shaders/spv/meshes.vert.spv and b/projects/content/_shaders/spv/meshes.vert.spv differ diff --git a/projects/sampleGame/main.zig b/projects/sampleGame/main.zig index 673d976..6542cd7 100644 --- a/projects/sampleGame/main.zig +++ b/projects/sampleGame/main.zig @@ -25,11 +25,16 @@ const assetReferences = [_]assets.AssetImportReference{ "m_empire", .{ .path = "meshes/lost_empire.obj" }, ), - // assets.MakeImportRefOptions( - // "Mesh", - // "m_fox", - // .{ .path = "gltf-samples/Fox/glTF/Fox.gltf" }, - // ), + assets.MakeImportRefOptions( + "Mesh", + "m_fox", + .{ .path = "gltf-samples/Fox/glTF/Fox.gltf" }, + ), + assets.MakeImportRefOptions( + "Texture", + "t_empire", + .{ .path = "textures/texture_sample.png" }, + ), }; pub fn prepare(self: *@This()) !void { @@ -59,6 +64,15 @@ pub fn prepare(self: *@This()) !void { empireMesh.setMesh("m_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"); + } + rend.setActiveCamera(camera); self.moveInput = try core.Axis2dBinding.create(core.MakeName("movement"));