> texture asset loader implemented

This commit is contained in:
Peter Li 2025-04-20 15:57:08 -07:00
parent ac2c9c0613
commit 2ec0cd8c31
13 changed files with 214 additions and 31 deletions

View File

@ -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,
};

View File

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

View File

@ -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));

View File

@ -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,

View File

@ -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;

View File

@ -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");

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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"));