diff --git a/build.zig b/build.zig index a3bf0b5..d0bfa5b 100644 --- a/build.zig +++ b/build.zig @@ -7,15 +7,15 @@ pub fn build(b: *std.Build) !void { const optimize = b.standardOptimizeOption(.{}); const llvm = b.option(bool, "llvm", "Use LLVM and LLD") orelse false; + const media_dep = b.dependency("media", .{}); const vecmath_dep = b.dependency("vecmath", .{}); const vulkan_dep = b.dependency("vulkan_zig", .{ .registry = b.path("vendor/vk.xml") }); const zglfw_dep = b.dependency("zglfw", .{ .import_vulkan = true }); - const zstbi_dep = b.dependency("zstbi", .{}); + const media_mod = media_dep.module("media"); const vecmath_mod = vecmath_dep.module("vecmath"); const vulkan_mod = vulkan_dep.module("vulkan-zig"); const zglfw_mod = zglfw_dep.module("root"); - const zstbi_mod = zstbi_dep.module("root"); zglfw_mod.addImport("vulkan", vulkan_mod); @@ -27,10 +27,10 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, }); + exe_mod.addImport("media", media_mod); exe_mod.addImport("vecmath", vecmath_mod); exe_mod.addImport("vulkan", vulkan_mod); exe_mod.addImport("zglfw", zglfw_mod); - exe_mod.addImport("zstbi", zstbi_mod); exe_mod.linkLibrary(zglfw_lib); const options = b.addOptions(); diff --git a/build.zig.zon b/build.zig.zon index 3ba66cf..c5a3db1 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -5,6 +5,9 @@ .minimum_zig_version = "0.15.2", .dependencies = .{ + .media = .{ + .path = "castle/packages/media", + }, .vecmath = .{ .path = "castle/packages/vecmath", }, @@ -16,10 +19,6 @@ .url = "git+https://github.com/zig-gamedev/zglfw.git#6034a5623312c58bf5e64c1a2b686691c28575f4", .hash = "zglfw-0.10.0-dev-zgVDNPKyIQCBi-wv_vxkvIQq1u0bP4D56Wszx_2mszc7", }, - .zstbi = .{ - .url = "git+https://github.com/zig-gamedev/zstbi#2c4b3100ccb7aed90ecc9439030899764e2a8d47", - .hash = "zstbi-0.11.0-dev-L0Ea_yaWBwAHwFoCuyjkFyaiSsbjt4UOrkntR0c_nmzz", - }, }, .paths = .{ diff --git a/castle b/castle index 31651dc..85f4957 160000 --- a/castle +++ b/castle @@ -1 +1 @@ -Subproject commit 31651dc96a9721db11099aba34dae18d98be46d1 +Subproject commit 85f49576611c2cbb63f9785ac39abb75403aa203 diff --git a/src/Game.zig b/src/Game.zig index 11a3076..8321760 100644 --- a/src/Game.zig +++ b/src/Game.zig @@ -4,6 +4,7 @@ const std = @import("std"); const c = @import("const.zig"); const glfw = @import("zglfw"); const math = @import("math.zig"); +const media = @import("media"); const shaders = @import("shaders.zig"); const vk = @import("vulkan"); const vm = @import("vecmath"); @@ -43,6 +44,7 @@ directional_lights: shaders.DirectionalLightBuffer, sampler: vk.Sampler, deferred_command_buffers: std.ArrayList(CommandBuffer), +stbi: media.stbi, blocks: Blocks, materials: Materials, textures: Textures, @@ -59,6 +61,9 @@ const chunk_descriptor_pool = 1024; const camera_near_plane = 0.1; pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain) !Game { + var stbi = media.stbi.init(allocator); + errdefer stbi.deinit(); + var materials = try Materials.init(engine, allocator); errdefer materials.deinit(engine, allocator); @@ -72,7 +77,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain // will crash the game with segfault reading address 0x140 (presumably // within librenderdoc.so). - blocks.loadAll(engine, &materials, &textures, allocator); + blocks.loadAll(engine, &materials, &textures, &stbi, allocator); const sampler = try engine.createSampler(.{ .mag_filter = .linear, @@ -433,10 +438,10 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain }); engine.setObjectName(global_descriptor_set, "DS Global", .{}); - const block_grass = try blocks.getOrLoad(engine, &materials, &textures, "Grass.json", allocator); - const block_dirt = try blocks.getOrLoad(engine, &materials, &textures, "Dirt.json", allocator); - const block_stone = try blocks.getOrLoad(engine, &materials, &textures, "Stone.json", allocator); - const block_bedrock = try blocks.getOrLoad(engine, &materials, &textures, "Bedrock.json", allocator); + const block_grass = try blocks.getOrLoad(engine, &materials, &textures, &stbi, "Grass.json", allocator); + const block_dirt = try blocks.getOrLoad(engine, &materials, &textures, &stbi, "Dirt.json", allocator); + const block_stone = try blocks.getOrLoad(engine, &materials, &textures, &stbi, "Stone.json", allocator); + const block_bedrock = try blocks.getOrLoad(engine, &materials, &textures, &stbi, "Bedrock.json", allocator); // VOLATILE Load all assets before this point @@ -627,7 +632,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain .elements = directional_lights_data, }); - var skybox = try Skybox.load("skybox.hdr", engine, 512, global_uniforms.buffer, swapchain.render_pass, allocator); + var skybox = try Skybox.load("skybox.hdr", engine, &stbi, 512, global_uniforms.buffer, swapchain.render_pass, allocator); errdefer skybox.deinit(engine); return .{ @@ -652,6 +657,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain .sampler = sampler, .deferred_command_buffers = try .initCapacity(allocator, 4), + .stbi = stbi, .blocks = blocks, .materials = materials, .textures = textures, @@ -696,6 +702,7 @@ pub fn deinit(self: *Game) void { self.textures.deinit(self.engine, self.allocator); self.materials.deinit(self.engine, self.allocator); self.blocks.deinit(self.allocator); + self.stbi.deinit(); self.* = undefined; } diff --git a/src/Player.zig b/src/Player.zig index 74e19fb..bf8f2fe 100644 --- a/src/Player.zig +++ b/src/Player.zig @@ -264,7 +264,7 @@ pub fn onMouseDown(self: *Player, button: glfw.MouseButton, game: *Game) void { }, .right => blk: { const target_vx = raycast_hit.voxel.add(raycast_hit.side.getSignVector()); - const id = game.blocks.getOrLoad(game.engine, &game.materials, &game.textures, blocks[self.block_index], game.allocator) catch |err| { + const id = game.blocks.getOrLoad(game.engine, &game.materials, &game.textures, &game.stbi, blocks[self.block_index], game.allocator) catch |err| { std.log.err("Error while placing voxel at {f}: {}", .{ target_vx, err }); break :blk; }; diff --git a/src/assets/Blocks.zig b/src/assets/Blocks.zig index 054192a..e2bb4ae 100644 --- a/src/assets/Blocks.zig +++ b/src/assets/Blocks.zig @@ -3,6 +3,7 @@ const Blocks = @This(); const std = @import("std"); +const media = @import("media"); const voxels = @import("../voxels.zig"); const Atom = @import("../engine/Atom.zig").Atom; @@ -134,6 +135,7 @@ pub fn getOrLoad( engine: *Engine, materials: *Materials, textures: *Textures, + stbi: *media.stbi, filename: []const u8, temp_allocator: std.mem.Allocator, ) !Id { @@ -152,7 +154,7 @@ pub fn getOrLoad( const id = Id.fromIndexSafe(self.array.items.len) catch |err| switch (err) { error.Overflow => return error.OutOfBlocks, }; - const def = try loadBlock(engine, materials, textures, filename, temp_allocator); + const def = try loadBlock(engine, materials, textures, stbi, filename, temp_allocator); self.map.putAssumeCapacityNoClobber(key, id); self.array.appendAssumeCapacity(def); @@ -166,6 +168,7 @@ pub fn getOrLoadAtom( engine: *Engine, materials: *Materials, textures: *Textures, + stbi: *media.stbi, filename: Atom, temp_allocator: std.mem.Allocator, ) !Id { @@ -182,7 +185,7 @@ pub fn getOrLoadAtom( const id = Id.fromIndexSafe(self.array.items.len) catch |err| switch (err) { error.Overflow => return error.OutOfBlocks, }; - const def = try loadBlock(engine, materials, textures, filename.toString(), temp_allocator); + const def = try loadBlock(engine, materials, textures, stbi, filename.toString(), temp_allocator); self.map.putAssumeCapacityNoClobber(key, id); self.array.appendAssumeCapacity(def); @@ -196,6 +199,7 @@ pub fn loadAll( engine: *Engine, materials: *Materials, textures: *Textures, + stbi: *media.stbi, temp_allocator: std.mem.Allocator, ) void { const cwd = std.fs.cwd(); @@ -216,7 +220,7 @@ pub fn loadAll( continue; } - _ = self.getOrLoad(engine, materials, textures, entry.name, temp_allocator) catch |err| { + _ = self.getOrLoad(engine, materials, textures, stbi, entry.name, temp_allocator) catch |err| { std.log.err("Error while loading block definition entry {s}: {s}", .{ entry.name, @errorName(err) }); }; } @@ -226,6 +230,7 @@ fn loadBlock( engine: *Engine, materials: *Materials, textures: *Textures, + stbi: *media.stbi, filename: []const u8, temp_allocator: std.mem.Allocator, ) !Definition { @@ -274,7 +279,7 @@ fn loadBlock( return error.ParseError; } - const material = try materials.getOrLoad(engine, textures, name, temp_allocator); + const material = try materials.getOrLoad(engine, textures, stbi, name, temp_allocator); break :blk .initUniform(material); } @@ -284,7 +289,7 @@ fn loadBlock( var ret: Definition.Walls = undefined; inline for (@typeInfo(voxels.Orientation).@"enum".fields) |field| { @field(ret, field.name) = .{ - .material = try materials.getOrLoad(engine, textures, @field(walls, field.name).material, temp_allocator), + .material = try materials.getOrLoad(engine, textures, stbi, @field(walls, field.name).material, temp_allocator), .transform = @field(walls, field.name).transform, }; } diff --git a/src/assets/Materials.zig b/src/assets/Materials.zig index 6e6b875..c440d70 100644 --- a/src/assets/Materials.zig +++ b/src/assets/Materials.zig @@ -3,6 +3,7 @@ const Materials = @This(); const std = @import("std"); +const media = @import("media"); const shaders = @import("../shaders.zig"); const vk = @import("vulkan"); @@ -148,7 +149,7 @@ pub fn getAtom(self: *const Materials, filename: Atom) ?Id { /// deinitialized or reset after this function returns. Note that during loading /// the engine will make its own persistent allocations, so an out of memory /// error is not necessarily related to `temp_allocator`. -pub fn getOrLoad(self: *Materials, engine: *Engine, textures: *Textures, maybe_filename: ?[]const u8, temp_allocator: std.mem.Allocator) !Id { +pub fn getOrLoad(self: *Materials, engine: *Engine, textures: *Textures, stbi: *media.stbi, maybe_filename: ?[]const u8, temp_allocator: std.mem.Allocator) !Id { if (maybe_filename) |filename| { const key: Key = .{ // If the material already exists, then the atom must exist and the @@ -165,7 +166,7 @@ pub fn getOrLoad(self: *Materials, engine: *Engine, textures: *Textures, maybe_f const id = Id.fromIndexSafe(self.material_count) catch |err| switch (err) { error.Overflow => return error.OutOfMaterials, }; - try self.loadMaterial(engine, textures, filename, id.toInt(), temp_allocator); + try self.loadMaterial(engine, textures, stbi, filename, id.toInt(), temp_allocator); self.map.putAssumeCapacityNoClobber(key, id); self.material_count += 1; @@ -188,7 +189,7 @@ pub fn getOrLoad(self: *Materials, engine: *Engine, textures: *Textures, maybe_f /// deinitialized or reset after this function returns. Note that during loading /// the engine will make its own persistent allocations, so an out of memory /// error is not necessarily related to `temp_allocator`. -pub fn getOrLoadAtom(self: *Materials, engine: *Engine, textures: *Textures, filename: Atom, temp_allocator: std.mem.Allocator) !Id { +pub fn getOrLoadAtom(self: *Materials, engine: *Engine, textures: *Textures, stbi: *media.stbi, filename: Atom, temp_allocator: std.mem.Allocator) !Id { if (filename != .empty) { const key: Key = .{ .filename = filename, @@ -203,7 +204,7 @@ pub fn getOrLoadAtom(self: *Materials, engine: *Engine, textures: *Textures, fil const id = Id.fromIndexSafe(self.material_count) catch |err| switch (err) { error.Overflow => return error.OutOfMaterials, }; - try self.loadMaterial(engine, textures, filename.toString(), id.toInt(), temp_allocator); + try self.loadMaterial(engine, textures, stbi, filename.toString(), id.toInt(), temp_allocator); self.map.putAssumeCapacityNoClobber(key, id); self.material_count += 1; @@ -225,7 +226,7 @@ pub fn getOrLoadAtom(self: *Materials, engine: *Engine, textures: *Textures, fil /// deinitialized or reset after this function returns. Note that during loading /// the engine will make its own persistent allocations, so an out of memory /// error is not necessarily related to `temp_allocator`. -pub fn loadAll(self: *Materials, engine: *Engine, textures: *Textures, temp_allocator: std.mem.Allocator) void { +pub fn loadAll(self: *Materials, engine: *Engine, textures: *Textures, stbi: *media.stbi, temp_allocator: std.mem.Allocator) void { const cwd = std.fs.cwd(); var dir = cwd.openDir("assets/materials", .{ .iterate = true }) catch |err| { @@ -244,13 +245,13 @@ pub fn loadAll(self: *Materials, engine: *Engine, textures: *Textures, temp_allo continue; } - _ = self.getOrLoad(engine, textures, entry.name, temp_allocator) catch |err| { + _ = self.getOrLoad(engine, textures, stbi, entry.name, temp_allocator) catch |err| { std.log.err("Error while loading material entry {s}: {s}", .{ entry.name, @errorName(err) }); }; } } -fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, filename: []const u8, index: u32, temp_allocator: std.mem.Allocator) !void { +fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, stbi: *media.stbi, filename: []const u8, index: u32, temp_allocator: std.mem.Allocator) !void { const MaterialJson = struct { baseColor: [3]f32 = .{ 1, 1, 1 }, baseColorTexture: ?[]const u8 = null, @@ -302,10 +303,10 @@ fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, filename .normal_scale = material_json.normalScale, .occlusion_texture_strength = material_json.occlusionTextureStrength, .roughness = material_json.roughness, - .base_color_texture = try textures.getOrLoad(engine, material_json.baseColorTexture, .base_color, temp_allocator), - .emissive_texture = try textures.getOrLoad(engine, material_json.emissiveTexture, .emissive, temp_allocator), - .normal_texture = try textures.getOrLoad(engine, material_json.normalTexture, .normal, temp_allocator), - .occlusion_roughness_metallic_texture = try textures.getOrLoad(engine, material_json.occlusionRoughnessMetallicTexture, .occlusion_roughness_metallic, temp_allocator), + .base_color_texture = try textures.getOrLoad(engine, stbi, material_json.baseColorTexture, .base_color), + .emissive_texture = try textures.getOrLoad(engine, stbi, material_json.emissiveTexture, .emissive), + .normal_texture = try textures.getOrLoad(engine, stbi, material_json.normalTexture, .normal), + .occlusion_roughness_metallic_texture = try textures.getOrLoad(engine, stbi, material_json.occlusionRoughnessMetallicTexture, .occlusion_roughness_metallic), }, }, }); diff --git a/src/assets/Textures.zig b/src/assets/Textures.zig index a6ff3f3..c1a679a 100644 --- a/src/assets/Textures.zig +++ b/src/assets/Textures.zig @@ -3,7 +3,7 @@ const Textures = @This(); const std = @import("std"); -const stbi = @import("zstbi"); +const media = @import("media"); const Atom = @import("../engine/Atom.zig").Atom; const Engine = @import("../engine/Engine.zig"); @@ -172,14 +172,7 @@ pub fn getAtom(self: *const Textures, filename: Atom, usage: Texture.Usage) ?Id /// if necessary. Will not return any error if the texture already exists. When /// the filename is `null`, returns an empty texture ID appropriate for given /// usage. -/// -/// When a texture is being loaded, `temp_allocator` is used for temporary -/// allocations necessary to perform all operations. No memory allocated with -/// `temp_allocator` is retained, so the allocator can be deinitialized or reset -/// after this function returns. Note that during loading the engine will make -/// its own persistent allocations, so an out of memory error is not necessarily -/// related to `temp_allocator`. -pub fn getOrLoad(self: *Textures, engine: *Engine, maybe_filename: ?[]const u8, usage: Texture.Usage, temp_allocator: std.mem.Allocator) !Id { +pub fn getOrLoad(self: *Textures, engine: *Engine, stbi: *media.stbi, maybe_filename: ?[]const u8, usage: Texture.Usage) !Id { if (maybe_filename) |filename| { const key: Key = .{ // If the texture already exists, then the atom must exist and the @@ -197,7 +190,7 @@ pub fn getOrLoad(self: *Textures, engine: *Engine, maybe_filename: ?[]const u8, const id = Id.fromIndexSafe(self.array.items.len) catch |err| switch (err) { error.Overflow => return error.OutOfTextures, }; - const texture = try loadTexture(engine, filename, usage, temp_allocator); + const texture = try loadTexture(engine, stbi, filename, usage); self.map.putAssumeCapacityNoClobber(key, id); self.array.appendAssumeCapacity(texture); @@ -214,14 +207,7 @@ pub fn getOrLoad(self: *Textures, engine: *Engine, maybe_filename: ?[]const u8, /// if necessary. Will not return any error if the texture already exists. When /// the filename is `.empty`, returns an empty texture ID appropriate for given /// usage. -/// -/// When a texture is being loaded, `temp_allocator` is used for temporary -/// allocations necessary to perform all operations. No memory allocated with -/// `temp_allocator` is retained, so the allocator can be deinitialized or reset -/// after this function returns. Note that during loading the engine will make -/// its own persistent allocations, so an out of memory is not necessarily -/// related to `temp_allocator`. -pub fn getOrLoadAtom(self: *Textures, engine: *Engine, filename: Atom, usage: Texture.Usage, temp_allocator: std.mem.Allocator) !Id { +pub fn getOrLoadAtom(self: *Textures, engine: *Engine, stbi: *media.stbi, filename: Atom, usage: Texture.Usage) !Id { if (filename != .empty) { const key: Key = .{ .filename = filename, @@ -237,7 +223,7 @@ pub fn getOrLoadAtom(self: *Textures, engine: *Engine, filename: Atom, usage: Te const id = Id.fromIndexSafe(self.array.items.len) catch |err| switch (err) { error.Overflow => return error.OutOfTextures, }; - const texture = try loadTexture(engine, filename.toString(), usage, temp_allocator); + const texture = try loadTexture(engine, stbi, filename.toString(), usage); self.map.putAssumeCapacityNoClobber(key, id); self.array.appendAssumeCapacity(texture); @@ -249,7 +235,7 @@ pub fn getOrLoadAtom(self: *Textures, engine: *Engine, filename: Atom, usage: Te } } -fn loadTexture(engine: *Engine, filename: []const u8, usage: Texture.Usage, temp_allocator: std.mem.Allocator) !Texture { +fn loadTexture(engine: *Engine, stbi: *media.stbi, filename: []const u8, usage: Texture.Usage) !Texture { std.log.debug("Loading texture \"{s}\" as {s}...", .{ filename, @tagName(usage) }); const cwd = std.fs.cwd(); @@ -257,15 +243,25 @@ fn loadTexture(engine: *Engine, filename: []const u8, usage: Texture.Usage, temp var dir = try cwd.openDir("assets/textures", .{}); defer dir.close(); - const file_buf = try dir.readFileAlloc(temp_allocator, filename, std.math.maxInt(usize)); - defer temp_allocator.free(file_buf); + var file = try dir.openFile(filename, .{}); + defer file.close(); + + // The textures are expected to be small; a standard block base color as a + // PNG takes well below 1 kiB. + var buf: [4096]u8 = undefined; + var reader = file.reader(&buf); + + const img = try stbi.loadDynamicIo(&reader.interface); + defer stbi.freeDynamic(img); + + const data = img.data[0 .. img.width * img.height]; - var img = try stbi.Image.loadFromMemory(file_buf, usage.samplesPerTexel()); - defer img.deinit(); - std.debug.assert(img.num_components == usage.samplesPerTexel()); if (usage == .normal) { - for (img.data) |*sample| { - sample.* = sample.* +% 128; + for (data) |*pixel| { + pixel.r = pixel.r +% 128; + pixel.g = pixel.g +% 128; + pixel.b = pixel.b +% 128; + pixel.a = pixel.a +% 128; } } @@ -278,7 +274,7 @@ fn loadTexture(engine: *Engine, filename: []const u8, usage: Texture.Usage, temp }); errdefer texture.deinit(engine); - try texture.writeRaw(engine, img.data); + try texture.writeRaw(engine, @ptrCast(data)); return texture; } diff --git a/src/engine/Skybox.zig b/src/engine/Skybox.zig index 8a4e023..2a7742e 100644 --- a/src/engine/Skybox.zig +++ b/src/engine/Skybox.zig @@ -1,8 +1,8 @@ const Skybox = @This(); const std = @import("std"); +const media = @import("media"); const shaders = @import("../shaders.zig"); -const stbi = @import("zstbi"); const vk = @import("vulkan"); const vm = @import("vecmath"); @@ -25,7 +25,7 @@ descriptor_set: vk.DescriptorSet, pipeline_layout: vk.PipelineLayout, pipeline: vk.Pipeline, -pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, global_uniforms_buffer: vk.Buffer, render_pass: vk.RenderPass, temp_allocator: std.mem.Allocator) !Skybox { +pub fn load(filename: []const u8, engine: *Engine, stbi: *media.stbi, cube_size: u32, global_uniforms_buffer: vk.Buffer, render_pass: vk.RenderPass, temp_allocator: std.mem.Allocator) !Skybox { std.log.debug("Loading skybox \"{s}\"...", .{filename}); // --- LOAD IMAGE FROM MEMORY ---------------------------------------------- @@ -38,14 +38,8 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, global_unifor const file_buf = try dir.readFileAlloc(temp_allocator, filename, std.math.maxInt(usize)); defer temp_allocator.free(file_buf); - var img = try stbi.Image.loadFromMemory(file_buf, 4); - defer img.deinit(); - std.debug.assert(img.num_components == 4); - - // clamp +inf to max half float - for (std.mem.bytesAsSlice(f16, img.data)) |*sample| { - sample.* = @min(sample.*, std.math.floatMax(f16)); - } + const img = try stbi.loadHdrBuf(file_buf); + defer stbi.freeHdr(img); // --- SYNCHRONIZATION PRIMITIVES ------------------------------------------ @@ -64,13 +58,13 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, global_unifor // --- LOAD IMAGE INTO STAGING BUFFER -------------------------------------- var staging_buffer = try StagingBuffer.init(engine, .{ - .capacity = @intCast(img.data.len), + .capacity = @intCast(img.width * img.height * @sizeOf(vm.ColorHdr)), .target_queue = .compute, }); defer staging_buffer.deinit(engine); const staging_memory = try staging_buffer.map(engine); - @memcpy(staging_memory, img.data); + @memcpy(staging_memory, @as([*]const u8, @ptrCast(img.data))); staging_buffer.unmap(engine); // --- CREATE EQUIRECTANGULAR IMAGE ---------------------------------------- diff --git a/src/main.zig b/src/main.zig index 7fec816..fe47377 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,7 +1,6 @@ const std = @import("std"); const glfw = @import("zglfw"); -const stbi = @import("zstbi"); const vk = @import("vulkan"); const c = @import("const.zig"); @@ -34,9 +33,6 @@ pub fn main() !void { try atoms.init(allocator); defer atoms.deinit(); - stbi.init(allocator); - defer stbi.deinit(); - glfw.init() catch |err| { std.log.err("Could not initialize GLFW", .{}); return err;