Texture loading
This commit is contained in:
18
build.zig
18
build.zig
@@ -50,8 +50,7 @@ fn stepBuildMain(
|
|||||||
exe.root_module.addImport("sdl", sdl_module);
|
exe.root_module.addImport("sdl", sdl_module);
|
||||||
exe.step.dependOn(sdl_step);
|
exe.step.dependOn(sdl_step);
|
||||||
|
|
||||||
const c_module = cModule(b, target, optimize);
|
exe.addIncludePath(b.path("lib/clibs"));
|
||||||
exe.root_module.addImport("c", c_module);
|
|
||||||
|
|
||||||
return exe;
|
return exe;
|
||||||
}
|
}
|
||||||
@@ -107,21 +106,6 @@ fn stepSdlModule(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cModule(
|
|
||||||
b: *Build,
|
|
||||||
target: Build.ResolvedTarget,
|
|
||||||
optimize: std.builtin.OptimizeMode,
|
|
||||||
) *Build.Module {
|
|
||||||
const c_module = b.addModule("c", .{
|
|
||||||
.root_source_file = b.path("lib/c.zig"),
|
|
||||||
.link_libc = true,
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
c_module.addIncludePath(b.path("lib/clibs"));
|
|
||||||
return c_module;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stepCopyData(
|
fn stepCopyData(
|
||||||
b: *Build,
|
b: *Build,
|
||||||
target: Build.ResolvedTarget,
|
target: Build.ResolvedTarget,
|
||||||
|
BIN
data/wawa.png
Normal file
BIN
data/wawa.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 550 B |
104
src/assets.zig
Normal file
104
src/assets.zig
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const sdl = @import("sdl");
|
||||||
|
const err = @import("error.zig");
|
||||||
|
const c = @import("c.zig");
|
||||||
|
const comp = @import("components.zig");
|
||||||
|
const Game = @import("game.zig");
|
||||||
|
const Graphics = @import("graphics.zig");
|
||||||
|
const Assets = @This();
|
||||||
|
|
||||||
|
const Storage = comp.Storage(Asset, .{});
|
||||||
|
|
||||||
|
var storage: Storage = undefined;
|
||||||
|
|
||||||
|
pub const AssetType = enum {
|
||||||
|
texture,
|
||||||
|
};
|
||||||
|
pub const Texture = struct {
|
||||||
|
handle: Storage.Key,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Asset = struct {
|
||||||
|
path: []const u8,
|
||||||
|
data: union(AssetType) {
|
||||||
|
texture: AssetTexture,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
pub const AssetTexture = struct {
|
||||||
|
texture: *sdl.GPUTexture,
|
||||||
|
sampler: *sdl.GPUSampler,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init() void {
|
||||||
|
Assets.storage = Storage.init();
|
||||||
|
}
|
||||||
|
pub fn deinit() void {
|
||||||
|
var iter = Assets.storage.iter();
|
||||||
|
while (iter.next()) |asset| {
|
||||||
|
Assets.freeAsset(asset);
|
||||||
|
}
|
||||||
|
Assets.storage.deinit();
|
||||||
|
}
|
||||||
|
pub fn load(comptime asset_type: AssetType, path: []const u8) typeFromAssetType(asset_type) {
|
||||||
|
switch (asset_type) {
|
||||||
|
.texture => {
|
||||||
|
const data = loadFile(Game.alloc, path) catch |e| err.file(e, path);
|
||||||
|
var x: i32 = undefined;
|
||||||
|
var y: i32 = undefined;
|
||||||
|
var z: i32 = undefined;
|
||||||
|
const image = c.stbi_load_from_memory(@ptrCast(data), @intCast(data.len), &x, &y, &z, 4);
|
||||||
|
Game.alloc.free(data);
|
||||||
|
if (image == null) err.stbi();
|
||||||
|
const image_slice = image[0..@intCast(x * y * z)];
|
||||||
|
const texture, const sampler = Graphics.loadTexture(@intCast(x), @intCast(y), image_slice);
|
||||||
|
c.stbi_image_free(image);
|
||||||
|
return .{ .handle = Assets.storage.add(.{
|
||||||
|
.path = path,
|
||||||
|
.data = .{ .texture = .{
|
||||||
|
.texture = texture,
|
||||||
|
.sampler = sampler,
|
||||||
|
} },
|
||||||
|
}) };
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn free(asset: anytype) void {
|
||||||
|
if (Assets.storage.free(asset.handle)) |stored| {
|
||||||
|
freeAsset(stored);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn freeAsset(asset: *Asset) void {
|
||||||
|
switch (asset.data) {
|
||||||
|
.texture => {
|
||||||
|
Graphics.unloadTexture(asset.data.texture.texture, asset.data.texture.sampler);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get(asset: anytype) ?assetTypeFromType(@TypeOf(asset)) {
|
||||||
|
if (Assets.storage.get(asset.handle)) |stored| {
|
||||||
|
switch (@TypeOf(asset)) {
|
||||||
|
Texture => {
|
||||||
|
return stored.data.texture;
|
||||||
|
},
|
||||||
|
else => @compileError("Cannot get asset of type " ++ @typeName(@TypeOf(asset))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn loadFile(alloc: std.mem.Allocator, path: []const u8) ![]u8 {
|
||||||
|
const file = try std.fs.cwd().openFile(path, .{});
|
||||||
|
defer file.close();
|
||||||
|
return file.readToEndAlloc(alloc, std.math.maxInt(i32));
|
||||||
|
}
|
||||||
|
fn typeFromAssetType(comptime asset_type: AssetType) type {
|
||||||
|
return switch (asset_type) {
|
||||||
|
.texture => Texture,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
fn assetTypeFromType(comptime T: type) type {
|
||||||
|
return switch (T) {
|
||||||
|
Texture => AssetTexture,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
}
|
8
src/c.zig
Normal file
8
src/c.zig
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
pub usingnamespace @cImport({
|
||||||
|
@cDefine("STBI_NO_GIF", "1");
|
||||||
|
@cDefine("STBI_NO_JPEG", "1");
|
||||||
|
@cDefine("STBI_NO_HDR", "1");
|
||||||
|
@cDefine("STBI_NO_TGA", "1");
|
||||||
|
@cDefine("STB_IMAGE_IMPLEMENTATION", "1");
|
||||||
|
@cInclude("stb_image.h");
|
||||||
|
});
|
@@ -51,8 +51,12 @@ pub fn Storage(comptime T: type, comptime options: StorageOptions) type {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
pub fn free(self: *Self, key: Key) bool {
|
pub fn free(self: *Self, key: Key) ?*T {
|
||||||
self.components.items[key.cell].count -= 1;
|
self.components.items[key.cell].count -= 1;
|
||||||
|
if (self.components.items[key.cell].count == 0) {
|
||||||
|
return &self.components.items[key.cell].component;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
pub fn iter(self: *Self) Iterator {
|
pub fn iter(self: *Self) Iterator {
|
||||||
return .{
|
return .{
|
||||||
|
@@ -14,3 +14,7 @@ const FileError = std.mem.Allocator.Error || std.fs.File.OpenError || std.fs.Fil
|
|||||||
pub fn file(err: FileError, path: []const u8) noreturn {
|
pub fn file(err: FileError, path: []const u8) noreturn {
|
||||||
std.debug.panic("Error while reading \"{s}\": {any}", .{ path, err });
|
std.debug.panic("Error while reading \"{s}\": {any}", .{ path, err });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stbi() noreturn {
|
||||||
|
std.debug.panic("STBI error!\n", .{});
|
||||||
|
}
|
||||||
|
@@ -5,6 +5,7 @@ const err = @import("error.zig");
|
|||||||
const Mouse = @import("mouse.zig");
|
const Mouse = @import("mouse.zig");
|
||||||
const Keyboard = @import("keyboard.zig");
|
const Keyboard = @import("keyboard.zig");
|
||||||
|
|
||||||
|
pub const Assets = @import("assets.zig");
|
||||||
pub const Graphics = @import("graphics.zig");
|
pub const Graphics = @import("graphics.zig");
|
||||||
pub const World = @import("world.zig");
|
pub const World = @import("world.zig");
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ pub fn init(game_alloc: std.mem.Allocator) void {
|
|||||||
Game.keyboard = .{};
|
Game.keyboard = .{};
|
||||||
Game.mouse = .{ .x = 0, .y = 0, .dx = 0, .dy = 0 };
|
Game.mouse = .{ .x = 0, .y = 0, .dx = 0, .dy = 0 };
|
||||||
Graphics.create();
|
Graphics.create();
|
||||||
|
Assets.init();
|
||||||
World.initDebug();
|
World.initDebug();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +116,7 @@ fn processEvents() void {
|
|||||||
|
|
||||||
pub fn deinit() void {
|
pub fn deinit() void {
|
||||||
World.deinit();
|
World.deinit();
|
||||||
|
Assets.deinit();
|
||||||
Graphics.destroy();
|
Graphics.destroy();
|
||||||
sdl.Quit();
|
sdl.Quit();
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ const std = @import("std");
|
|||||||
const sdl = @import("sdl");
|
const sdl = @import("sdl");
|
||||||
const err = @import("error.zig");
|
const err = @import("error.zig");
|
||||||
const presets = @import("graphics/presets.zig");
|
const presets = @import("graphics/presets.zig");
|
||||||
|
const Assets = @import("assets.zig");
|
||||||
|
|
||||||
pub const Transform = @import("graphics/transform.zig");
|
pub const Transform = @import("graphics/transform.zig");
|
||||||
pub const Camera = @import("graphics/camera.zig");
|
pub const Camera = @import("graphics/camera.zig");
|
||||||
@@ -11,11 +12,6 @@ pub const Mesh = struct {
|
|||||||
vertex_count: usize,
|
vertex_count: usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Texture = struct {
|
|
||||||
texture: *sdl.GPUTexture,
|
|
||||||
sampler: *sdl.GPUSampler,
|
|
||||||
};
|
|
||||||
|
|
||||||
var window: *sdl.Window = undefined;
|
var window: *sdl.Window = undefined;
|
||||||
var renderer: *sdl.Renderer = undefined;
|
var renderer: *sdl.Renderer = undefined;
|
||||||
var device: *sdl.GPUDevice = undefined;
|
var device: *sdl.GPUDevice = undefined;
|
||||||
@@ -45,7 +41,7 @@ var to_resize: ?[2]u32 = null;
|
|||||||
|
|
||||||
const VERTEX_BUFFER_DEFAULT_CAPACITY = 1024;
|
const VERTEX_BUFFER_DEFAULT_CAPACITY = 1024;
|
||||||
const VERTEX_BUFFER_GROWTH_MULTIPLIER = 2;
|
const VERTEX_BUFFER_GROWTH_MULTIPLIER = 2;
|
||||||
const TRANSFER_BUFFER_DEFAULT_CAPACITY = 1024;
|
const TRANSFER_BUFFER_DEFAULT_CAPACITY = 4096;
|
||||||
const BYTES_PER_VERTEX = 5 * 4;
|
const BYTES_PER_VERTEX = 5 * 4;
|
||||||
|
|
||||||
const Graphics = @This();
|
const Graphics = @This();
|
||||||
@@ -193,8 +189,9 @@ pub fn destroy() void {
|
|||||||
sdl.DestroyGPUDevice(Graphics.device);
|
sdl.DestroyGPUDevice(Graphics.device);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn loadTexture(width: u32, height: u32, texture_bytes: []const u8) Texture {
|
pub fn loadTexture(width: u32, height: u32, texture_bytes: []const u8) struct { *sdl.GPUTexture, *sdl.GPUSampler } {
|
||||||
const target_format = sdl.SDL_GetGPUSwapchainTextureFormat(Graphics.device, Graphics.window);
|
// const target_format = sdl.SDL_GetGPUSwapchainTextureFormat(Graphics.device, Graphics.window);
|
||||||
|
const target_format = sdl.GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
||||||
|
|
||||||
const texture = sdl.CreateGPUTexture(Graphics.device, &sdl.GPUTextureCreateInfo{
|
const texture = sdl.CreateGPUTexture(Graphics.device, &sdl.GPUTextureCreateInfo{
|
||||||
.format = target_format,
|
.format = target_format,
|
||||||
@@ -242,15 +239,15 @@ pub fn loadTexture(width: u32, height: u32, texture_bytes: []const u8) Texture {
|
|||||||
.min_filter = sdl.GPU_FILTER_LINEAR,
|
.min_filter = sdl.GPU_FILTER_LINEAR,
|
||||||
}) orelse err.sdl();
|
}) orelse err.sdl();
|
||||||
|
|
||||||
return Texture{
|
return .{
|
||||||
.texture = texture,
|
texture,
|
||||||
.sampler = sampler,
|
sampler,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unloadTexture(texture: Texture) void {
|
pub fn unloadTexture(texture: *sdl.GPUTexture, sampler: *sdl.GPUSampler) void {
|
||||||
sdl.ReleaseGPUSampler(Graphics.device, texture.sampler);
|
sdl.ReleaseGPUSampler(Graphics.device, sampler);
|
||||||
sdl.ReleaseGPUTexture(Graphics.device, texture.texture);
|
sdl.ReleaseGPUTexture(Graphics.device, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn loadMesh(mesh_bytes: []const u8) Mesh {
|
pub fn loadMesh(mesh_bytes: []const u8) Mesh {
|
||||||
@@ -388,13 +385,14 @@ pub fn beginDraw() bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawMesh(mesh: Mesh, texture: Texture, transform: Transform) void {
|
pub fn drawMesh(mesh: Mesh, texture: Assets.Texture, transform: Transform) void {
|
||||||
if (Graphics.render_pass == null) return;
|
if (Graphics.render_pass == null) return;
|
||||||
|
const asset_texture = Assets.get(texture) orelse return;
|
||||||
|
|
||||||
sdl.PushGPUVertexUniformData(Graphics.command_buffer, 1, &transform.matrix(), 16 * 4);
|
sdl.PushGPUVertexUniformData(Graphics.command_buffer, 1, &transform.matrix(), 16 * 4);
|
||||||
sdl.BindGPUFragmentSamplers(Graphics.render_pass, 0, &sdl.GPUTextureSamplerBinding{
|
sdl.BindGPUFragmentSamplers(Graphics.render_pass, 0, &sdl.GPUTextureSamplerBinding{
|
||||||
.texture = texture.texture,
|
.texture = asset_texture.texture,
|
||||||
.sampler = texture.sampler,
|
.sampler = asset_texture.sampler,
|
||||||
}, 1);
|
}, 1);
|
||||||
sdl.DrawGPUPrimitives(Graphics.render_pass, @intCast(mesh.vertex_count), 1, @intCast(mesh.vertex_start), 0);
|
sdl.DrawGPUPrimitives(Graphics.render_pass, @intCast(mesh.vertex_count), 1, @intCast(mesh.vertex_start), 0);
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
const Graphics = @import("graphics.zig");
|
const Graphics = @import("graphics.zig");
|
||||||
|
const Assets = @import("assets.zig");
|
||||||
const Entity = @import("entity.zig");
|
const Entity = @import("entity.zig");
|
||||||
const Time = @import("time.zig");
|
const Time = @import("time.zig");
|
||||||
const comp = @import("components.zig");
|
const comp = @import("components.zig");
|
||||||
@@ -9,7 +10,7 @@ var entities: comp.Storage(Entity, .{}) = undefined;
|
|||||||
|
|
||||||
pub var plane_mesh: Graphics.Mesh = undefined;
|
pub var plane_mesh: Graphics.Mesh = undefined;
|
||||||
pub var cube_mesh: Graphics.Mesh = undefined;
|
pub var cube_mesh: Graphics.Mesh = undefined;
|
||||||
pub var texture: Graphics.Texture = undefined;
|
pub var texture: Assets.Texture = undefined;
|
||||||
|
|
||||||
const World = @This();
|
const World = @This();
|
||||||
pub fn initDebug() void {
|
pub fn initDebug() void {
|
||||||
@@ -35,13 +36,13 @@ pub fn initDebug() void {
|
|||||||
time = Time.ZERO;
|
time = Time.ZERO;
|
||||||
World.plane_mesh = Graphics.loadMesh(@ptrCast(&PLANE_MESH_DATA));
|
World.plane_mesh = Graphics.loadMesh(@ptrCast(&PLANE_MESH_DATA));
|
||||||
World.cube_mesh = Graphics.loadMesh(@ptrCast(&CUBE_MESH_DATA));
|
World.cube_mesh = Graphics.loadMesh(@ptrCast(&CUBE_MESH_DATA));
|
||||||
World.texture = Graphics.loadTexture(2, 2, @ptrCast(&TEXTURE_DATA));
|
World.texture = Assets.load(.texture, "data/wawa.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit() void {
|
pub fn deinit() void {
|
||||||
Graphics.unloadMesh(World.plane_mesh);
|
Graphics.unloadMesh(World.plane_mesh);
|
||||||
Graphics.unloadMesh(World.cube_mesh);
|
Graphics.unloadMesh(World.cube_mesh);
|
||||||
Graphics.unloadTexture(World.texture);
|
Assets.free(World.texture);
|
||||||
World.entities.deinit();
|
World.entities.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,30 +100,35 @@ const CUBE_MESH_DATA = [_]f32{
|
|||||||
0.5, -0.5, -0.5, 0.0, 0.0,
|
0.5, -0.5, -0.5, 0.0, 0.0,
|
||||||
-0.5, -0.5, -0.5, 0.0, 0.0,
|
-0.5, -0.5, -0.5, 0.0, 0.0,
|
||||||
0.5, 0.5, -0.5, 0.0, 0.0,
|
0.5, 0.5, -0.5, 0.0, 0.0,
|
||||||
|
|
||||||
0.5, 0.5, -0.5, 0.0, 0.0,
|
0.5, 0.5, -0.5, 0.0, 0.0,
|
||||||
0.5, 0.5, 0.5, 0.0, 0.0,
|
0.5, 0.5, 0.5, 0.0, 0.0,
|
||||||
0.5, -0.5, -0.5, 0.0, 0.0,
|
0.5, -0.5, -0.5, 0.0, 0.0,
|
||||||
0.5, -0.5, 0.5, 0.0, 0.0,
|
0.5, -0.5, 0.5, 0.0, 0.0,
|
||||||
0.5, -0.5, -0.5, 0.0, 0.0,
|
0.5, -0.5, -0.5, 0.0, 0.0,
|
||||||
0.5, 0.5, 0.5, 0.0, 0.0,
|
0.5, 0.5, 0.5, 0.0, 0.0,
|
||||||
0.5, 0.5, 0.5, 0.0, 0.0,
|
|
||||||
|
0.5, 0.5, 0.5, 1.0, 0.0,
|
||||||
-0.5, 0.5, 0.5, 0.0, 0.0,
|
-0.5, 0.5, 0.5, 0.0, 0.0,
|
||||||
0.5, -0.5, 0.5, 0.0, 0.0,
|
0.5, -0.5, 0.5, 1.0, 1.0,
|
||||||
-0.5, -0.5, 0.5, 0.0, 0.0,
|
-0.5, -0.5, 0.5, 0.0, 1.0,
|
||||||
0.5, -0.5, 0.5, 0.0, 0.0,
|
0.5, -0.5, 0.5, 1.0, 1.0,
|
||||||
-0.5, 0.5, 0.5, 0.0, 0.0,
|
-0.5, 0.5, 0.5, 0.0, 0.0,
|
||||||
|
|
||||||
-0.5, 0.5, 0.5, 0.0, 0.0,
|
-0.5, 0.5, 0.5, 0.0, 0.0,
|
||||||
-0.5, 0.5, -0.5, 0.0, 0.0,
|
-0.5, 0.5, -0.5, 0.0, 0.0,
|
||||||
-0.5, -0.5, 0.5, 0.0, 0.0,
|
-0.5, -0.5, 0.5, 0.0, 0.0,
|
||||||
-0.5, -0.5, -0.5, 0.0, 0.0,
|
-0.5, -0.5, -0.5, 0.0, 0.0,
|
||||||
-0.5, -0.5, 0.5, 0.0, 0.0,
|
-0.5, -0.5, 0.5, 0.0, 0.0,
|
||||||
-0.5, 0.5, -0.5, 0.0, 0.0,
|
-0.5, 0.5, -0.5, 0.0, 0.0,
|
||||||
|
|
||||||
-0.5, 0.5, 0.5, 0.0, 0.0,
|
-0.5, 0.5, 0.5, 0.0, 0.0,
|
||||||
0.5, 0.5, 0.5, 0.0, 0.0,
|
0.5, 0.5, 0.5, 0.0, 0.0,
|
||||||
-0.5, 0.5, -0.5, 0.0, 0.0,
|
-0.5, 0.5, -0.5, 0.0, 0.0,
|
||||||
0.5, 0.5, -0.5, 0.0, 0.0,
|
0.5, 0.5, -0.5, 0.0, 0.0,
|
||||||
-0.5, 0.5, -0.5, 0.0, 0.0,
|
-0.5, 0.5, -0.5, 0.0, 0.0,
|
||||||
0.5, 0.5, 0.5, 0.0, 0.0,
|
0.5, 0.5, 0.5, 0.0, 0.0,
|
||||||
|
|
||||||
-0.5, -0.5, -0.5, 0.0, 0.0,
|
-0.5, -0.5, -0.5, 0.0, 0.0,
|
||||||
0.5, -0.5, -0.5, 0.0, 0.0,
|
0.5, -0.5, -0.5, 0.0, 0.0,
|
||||||
-0.5, -0.5, 0.5, 0.0, 0.0,
|
-0.5, -0.5, 0.5, 0.0, 0.0,
|
||||||
|
Reference in New Issue
Block a user