From d33d6b24542ecaaf2528a8469e4fb5487d258fea Mon Sep 17 00:00:00 2001 From: sergeypdev Date: Tue, 27 Feb 2024 00:01:58 +0400 Subject: [PATCH] Load gltf with embedded albedo, metallic and roughness maps --- .gitattributes | 2 + assets/amd_ryzen_9.glb | 3 + assets/shaders/mesh.glsl | 4 +- build.zig.zon | 6 +- src/AssetManager.zig | 45 ++++++++ src/assets/root.zig | 1 + src/formats.zig | 17 ++++ src/game.zig | 37 +++---- src/gen/asset_manifest.zig | 1 + src/globals.zig | 2 +- tools/asset_compiler.zig | 204 +++++++++++++++++++++++++++++++------ tools/types.zig | 3 + 12 files changed, 269 insertions(+), 56 deletions(-) create mode 100644 assets/amd_ryzen_9.glb diff --git a/.gitattributes b/.gitattributes index 9f59d5b..b12b069 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,6 +2,8 @@ * text=auto eol=lf # Git LFS hooks, add large file types to track here. +*.glb filter=lfs diff=lfs merge=lfs -text +*.gltf filter=lfs diff=lfs merge=lfs -text *.ogg filter=lfs diff=lfs merge=lfs -text *.wav filter=lfs diff=lfs merge=lfs -text *.mp3 filter=lfs diff=lfs merge=lfs -text diff --git a/assets/amd_ryzen_9.glb b/assets/amd_ryzen_9.glb new file mode 100644 index 0000000..5dbeeaa --- /dev/null +++ b/assets/amd_ryzen_9.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8af741b6471ab7d5095ae137ddda1e095e1d092b77a1152f5a8e2988158b51a +size 4551664 diff --git a/assets/shaders/mesh.glsl b/assets/shaders/mesh.glsl index 0f16855..079d5f5 100644 --- a/assets/shaders/mesh.glsl +++ b/assets/shaders/mesh.glsl @@ -81,9 +81,9 @@ struct Material { Material evalMaterial() { Material result; result.albedo = textureSize(albedo_map, 0) == ivec2(0) ? pow(color, vec3(2.2)) : texture(albedo_map, VertexOut.uv).rgb; - float fMetallic = textureSize(metallic_map, 0) == ivec2(0) ? metallic : texture(metallic_map, VertexOut.uv).r; + float fMetallic = textureSize(metallic_map, 0) == ivec2(0) ? metallic : texture(metallic_map, VertexOut.uv).b; result.metallic = fMetallic > 0.5; - result.roughness = max(0.01, textureSize(roughness_map, 0) == ivec2(0) ? roughness : texture(roughness_map, VertexOut.uv).r); + result.roughness = max(0.01, textureSize(roughness_map, 0) == ivec2(0) ? roughness : texture(roughness_map, VertexOut.uv).g); result.emission = textureSize(emission_map, 0) == ivec2(0) ? emission : texture(emission_map, VertexOut.uv).rgb; return result; diff --git a/build.zig.zon b/build.zig.zon index fd613e7..5318e4a 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -20,11 +20,11 @@ .hash = "1220483cbb42231cb056f4ea6669894c68ccd560d3af5832d6e9c84c61844bc20b7d", }, .@"zig-assimp" = .{ - .url = "https://github.com/sergeypdev/zig-assimp/tarball/59c2f0202bf1e5110f3eb219669f3762e3db2768", - .hash = "122015247b178258ee2fd9f7fbd3f8025138e8e38b5cbecdc94262974da49bd1c225", + .url = "https://github.com/sergeypdev/zig-assimp/tarball/39380dcc231788b3b54f447540bd6fea296fab10", + .hash = "12209b95f2f5a85107ed38814143179f1e7516440704fb94004046d6f5b5ed3c8667", }, .zalgebra = .{ - .url = "git+https://github.com/sergeypdev/zalgebra.git#232ff76712dc7cc270b6c48cedc84617536f3a59", + .url = "https://github.com/sergeypdev/zalgebra/tarball/232ff76712dc7cc270b6c48cedc84617536f3a59", .hash = "12206e29e5d0f012c694f413b21cb66238964fdaef0a29781e0bf3ff75ec08a2ed78", }, }, diff --git a/src/AssetManager.zig b/src/AssetManager.zig index 00974f5..fb179c2 100644 --- a/src/AssetManager.zig +++ b/src/AssetManager.zig @@ -137,6 +137,21 @@ pub fn resolveScene(self: *AssetManager, handle: Handle.Scene) *const formats.Sc return &self.loadScene(handle.id).scene; } +pub fn resolveMaterial(self: *AssetManager, handle: Handle.Material) *const formats.Material { + if (handle.id == 0) return &NullMaterial; + + if (self.loaded_assets.getPtr(handle.id)) |asset| { + switch (asset.*) { + .material => |*material| { + return material; + }, + else => unreachable, + } + } + + return self.loadMaterial(handle.id); +} + // TODO: proper watching pub fn watchChanges(self: *AssetManager) void { var iter = self.loaded_assets.iterator(); @@ -278,6 +293,8 @@ const NullScene = LoadedScene{ .scene = .{}, }; +const NullMaterial = formats.Material{}; + pub fn loadMesh(self: *AssetManager, id: AssetId) *const LoadedMesh { return self.loadMeshErr(id) catch |err| { std.log.err("Error: {} loading mesh at path: {s}", .{ err, asset_manifest.getPath(id) }); @@ -474,12 +491,39 @@ fn loadSceneErr(self: *AssetManager, id: AssetId) !*const LoadedScene { return &self.loaded_assets.getPtr(id).?.scene; } +fn loadMaterial(self: *AssetManager, id: AssetId) *const formats.Material { + return self.loadMaterialErr(id) catch |err| { + std.log.err("Error: {} loading material at path {s}\n", .{ err, asset_manifest.getPath(id) }); + + return &NullMaterial; + }; +} + +fn loadMaterialErr(self: *AssetManager, id: AssetId) !*const formats.Material { + const path = asset_manifest.getPath(id); + const data = try self.loadFile(self.frame_arena, path, TEXTURE_MAX_BYTES); + + const material = formats.Material.fromBuffer(data.bytes); + + try self.loaded_assets.put( + self.allocator, + id, + .{ + .material = material, + }, + ); + try self.modified_times.put(self.allocator, id, data.modified); + + return &self.loaded_assets.getPtr(id).?.material; +} + const LoadedAsset = union(enum) { shader: LoadedShader, shaderProgram: LoadedShaderProgram, mesh: LoadedMesh, texture: LoadedTexture, scene: LoadedScene, + material: formats.Material, }; const LoadedShader = struct { @@ -666,6 +710,7 @@ fn unloadAssetWithDependees(self: *AssetManager, id: AssetId) void { .scene => |*scene| { self.allocator.free(scene.buf); }, + .material => {}, } } _ = self.loaded_assets.remove(id); diff --git a/src/assets/root.zig b/src/assets/root.zig index 701c24a..b949b99 100644 --- a/src/assets/root.zig +++ b/src/assets/root.zig @@ -6,4 +6,5 @@ pub const Handle = struct { pub const ShaderProgram = extern struct { id: AssetId = 0 }; pub const Mesh = extern struct { id: AssetId = 0 }; pub const Texture = extern struct { id: AssetId = 0 }; + pub const Material = extern struct { id: AssetId = 0 }; }; diff --git a/src/formats.zig b/src/formats.zig index 55a0344..be360c4 100644 --- a/src/formats.zig +++ b/src/formats.zig @@ -163,6 +163,11 @@ fn writeVector3(writer: anytype, value: Vector3, endian: std.builtin.Endian) !vo try writeFloat(writer, value.y, endian); try writeFloat(writer, value.z, endian); } +fn writeVec3(writer: anytype, value: Vec3, endian: std.builtin.Endian) !void { + try writeFloat(writer, value.x(), endian); + try writeFloat(writer, value.y(), endian); + try writeFloat(writer, value.z(), endian); +} fn writeFloat(writer: anytype, value: f32, endian: std.builtin.Endian) !void { const val: u32 = @bitCast(value); @@ -350,6 +355,7 @@ test "write and read scene" { } pub const Material = extern struct { + // TODO: rgba albedo: Vec3 = Vec3.one(), albedo_map: Handle.Texture = .{}, normal_map: Handle.Texture = .{}, @@ -359,4 +365,15 @@ pub const Material = extern struct { roughness_map: Handle.Texture = .{}, emission: f32 = 0, emission_map: Handle.Texture = .{}, + + pub fn fromBuffer(buf: []const u8) Material { + const mat: *align(1) const Material = @ptrCast(buf); + + return mat.*; + } }; + +// TODO: doesn't respect endianness +pub fn writeMaterial(writer: anytype, value: Material) !void { + try writer.writeStruct(value); +} diff --git a/src/game.zig b/src/game.zig index ed7c755..6e9c9c2 100644 --- a/src/game.zig +++ b/src/game.zig @@ -224,9 +224,9 @@ export fn game_init(global_allocator: *std.mem.Allocator) void { .transform = .{ .scale = Vec3.one().scale(2) }, .mesh = .{ .handle = a.Meshes.plane, - .material = .{ - .normal_map = a.Textures.@"tile.norm", - }, + // .material = .{ + // .normal_map = a.Textures.@"tile.norm", + // }, }, }); @@ -239,11 +239,11 @@ export fn game_init(global_allocator: *std.mem.Allocator) void { .flags = .{ .mesh = true }, .mesh = .{ .handle = a.Meshes.bunny, - .material = .{ - .albedo_map = a.Textures.bunny_tex1, - // .normal_map = a.Textures.@"tile.norm", - .roughness = @as(f32, @floatFromInt(i)) / 10.0, - }, + // .material = .{ + // .albedo_map = a.Textures.bunny_tex1, + // // .normal_map = a.Textures.@"tile.norm", + // .roughness = @as(f32, @floatFromInt(i)) / 10.0, + // }, }, }); } @@ -257,19 +257,22 @@ export fn game_init(global_allocator: *std.mem.Allocator) void { .flags = .{ .mesh = true }, .mesh = .{ .handle = a.Meshes.bunny, - .material = .{ - .albedo = Vec3.new(1.000, 0.766, 0.336), - // .albedo_map = a.Textures.bunny_tex1, - // .normal_map = a.Textures.@"tile.norm", - .roughness = @as(f32, @floatFromInt(i + 1)) / 10.0, - .metallic = 1.0, - }, + // .material = .{ + // .albedo = Vec3.new(1.000, 0.766, 0.336), + // // .albedo_map = a.Textures.bunny_tex1, + // // .normal_map = a.Textures.@"tile.norm", + // .roughness = @as(f32, @floatFromInt(i + 1)) / 10.0, + // .metallic = 1.0, + // }, }, }); } } - // const test_scene_root = globals.g_mem.world.createScene(globals.g_assetman.resolveScene(a.Scenes.test_scene.scene)); + const ryzen = globals.g_mem.world.createScene(globals.g_assetman.resolveScene(a.Scenes.amd_ryzen_9.scene)); + const ent = globals.g_mem.world.getEntity(ryzen) orelse @panic("WTF"); + ent.data.transform.pos = Vec3.new(0, 1, 0); + ent.data.transform.scale = Vec3.one().scale(0.2); } export fn game_update() bool { @@ -456,7 +459,7 @@ export fn game_update() bool { if (ent.data.flags.mesh) { gmem.render.draw(.{ .mesh = ent.data.mesh.handle, - .material = ent.data.mesh.material, + .material = gmem.assetman.resolveMaterial(ent.data.mesh.material).*, .transform = ent.globalMatrix(&gmem.world).*, }); } else if (ent.data.flags.point_light) { diff --git a/src/gen/asset_manifest.zig b/src/gen/asset_manifest.zig index f396c8f..d847f32 100644 --- a/src/gen/asset_manifest.zig +++ b/src/gen/asset_manifest.zig @@ -5,6 +5,7 @@ pub const Meshes = manifest.Meshes; pub const Shaders = manifest.Shaders; pub const ShaderPrograms = manifest.ShaderPrograms; pub const Textures = manifest.Textures; +pub const Materials = manifest.Materials; pub fn getPath(asset_id: u64) []const u8 { manifest.init(); diff --git a/src/globals.zig b/src/globals.zig index fdead6e..93de71b 100644 --- a/src/globals.zig +++ b/src/globals.zig @@ -77,7 +77,7 @@ pub const Entity = struct { pub const Mesh = extern struct { handle: AssetManager.Handle.Mesh = .{}, - material: Material = .{}, + material: AssetManager.Handle.Material = .{}, }; pub const PointLight = extern struct { radius: f32 = std.math.floatEps(f32), // should never be 0 or bad things happen diff --git a/tools/asset_compiler.zig b/tools/asset_compiler.zig index bd5b13b..4948515 100644 --- a/tools/asset_compiler.zig +++ b/tools/asset_compiler.zig @@ -69,8 +69,9 @@ pub fn main() !void { const cwd_path = try std.os.getcwd(&cwd_buf); const rel_input = try std.fs.path.relative(allocator, cwd_path, abs_input); + const rel_output = try std.fs.path.relative(allocator, cwd_path, output_dirname); - var output_dir = try std.fs.cwd().makeOpenPath(output_dirname, .{}); + var output_dir = try std.fs.cwd().makeOpenPath(rel_output, .{}); defer output_dir.close(); const asset_type = resolveAssetTypeByExtension(abs_input) orelse return error.UnknownAssetType; @@ -78,7 +79,7 @@ pub fn main() !void { var buf_asset_list_writer = std.io.bufferedWriter(std.io.getStdOut().writer()); const asset_list_writer = buf_asset_list_writer.writer(); - std.log.debug("type: {s}, rel_input: {s}", .{ @tagName(asset_type), rel_input }); + std.log.debug("type: {s}, rel_input: {s}, output_dir: {s}", .{ @tagName(asset_type), rel_input, rel_output }); switch (asset_type) { .Scene => try processScene(allocator, rel_input, output_dir, asset_list_writer), @@ -134,16 +135,23 @@ fn createOutput(_type: AssetType, asset_path: AssetPath, output_dir: std.fs.Dir, }; } +const AI_MATKEY_NAME = "?mat.name"; +const AI_MATKEY_SHADING_MODEL = "$mat.shadingm"; +const AI_MATKEY_BASE_COLOR = "$clr.base"; +const AI_MATKEY_METALLIC_FACTOR = "$mat.metallicFactor"; +const AI_MATKEY_ROUGHNESS_FACTOR = "$mat.roughnessFactor"; +const AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE = c.aiTextureType_UNKNOWN; + /// This can output either a single mesh (for simple formats like obj) /// or a scene + a bunch of sub assets (meshes, materials, textures, animations, etc.) /// It all depends on the source asset. fn processScene(allocator: std.mem.Allocator, input: []const u8, output_dir: std.fs.Dir, asset_list_writer: anytype) !void { const input_z = try std.mem.concatWithSentinel(allocator, u8, &.{input}, 0); - const config: *c.aiPropertyStore = @as(?*c.aiPropertyStore, @ptrCast(c.aiCreatePropertyStore())) orelse return error.PropertyStore; - defer c.aiReleasePropertyStore(config); + // const config: *c.aiPropertyStore = @as(?*c.aiPropertyStore, @ptrCast(c.aiCreatePropertyStore())) orelse return error.PropertyStore; + // defer c.aiReleasePropertyStore(config); - // Remove point and line meshes - c.aiSetImportPropertyInteger(config, c.AI_CONFIG_PP_SBP_REMOVE, c.aiPrimitiveType_POINT | c.aiPrimitiveType_LINE); + // // Remove point and line meshes + // c.aiSetImportPropertyInteger(config, c.AI_CONFIG_PP_SBP_REMOVE, c.aiPrimitiveType_POINT | c.aiPrimitiveType_LINE); const maybe_scene: ?*const c.aiScene = @ptrCast(c.aiImportFile( input_z.ptr, @@ -154,7 +162,7 @@ fn processScene(allocator: std.mem.Allocator, input: []const u8, output_dir: std return error.ImportFailed; } const scene = maybe_scene.?; - defer c.aiReleaseImport(scene); + // defer c.aiReleaseImport(scene); if (scene.mNumMeshes == 0) return error.NoMeshes; @@ -168,20 +176,7 @@ fn processScene(allocator: std.mem.Allocator, input: []const u8, output_dir: std } else { const base_asset_path = AssetPath{ .simple = input }; - const meshes: []*c.aiMesh = @ptrCast(scene.mMeshes[0..@intCast(scene.mNumMeshes)]); - var mesh_outputs = try allocator.alloc(AssetListEntry, meshes.len); - for (meshes, 0..) |mesh, i| { - const name = mesh.mName.data[0..mesh.mName.length]; - std.log.debug("mesh name {s}\n", .{name}); - - var output = try createOutput(.Mesh, base_asset_path.subPath(try allocator.dupe(u8, name)), output_dir, asset_list_writer); - defer output.file.close(); - - mesh_outputs[i] = output.list_entry; - - try processMesh(allocator, scene, mesh, output.file); - } - + // Embedded textures var texture_outputs = try allocator.alloc(AssetListEntry, @intCast(scene.mNumTextures)); if (scene.mTextures != null) { const textures: []*c.aiTexture = @ptrCast(scene.mTextures[0..@intCast(scene.mNumTextures)]); @@ -200,12 +195,85 @@ fn processScene(allocator: std.mem.Allocator, input: []const u8, output_dir: std var output = try createOutput(.Texture, base_asset_path.subPath(name), output_dir, asset_list_writer); defer output.file.close(); - try processTexture(allocator, name, @as([*]u8, @ptrCast(texture.pcData))[0..@intCast(texture.mWidth)], output.file); - texture_outputs[i] = output.list_entry; + + try processTexture(allocator, name, @as([*]u8, @ptrCast(texture.pcData))[0..@intCast(texture.mWidth)], output.file); } } + // Materials + var material_outputs = try allocator.alloc(AssetListEntry, @intCast(scene.mNumMaterials)); + if (scene.mMaterials != null) { + const materials: []*c.aiMaterial = @ptrCast(scene.mMaterials[0..@intCast(scene.mNumMaterials)]); + + for (materials, 0..) |material, i| { + var str: c.aiString = .{}; + tryAssimp(c.aiGetMaterialString(material, AI_MATKEY_NAME, 0, 0, &str)) catch {}; + var name: []u8 = @alignCast(str.data[0..str.length]); + if (name.len == 0) { + name = try std.fmt.allocPrint(allocator, "material_{}", .{i + 1}); + } else { + name = try allocator.dupe(u8, name); + } + + var output = try createOutput(.Material, base_asset_path.subPath(name), output_dir, asset_list_writer); + defer output.file.close(); + + var buf_writer = std.io.bufferedWriter(output.file.writer()); + + material_outputs[i] = output.list_entry; + + var mat_output = formats.Material{}; + + var base_color: c.aiColor4D = .{}; + try tryAssimp(c.aiGetMaterialColor(material, AI_MATKEY_BASE_COLOR, 0, 0, &base_color)); + // TODO: rgba + mat_output.albedo = Vec3.new(base_color.r, base_color.g, base_color.b); + + if (c.aiGetMaterialTextureCount(material, c.aiTextureType_BASE_COLOR) > 0) { + const mat_texture = try getMaterialTexture(allocator, material, c.aiTextureType_BASE_COLOR, 0); + const entry = mat_texture.path.resolveAssetListEntry(texture_outputs); + mat_output.albedo_map.id = entry.getAssetId(); + } + + try tryAssimp(c.aiGetMaterialFloat(material, AI_MATKEY_METALLIC_FACTOR, 0, 0, &mat_output.metallic)); + if (c.aiGetMaterialTextureCount(material, c.aiTextureType_METALNESS) > 0) { + const mat_texture = try getMaterialTexture(allocator, material, c.aiTextureType_METALNESS, 0); + const entry = mat_texture.path.resolveAssetListEntry(texture_outputs); + mat_output.metallic_map.id = entry.getAssetId(); + } + + try tryAssimp(c.aiGetMaterialFloat(material, AI_MATKEY_ROUGHNESS_FACTOR, 0, 0, &mat_output.roughness)); + if (c.aiGetMaterialTextureCount(material, c.aiTextureType_DIFFUSE_ROUGHNESS) > 0) { + const mat_texture = try getMaterialTexture(allocator, material, c.aiTextureType_DIFFUSE_ROUGHNESS, 0); + const entry = mat_texture.path.resolveAssetListEntry(texture_outputs); + mat_output.roughness_map.id = entry.getAssetId(); + } + + try formats.writeMaterial(buf_writer.writer(), mat_output); + try buf_writer.flush(); + } + } + + const MeshEntry = struct { mesh: AssetListEntry, material: AssetListEntry }; + + const meshes: []*c.aiMesh = @ptrCast(scene.mMeshes[0..@intCast(scene.mNumMeshes)]); + var mesh_outputs = try allocator.alloc(MeshEntry, meshes.len); + for (meshes, 0..) |mesh, i| { + const name = mesh.mName.data[0..mesh.mName.length]; + + var output = try createOutput(.Mesh, base_asset_path.subPath(try allocator.dupe(u8, name)), output_dir, asset_list_writer); + defer output.file.close(); + + if (mesh.mMaterialIndex < 0 or @as(usize, @intCast(mesh.mMaterialIndex)) > material_outputs.len) { + return error.InvalidMaterialIndex; + } + + mesh_outputs[i] = .{ .mesh = output.list_entry, .material = material_outputs[@intCast(mesh.mMaterialIndex)] }; + + try processMesh(allocator, scene, mesh, output.file); + } + if (scene.mRootNode == null) return; var node_to_entity_idx = std.AutoHashMap(*c.aiNode, usize).init(allocator); @@ -253,7 +321,8 @@ fn processScene(allocator: std.mem.Allocator, input: []const u8, output_dir: std const mesh_entry = mesh_outputs[mesh_indices[0]]; ent.flags.mesh = true; - ent.mesh.handle = .{ .id = mesh_entry.src_path.hash() }; + ent.mesh.handle = .{ .id = mesh_entry.mesh.getAssetId() }; + ent.mesh.material = .{ .id = mesh_entry.material.getAssetId() }; } else { for (mesh_indices) |mesh_idx| { const mesh_entry = mesh_outputs[@intCast(mesh_idx)]; @@ -266,7 +335,8 @@ fn processScene(allocator: std.mem.Allocator, input: []const u8, output_dir: std sub_ent.flags.mesh = true; sub_ent.mesh = .{ - .handle = .{ .id = mesh_entry.src_path.hash() }, + .handle = .{ .id = mesh_entry.mesh.getAssetId() }, + .material = .{ .id = mesh_entry.material.getAssetId() }, }; } } @@ -289,6 +359,67 @@ fn processScene(allocator: std.mem.Allocator, input: []const u8, output_dir: std } } +const AssimpTextureRef = union(enum) { + external: []const u8, + embedded: usize, + + pub fn fromString(str: []const u8) !AssimpTextureRef { + if (str.len == 0) return error.EmptyPath; + + if (str[0] == '*') { + const idx = try std.fmt.parseInt(usize, str[1..], 10); + + return .{ .embedded = idx }; + } + + return .{ .external = str }; + } + + pub fn resolveAssetListEntry(self: AssimpTextureRef, embedded: []const AssetListEntry) AssetListEntry { + switch (self) { + .embedded => |idx| { + return embedded[idx]; + }, + .external => |path| { + // TODO: resolve relative to current input file + return AssetListEntry{ .src_path = AssetPath.fromString(path), .type = .Texture }; + }, + } + } +}; + +const MaterialTexture = struct { + path: AssimpTextureRef = .{ .external = "" }, + mapping: c.aiTextureMapping = 0, + uv_index: c_uint = 0, + blend: f32 = 0, + op: c.aiTextureOp = 0, + map_mode: [3]c.aiTextureMapMode = .{ 0, 0, 0 }, + flags: c_uint = 0, +}; +fn getMaterialTexture(allocator: std.mem.Allocator, material: *c.aiMaterial, _type: c.aiTextureType, index: c_uint) !MaterialTexture { + var path: c.aiString = undefined; + var result: MaterialTexture = .{}; + + try tryAssimp(c.aiGetMaterialTexture( + material, + _type, + index, + &path, + &result.mapping, + &result.uv_index, + &result.blend, + &result.op, + &result.map_mode, + &result.flags, + )); + + const path_str: []u8 = try allocator.dupe(u8, @alignCast(path.data[0..path.length])); + result.path = try AssimpTextureRef.fromString(path_str); + + return result; +} + fn processMesh(allocator: std.mem.Allocator, scene: *const c.aiScene, mesh: *const c.aiMesh, out_file: std.fs.File) !void { _ = scene; // autofix if (mesh.mNormals == null) return error.MissingNormals; @@ -422,9 +553,9 @@ fn processTexture(allocator: std.mem.Allocator, input: []const u8, contents: []c const sub_ext = std.fs.path.extension(std.fs.path.stem(input)); const format = if (std.mem.eql(u8, sub_ext, ".norm")) formats.Texture.Format.bc5 else formats.Texture.Format.bc7; - var width_int: c_int = undefined; - var height_int: c_int = undefined; - var comps: c_int = undefined; + var width_int: c_int = 0; + var height_int: c_int = 0; + var comps: c_int = 0; c.stbi_set_flip_vertically_on_load(1); const rgba_data_c = c.stbi_load_from_memory(contents.ptr, @intCast(contents.len), &width_int, &height_int, &comps, 4); @@ -711,9 +842,16 @@ inline fn storeColorVec4(pixel: []u8, vec: @Vector(4, f32)) void { pixel[3] = @intFromFloat(out[3]); } -fn changeExtensionAlloc(allocator: std.mem.Allocator, input: []const u8, new_ext: []const u8) ![]u8 { - const input_basename = std.fs.path.basename(input); - const ext = std.fs.path.extension(input_basename); - const name_without_ext = input_basename[0 .. input_basename.len - ext.len]; - return try std.mem.concat(allocator, u8, &.{ name_without_ext, ".", new_ext }); +fn tryAssimp(code: c.aiReturn) !void { + switch (code) { + c.aiReturn_SUCCESS => {}, + c.aiReturn_FAILURE => { + std.log.err("getMaterialTexture: {s}\n", .{c.aiGetErrorString()}); + return error.AssimpError; + }, + c.aiReturn_OUTOFMEMORY => { + return error.OutOfMemory; + }, + else => unreachable, + } } diff --git a/tools/types.zig b/tools/types.zig index eb68792..58065c4 100644 --- a/tools/types.zig +++ b/tools/types.zig @@ -6,6 +6,7 @@ pub const AssetType = enum { Shader, ShaderProgram, Texture, + Material, pub fn pluralName(self: AssetType) []const u8 { return switch (self) { @@ -14,6 +15,7 @@ pub const AssetType = enum { .Shader => "Shaders", .ShaderProgram => "ShaderPrograms", .Texture => "Textures", + .Material => "Materials", }; } @@ -24,6 +26,7 @@ pub const AssetType = enum { .Shader => "glsl", .ShaderProgram => "prog", .Texture => "tex", + .Material => "mat", }; } };