Texture loading
This commit is contained in:
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;
|
||||
}
|
||||
pub fn free(self: *Self, key: Key) bool {
|
||||
pub fn free(self: *Self, key: Key) ?*T {
|
||||
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 {
|
||||
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 {
|
||||
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 Keyboard = @import("keyboard.zig");
|
||||
|
||||
pub const Assets = @import("assets.zig");
|
||||
pub const Graphics = @import("graphics.zig");
|
||||
pub const World = @import("world.zig");
|
||||
|
||||
@@ -28,6 +29,7 @@ pub fn init(game_alloc: std.mem.Allocator) void {
|
||||
Game.keyboard = .{};
|
||||
Game.mouse = .{ .x = 0, .y = 0, .dx = 0, .dy = 0 };
|
||||
Graphics.create();
|
||||
Assets.init();
|
||||
World.initDebug();
|
||||
}
|
||||
|
||||
@@ -114,6 +116,7 @@ fn processEvents() void {
|
||||
|
||||
pub fn deinit() void {
|
||||
World.deinit();
|
||||
Assets.deinit();
|
||||
Graphics.destroy();
|
||||
sdl.Quit();
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ const std = @import("std");
|
||||
const sdl = @import("sdl");
|
||||
const err = @import("error.zig");
|
||||
const presets = @import("graphics/presets.zig");
|
||||
const Assets = @import("assets.zig");
|
||||
|
||||
pub const Transform = @import("graphics/transform.zig");
|
||||
pub const Camera = @import("graphics/camera.zig");
|
||||
@@ -11,11 +12,6 @@ pub const Mesh = struct {
|
||||
vertex_count: usize,
|
||||
};
|
||||
|
||||
pub const Texture = struct {
|
||||
texture: *sdl.GPUTexture,
|
||||
sampler: *sdl.GPUSampler,
|
||||
};
|
||||
|
||||
var window: *sdl.Window = undefined;
|
||||
var renderer: *sdl.Renderer = 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_GROWTH_MULTIPLIER = 2;
|
||||
const TRANSFER_BUFFER_DEFAULT_CAPACITY = 1024;
|
||||
const TRANSFER_BUFFER_DEFAULT_CAPACITY = 4096;
|
||||
const BYTES_PER_VERTEX = 5 * 4;
|
||||
|
||||
const Graphics = @This();
|
||||
@@ -193,8 +189,9 @@ pub fn destroy() void {
|
||||
sdl.DestroyGPUDevice(Graphics.device);
|
||||
}
|
||||
|
||||
pub fn loadTexture(width: u32, height: u32, texture_bytes: []const u8) Texture {
|
||||
const target_format = sdl.SDL_GetGPUSwapchainTextureFormat(Graphics.device, Graphics.window);
|
||||
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.GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
const texture = sdl.CreateGPUTexture(Graphics.device, &sdl.GPUTextureCreateInfo{
|
||||
.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,
|
||||
}) orelse err.sdl();
|
||||
|
||||
return Texture{
|
||||
.texture = texture,
|
||||
.sampler = sampler,
|
||||
return .{
|
||||
texture,
|
||||
sampler,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn unloadTexture(texture: Texture) void {
|
||||
sdl.ReleaseGPUSampler(Graphics.device, texture.sampler);
|
||||
sdl.ReleaseGPUTexture(Graphics.device, texture.texture);
|
||||
pub fn unloadTexture(texture: *sdl.GPUTexture, sampler: *sdl.GPUSampler) void {
|
||||
sdl.ReleaseGPUSampler(Graphics.device, sampler);
|
||||
sdl.ReleaseGPUTexture(Graphics.device, texture);
|
||||
}
|
||||
|
||||
pub fn loadMesh(mesh_bytes: []const u8) Mesh {
|
||||
@@ -388,13 +385,14 @@ pub fn beginDraw() bool {
|
||||
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;
|
||||
const asset_texture = Assets.get(texture) orelse return;
|
||||
|
||||
sdl.PushGPUVertexUniformData(Graphics.command_buffer, 1, &transform.matrix(), 16 * 4);
|
||||
sdl.BindGPUFragmentSamplers(Graphics.render_pass, 0, &sdl.GPUTextureSamplerBinding{
|
||||
.texture = texture.texture,
|
||||
.sampler = texture.sampler,
|
||||
.texture = asset_texture.texture,
|
||||
.sampler = asset_texture.sampler,
|
||||
}, 1);
|
||||
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 Assets = @import("assets.zig");
|
||||
const Entity = @import("entity.zig");
|
||||
const Time = @import("time.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 cube_mesh: Graphics.Mesh = undefined;
|
||||
pub var texture: Graphics.Texture = undefined;
|
||||
pub var texture: Assets.Texture = undefined;
|
||||
|
||||
const World = @This();
|
||||
pub fn initDebug() void {
|
||||
@@ -35,13 +36,13 @@ pub fn initDebug() void {
|
||||
time = Time.ZERO;
|
||||
World.plane_mesh = Graphics.loadMesh(@ptrCast(&PLANE_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 {
|
||||
Graphics.unloadMesh(World.plane_mesh);
|
||||
Graphics.unloadMesh(World.cube_mesh);
|
||||
Graphics.unloadTexture(World.texture);
|
||||
Assets.free(World.texture);
|
||||
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, 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, 0.0, 0.0,
|
||||
0.5, -0.5, 0.5, 1.0, 1.0,
|
||||
-0.5, -0.5, 0.5, 0.0, 1.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,
|
||||
|
Reference in New Issue
Block a user