Compare commits
7 Commits
f836ab8b20
...
tabletop
Author | SHA1 | Date | |
---|---|---|---|
|
0658c2fdfa | ||
|
9d3a98b2d9 | ||
|
49267e629f | ||
|
640e7bed86 | ||
|
fc6ebb73b8 | ||
|
c59d833542 | ||
|
9933a956c2 |
8
.ignore
8
.ignore
@@ -1,5 +1,5 @@
|
|||||||
/data/**.png
|
/data/**/*.png
|
||||||
/data/**.bin
|
/data/**/*.bin
|
||||||
/data/**.blend
|
/data/**/*.blend
|
||||||
/data/**.blend1
|
/data/**/*.blend1
|
||||||
/.git
|
/.git
|
||||||
|
39
build.zig
39
build.zig
@@ -6,6 +6,10 @@ const SHADERS: []const []const u8 = &.{
|
|||||||
"data/shaders/basic.vert",
|
"data/shaders/basic.vert",
|
||||||
"data/shaders/basic.frag",
|
"data/shaders/basic.frag",
|
||||||
};
|
};
|
||||||
|
const SDL_LIBS: []const []const u8 = &.{
|
||||||
|
"SDL3",
|
||||||
|
"SDL3_image",
|
||||||
|
};
|
||||||
|
|
||||||
pub fn build(b: *Build) void {
|
pub fn build(b: *Build) void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
@@ -56,16 +60,16 @@ fn stepBuildClient(
|
|||||||
) *Build.Step.Compile {
|
) *Build.Step.Compile {
|
||||||
const exe = b.addExecutable(.{
|
const exe = b.addExecutable(.{
|
||||||
.name = "tabletop_client",
|
.name = "tabletop_client",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
.root_source_file = b.path("src/client.zig"),
|
.root_source_file = b.path("src/client.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
exe.root_module.addImport("sdl", sdl_module);
|
exe.root_module.addImport("sdl", sdl_module);
|
||||||
exe.step.dependOn(sdl_step);
|
exe.step.dependOn(sdl_step);
|
||||||
|
|
||||||
exe.addIncludePath(b.path("lib/clibs"));
|
|
||||||
|
|
||||||
return exe;
|
return exe;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,9 +80,11 @@ fn stepBuildServer(
|
|||||||
) *Build.Step.Compile {
|
) *Build.Step.Compile {
|
||||||
const exe = b.addExecutable(.{
|
const exe = b.addExecutable(.{
|
||||||
.name = "tabletop_server",
|
.name = "tabletop_server",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
.root_source_file = b.path("src/server.zig"),
|
.root_source_file = b.path("src/server.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
return exe;
|
return exe;
|
||||||
@@ -93,16 +99,16 @@ fn stepBuildOffline(
|
|||||||
) *Build.Step.Compile {
|
) *Build.Step.Compile {
|
||||||
const exe = b.addExecutable(.{
|
const exe = b.addExecutable(.{
|
||||||
.name = "tabletop",
|
.name = "tabletop",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
.root_source_file = b.path("src/offline.zig"),
|
.root_source_file = b.path("src/offline.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
exe.root_module.addImport("sdl", sdl_module);
|
exe.root_module.addImport("sdl", sdl_module);
|
||||||
exe.step.dependOn(sdl_step);
|
exe.step.dependOn(sdl_step);
|
||||||
|
|
||||||
exe.addIncludePath(b.path("lib/clibs"));
|
|
||||||
|
|
||||||
return exe;
|
return exe;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,11 +118,15 @@ fn stepBuildSdlTranslator(
|
|||||||
) *Build.Step.Compile {
|
) *Build.Step.Compile {
|
||||||
const sdl_translator = b.addExecutable(.{
|
const sdl_translator = b.addExecutable(.{
|
||||||
.name = "sdl_header_translator",
|
.name = "sdl_header_translator",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
.root_source_file = b.path("utils/sdl_translator.zig"),
|
.root_source_file = b.path("utils/sdl_translator.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = .Debug,
|
.optimize = .Debug,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
sdl_translator.linkSystemLibrary("SDL3");
|
for (SDL_LIBS) |lib| {
|
||||||
|
sdl_translator.linkSystemLibrary(lib);
|
||||||
|
}
|
||||||
return sdl_translator;
|
return sdl_translator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,20 +148,25 @@ fn stepSdlModule(
|
|||||||
target: Build.ResolvedTarget,
|
target: Build.ResolvedTarget,
|
||||||
optimize: std.builtin.OptimizeMode,
|
optimize: std.builtin.OptimizeMode,
|
||||||
) struct { *Build.Module, *Build.Step } {
|
) struct { *Build.Module, *Build.Step } {
|
||||||
const sdl_module = b.addModule("sdl", .{
|
const translate_sdl_step, const sdl_rename = stepTranslateSdl(b, target);
|
||||||
.root_source_file = b.path("lib/sdl.zig"),
|
|
||||||
|
const translate_c = b.addTranslateC(.{
|
||||||
|
.root_source_file = b.path("lib/sdl.h"),
|
||||||
.link_libc = true,
|
.link_libc = true,
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
sdl_module.linkSystemLibrary("SDL3", .{});
|
translate_c.addIncludePath(sdl_rename.dirname());
|
||||||
|
const translate_module = translate_c.createModule();
|
||||||
|
for (SDL_LIBS) |lib| {
|
||||||
|
translate_module.linkSystemLibrary(lib, .{ .needed = true });
|
||||||
|
}
|
||||||
|
|
||||||
const translate_step, const sdl_rename = stepTranslateSdl(b, target);
|
translate_c.step.dependOn(translate_sdl_step);
|
||||||
sdl_module.addIncludePath(sdl_rename.dirname());
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
sdl_module,
|
translate_module,
|
||||||
translate_step,
|
&translate_c.step,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,6 +13,6 @@ layout(set = 1, binding = 1) uniform Object{
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = vec4(inCoord, 1.0) * object.transform * camera.transform;
|
gl_Position = vec4(inCoord, 1.0) * object.transform * camera.transform;
|
||||||
gl_ClipDistance[0] = gl_Position.z;
|
gl_ClipDistance[0] = gl_Position.w - gl_Position.z;
|
||||||
outUV = inUV;
|
outUV = inUV;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
3
lib/sdl.h
Normal file
3
lib/sdl.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#include "SDL3/SDL.h"
|
||||||
|
#include "SDL3_image/SDL_image.h"
|
||||||
|
#include "sdl_rename.h"
|
@@ -1,4 +0,0 @@
|
|||||||
pub usingnamespace @cImport({
|
|
||||||
@cInclude("SDL3/SDL.h");
|
|
||||||
@cInclude("sdl_rename.h");
|
|
||||||
});
|
|
@@ -56,6 +56,7 @@ pub const LoadError = error{
|
|||||||
ParsingError,
|
ParsingError,
|
||||||
SdlError,
|
SdlError,
|
||||||
FileTooBig,
|
FileTooBig,
|
||||||
|
UnsupportedAsset,
|
||||||
} || std.mem.Allocator.Error || std.fs.File.OpenError || std.fs.File.ReadError || std.json.ParseError(std.json.Scanner);
|
} || std.mem.Allocator.Error || std.fs.File.OpenError || std.fs.File.ReadError || std.json.ParseError(std.json.Scanner);
|
||||||
|
|
||||||
pub const AssetType = enum {
|
pub const AssetType = enum {
|
||||||
@@ -123,7 +124,7 @@ pub fn AssetContainer(comptime T: type) type {
|
|||||||
self.last_state = self.asset_pointer.state;
|
self.last_state = self.asset_pointer.state;
|
||||||
}
|
}
|
||||||
if (self.last_state == .loaded) {
|
if (self.last_state == .loaded) {
|
||||||
self.data_pointer = @alignCast(@ptrCast(self.asset_pointer.data));
|
self.data_pointer = @ptrCast(@alignCast(self.asset_pointer.data));
|
||||||
return self.data_pointer;
|
return self.data_pointer;
|
||||||
} else return null;
|
} else return null;
|
||||||
},
|
},
|
||||||
@@ -150,7 +151,7 @@ pub fn AssetContainer(comptime T: type) type {
|
|||||||
self.last_state = self.asset_pointer.state;
|
self.last_state = self.asset_pointer.state;
|
||||||
}
|
}
|
||||||
if (self.last_state == .loaded) {
|
if (self.last_state == .loaded) {
|
||||||
self.data_pointer = @alignCast(@ptrCast(self.asset_pointer.data));
|
self.data_pointer = @ptrCast(@alignCast(self.asset_pointer.data));
|
||||||
}
|
}
|
||||||
continue :sw self.last_state;
|
continue :sw self.last_state;
|
||||||
},
|
},
|
||||||
@@ -175,6 +176,7 @@ pub fn deinit() void {
|
|||||||
if (worker.thread == null) continue;
|
if (worker.thread == null) continue;
|
||||||
worker.thread.?.join();
|
worker.thread.?.join();
|
||||||
}
|
}
|
||||||
|
updateFree();
|
||||||
var iter = Assets.asset_map.valueIterator();
|
var iter = Assets.asset_map.valueIterator();
|
||||||
while (iter.next()) |asset| {
|
while (iter.next()) |asset| {
|
||||||
std.debug.assert(asset.*.counter == 0);
|
std.debug.assert(asset.*.counter == 0);
|
||||||
@@ -203,22 +205,28 @@ pub fn update() void {
|
|||||||
Assets.next_worker_update = 0;
|
Assets.next_worker_update = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Assets.free_board_mutex.lock();
|
updateFree();
|
||||||
defer Assets.free_board_mutex.unlock();
|
}
|
||||||
if (Assets.free_board.items.len == 0) return;
|
|
||||||
|
|
||||||
|
fn updateFree() void {
|
||||||
// TODO: Delegate freeing to worker threads?
|
// TODO: Delegate freeing to worker threads?
|
||||||
Assets.asset_map_mutex.lock();
|
Assets.asset_map_mutex.lock();
|
||||||
defer Assets.asset_map_mutex.unlock();
|
defer Assets.asset_map_mutex.unlock();
|
||||||
|
|
||||||
|
Assets.free_board_mutex.lock();
|
||||||
while (Assets.free_board.pop()) |request| {
|
while (Assets.free_board.pop()) |request| {
|
||||||
if (@atomicLoad(usize, &request.counter, .monotonic) == 0) {
|
if (@atomicLoad(usize, &request.counter, .monotonic) == 0) {
|
||||||
if (!Assets.asset_map.remove(.{ .type = request.type, .path = request.path })) continue;
|
if (!Assets.asset_map.remove(.{ .type = request.type, .path = request.path })) continue;
|
||||||
if (request.state == .loaded)
|
if (request.state == .loaded) {
|
||||||
|
Assets.free_board_mutex.unlock();
|
||||||
request.unload(Game.alloc);
|
request.unload(Game.alloc);
|
||||||
|
Assets.free_board_mutex.lock();
|
||||||
|
}
|
||||||
Game.alloc.free(request.path);
|
Game.alloc.free(request.path);
|
||||||
Game.alloc.destroy(request);
|
Game.alloc.destroy(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Assets.free_board_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(comptime asset_type: AssetType, path: []const u8) AssetContainer(asset_type.getType()) {
|
pub fn load(comptime asset_type: AssetType, path: []const u8) AssetContainer(asset_type.getType()) {
|
||||||
@@ -298,8 +306,8 @@ fn makeLoader(comptime T: type, comptime func: *const fn ([]const u8, std.mem.Al
|
|||||||
fn makeUnloader(comptime T: type, comptime func: *const fn (T, std.mem.Allocator) void) *const fn (*AssetCell, std.mem.Allocator) void {
|
fn makeUnloader(comptime T: type, comptime func: *const fn (T, std.mem.Allocator) void) *const fn (*AssetCell, std.mem.Allocator) void {
|
||||||
const Container = struct {
|
const Container = struct {
|
||||||
pub fn unloader(cell: *AssetCell, alloc: std.mem.Allocator) void {
|
pub fn unloader(cell: *AssetCell, alloc: std.mem.Allocator) void {
|
||||||
func(@as(*T, @alignCast(@ptrCast(cell.data))).*, alloc);
|
func(@as(*T, @ptrCast(@alignCast(cell.data))).*, alloc);
|
||||||
alloc.destroy(@as(*T, @alignCast(@ptrCast(cell.data))));
|
alloc.destroy(@as(*T, @ptrCast(@alignCast(cell.data))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return Container.unloader;
|
return Container.unloader;
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const sdl = @import("sdl");
|
const sdl = @import("sdl");
|
||||||
const err = @import("../error.zig");
|
const err = @import("../error.zig");
|
||||||
const c = @import("../c.zig");
|
|
||||||
const Assets = @import("../assets.zig");
|
const Assets = @import("../assets.zig");
|
||||||
const Graphics = @import("../graphics.zig");
|
const Graphics = @import("../graphics.zig");
|
||||||
|
|
||||||
@@ -14,20 +13,15 @@ pub fn load(path: []const u8, alloc: std.mem.Allocator) Assets.LoadError!@This()
|
|||||||
defer Assets.free(file);
|
defer Assets.free(file);
|
||||||
const data = (file.getSync() catch return error.DependencyError).bytes;
|
const data = (file.getSync() catch return error.DependencyError).bytes;
|
||||||
|
|
||||||
var width: u32 = undefined;
|
const image: *sdl.Surface = @ptrCast(sdl.IMG_Load_IO(sdl.IOFromConstMem(data.ptr, data.len), true) orelse return error.ParsingError);
|
||||||
var height: u32 = undefined;
|
defer sdl.DestroySurface(image);
|
||||||
var channels: u32 = undefined;
|
const format = image.format;
|
||||||
const image = c.stbi_load_from_memory(
|
|
||||||
@ptrCast(data),
|
const width: u32 = @intCast(image.w);
|
||||||
@intCast(data.len),
|
const height: u32 = @intCast(image.h);
|
||||||
@ptrCast(&width),
|
const channels: u32 = 4;
|
||||||
@ptrCast(&height),
|
|
||||||
@ptrCast(&channels),
|
const image_slice = @as([*]u8, @ptrCast(image.pixels))[0..@intCast(width * height * channels)];
|
||||||
4,
|
|
||||||
);
|
|
||||||
if (image == null) return error.ParsingError;
|
|
||||||
defer c.stbi_image_free(image);
|
|
||||||
const image_slice = image[0..@intCast(width * height * channels)];
|
|
||||||
|
|
||||||
if (width > 8192 or height > 8192) return error.FileTooBig;
|
if (width > 8192 or height > 8192) return error.FileTooBig;
|
||||||
|
|
||||||
@@ -35,13 +29,14 @@ pub fn load(path: []const u8, alloc: std.mem.Allocator) Assets.LoadError!@This()
|
|||||||
const bytes_per_pixel = 4;
|
const bytes_per_pixel = 4;
|
||||||
const mip_level = if (std.math.isPowerOfTwo(width) and width == height) @as(u32, Graphics.MIP_LEVEL) else @as(u32, 1);
|
const mip_level = if (std.math.isPowerOfTwo(width) and width == height) @as(u32, Graphics.MIP_LEVEL) else @as(u32, 1);
|
||||||
|
|
||||||
const texture = Graphics.createTexture(
|
const texture = sdl.CreateGPUTexture(Graphics.device, &.{
|
||||||
width,
|
.width = width,
|
||||||
height,
|
.height = height,
|
||||||
target_format,
|
.layer_count_or_depth = 1,
|
||||||
sdl.GPU_TEXTUREUSAGE_SAMPLER | sdl.GPU_TEXTUREUSAGE_COLOR_TARGET,
|
.format = target_format,
|
||||||
mip_level,
|
.usage = sdl.GPU_TEXTUREUSAGE_SAMPLER | sdl.GPU_TEXTUREUSAGE_COLOR_TARGET,
|
||||||
);
|
.num_levels = mip_level,
|
||||||
|
}) orelse err.sdl();
|
||||||
errdefer Graphics.freeTexture(texture);
|
errdefer Graphics.freeTexture(texture);
|
||||||
|
|
||||||
const transfer_buffer_capacity = Graphics.TRANSFER_BUFFER_DEFAULT_CAPACITY;
|
const transfer_buffer_capacity = Graphics.TRANSFER_BUFFER_DEFAULT_CAPACITY;
|
||||||
@@ -63,6 +58,43 @@ pub fn load(path: []const u8, alloc: std.mem.Allocator) Assets.LoadError!@This()
|
|||||||
defer sdl.EndGPUCopyPass(copy_pass);
|
defer sdl.EndGPUCopyPass(copy_pass);
|
||||||
|
|
||||||
const map: [*]u8 = @ptrCast(sdl.MapGPUTransferBuffer(Graphics.device, transfer_buffer, false) orelse err.sdl());
|
const map: [*]u8 = @ptrCast(sdl.MapGPUTransferBuffer(Graphics.device, transfer_buffer, false) orelse err.sdl());
|
||||||
|
var pixel: u32 = rows_uploaded * width * bytes_per_pixel;
|
||||||
|
var mapped: u32 = 0;
|
||||||
|
while (pixel < (rows_uploaded + rows_to_upload) * width * bytes_per_pixel) {
|
||||||
|
defer pixel += bytes_per_pixel;
|
||||||
|
defer mapped += bytes_per_pixel;
|
||||||
|
switch (format) {
|
||||||
|
// Convert to RGBA8888
|
||||||
|
sdl.PIXELFORMAT_ABGR8888 => {
|
||||||
|
map[mapped + 0] = image_slice[pixel + 3];
|
||||||
|
map[mapped + 1] = image_slice[pixel + 2];
|
||||||
|
map[mapped + 2] = image_slice[pixel + 1];
|
||||||
|
map[mapped + 3] = image_slice[pixel + 0];
|
||||||
|
},
|
||||||
|
sdl.PIXELFORMAT_ARGB8888 => {
|
||||||
|
map[mapped + 0] = image_slice[pixel + 1];
|
||||||
|
map[mapped + 1] = image_slice[pixel + 2];
|
||||||
|
map[mapped + 2] = image_slice[pixel + 3];
|
||||||
|
map[mapped + 3] = image_slice[pixel + 0];
|
||||||
|
},
|
||||||
|
sdl.PIXELFORMAT_RGBA8888 => {
|
||||||
|
map[mapped + 0] = image_slice[pixel + 0];
|
||||||
|
map[mapped + 1] = image_slice[pixel + 1];
|
||||||
|
map[mapped + 2] = image_slice[pixel + 2];
|
||||||
|
map[mapped + 3] = image_slice[pixel + 3];
|
||||||
|
},
|
||||||
|
sdl.PIXELFORMAT_BGRA8888 => {
|
||||||
|
map[mapped + 0] = image_slice[pixel + 2];
|
||||||
|
map[mapped + 1] = image_slice[pixel + 1];
|
||||||
|
map[mapped + 2] = image_slice[pixel + 0];
|
||||||
|
map[mapped + 3] = image_slice[pixel + 3];
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
sdl.UnmapGPUTransferBuffer(Graphics.device, transfer_buffer);
|
||||||
|
return error.UnsupportedAsset;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@memcpy(map, image_slice[(rows_uploaded * width * bytes_per_pixel)..((rows_uploaded + rows_to_upload) * width * bytes_per_pixel)]);
|
@memcpy(map, image_slice[(rows_uploaded * width * bytes_per_pixel)..((rows_uploaded + rows_to_upload) * width * bytes_per_pixel)]);
|
||||||
sdl.UnmapGPUTransferBuffer(Graphics.device, transfer_buffer);
|
sdl.UnmapGPUTransferBuffer(Graphics.device, transfer_buffer);
|
||||||
|
|
||||||
|
@@ -1,8 +0,0 @@
|
|||||||
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");
|
|
||||||
});
|
|
@@ -14,7 +14,3 @@ 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", .{});
|
|
||||||
}
|
|
||||||
|
12
src/game.zig
12
src/game.zig
@@ -116,6 +116,18 @@ fn processEvents() void {
|
|||||||
sdl.EVENT_MOUSE_WHEEL => {
|
sdl.EVENT_MOUSE_WHEEL => {
|
||||||
Game.mouse.wheel += event.wheel.integer_y;
|
Game.mouse.wheel += event.wheel.integer_y;
|
||||||
},
|
},
|
||||||
|
sdl.EVENT_WINDOW_RESIZED => {
|
||||||
|
if (event.window.data1 < 1 or event.window.data2 < 1) continue;
|
||||||
|
|
||||||
|
Graphics.window_width = @intCast(event.window.data1);
|
||||||
|
Graphics.window_height = @intCast(event.window.data2);
|
||||||
|
},
|
||||||
|
sdl.EVENT_WINDOW_PIXEL_SIZE_CHANGED => {
|
||||||
|
if (event.window.data1 < 1 or event.window.data2 < 1) continue;
|
||||||
|
|
||||||
|
Graphics.pixel_width = @intCast(event.window.data1);
|
||||||
|
Graphics.pixel_height = @intCast(event.window.data2);
|
||||||
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
286
src/graphics.zig
286
src/graphics.zig
@@ -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 Game = @import("game.zig");
|
||||||
const Assets = @import("assets.zig");
|
const Assets = @import("assets.zig");
|
||||||
|
|
||||||
pub const Transform = @import("graphics/transform.zig");
|
pub const Transform = @import("graphics/transform.zig");
|
||||||
@@ -13,18 +14,22 @@ pub var device: *sdl.GPUDevice = undefined;
|
|||||||
var command_buffer: ?*sdl.GPUCommandBuffer = null;
|
var command_buffer: ?*sdl.GPUCommandBuffer = null;
|
||||||
var render_pass: ?*sdl.GPURenderPass = null;
|
var render_pass: ?*sdl.GPURenderPass = null;
|
||||||
var render_target: ?*sdl.GPUTexture = null;
|
var render_target: ?*sdl.GPUTexture = null;
|
||||||
|
var batches: Batches = undefined;
|
||||||
|
|
||||||
var shader_vert: *sdl.GPUShader = undefined;
|
var shader_vert: *sdl.GPUShader = undefined;
|
||||||
var shader_frag: *sdl.GPUShader = undefined;
|
var shader_frag: *sdl.GPUShader = undefined;
|
||||||
|
|
||||||
var depth_texture: *sdl.GPUTexture = undefined;
|
var depth_texture: *sdl.GPUTexture = undefined;
|
||||||
var fsaa_target: *sdl.GPUTexture = undefined;
|
var antialias: Antialias = undefined;
|
||||||
|
var aa_target: *sdl.GPUTexture = undefined;
|
||||||
var pipeline: *sdl.GPUGraphicsPipeline = undefined;
|
var pipeline: *sdl.GPUGraphicsPipeline = undefined;
|
||||||
|
|
||||||
pub var window_width: u32 = undefined;
|
pub var window_width: u32 = undefined;
|
||||||
pub var window_height: u32 = undefined;
|
pub var window_height: u32 = undefined;
|
||||||
var fsaa_scale: u32 = 4;
|
pub var pixel_width: u32 = undefined;
|
||||||
var fsaa_level: u32 = 3;
|
pub var pixel_height: u32 = undefined;
|
||||||
|
var render_width: u32 = undefined;
|
||||||
|
var render_height: u32 = undefined;
|
||||||
|
|
||||||
pub var camera: Camera = undefined;
|
pub var camera: Camera = undefined;
|
||||||
|
|
||||||
@@ -33,6 +38,53 @@ const DEPTH_FORMAT = sdl.GPU_TEXTUREFORMAT_D32_FLOAT;
|
|||||||
pub const TRANSFER_BUFFER_DEFAULT_CAPACITY = 512 * 1024;
|
pub const TRANSFER_BUFFER_DEFAULT_CAPACITY = 512 * 1024;
|
||||||
pub const MIP_LEVEL = 4;
|
pub const MIP_LEVEL = 4;
|
||||||
|
|
||||||
|
const Antialias = union(enum) {
|
||||||
|
none,
|
||||||
|
msaa: enum(sdl.GPUSampleCount) {
|
||||||
|
@"2" = sdl.GPU_SAMPLECOUNT_2,
|
||||||
|
@"4" = sdl.GPU_SAMPLECOUNT_4,
|
||||||
|
@"8" = sdl.GPU_SAMPLECOUNT_8,
|
||||||
|
},
|
||||||
|
fsaa: enum {
|
||||||
|
@"2",
|
||||||
|
@"4",
|
||||||
|
@"8",
|
||||||
|
},
|
||||||
|
|
||||||
|
pub fn getMsaaSamples(self: @This()) sdl.GPUSampleCount {
|
||||||
|
if (self != .msaa) return sdl.GPU_SAMPLECOUNT_1;
|
||||||
|
return @intFromEnum(self.msaa);
|
||||||
|
}
|
||||||
|
pub fn getFsaaScale(self: @This()) u8 {
|
||||||
|
if (self != .fsaa) return 1;
|
||||||
|
return switch (self.fsaa) {
|
||||||
|
.@"2" => 2,
|
||||||
|
.@"4" => 4,
|
||||||
|
.@"8" => 8,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn getFsaaLevel(self: @This()) u8 {
|
||||||
|
if (self != .fsaa) return 1;
|
||||||
|
return switch (self.fsaa) {
|
||||||
|
.@"2" => 2,
|
||||||
|
.@"4" => 3,
|
||||||
|
.@"8" => 4,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Batch = struct {
|
||||||
|
object: *Assets.Object,
|
||||||
|
transform: Transform,
|
||||||
|
z: f32,
|
||||||
|
|
||||||
|
fn orderLessThan(ctx: void, lhs: Batch, rhs: Batch) bool {
|
||||||
|
_ = ctx;
|
||||||
|
return lhs.z > rhs.z;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const Batches = std.ArrayListUnmanaged(Batch);
|
||||||
|
|
||||||
const Graphics = @This();
|
const Graphics = @This();
|
||||||
pub fn create() void {
|
pub fn create() void {
|
||||||
// Init
|
// Init
|
||||||
@@ -45,8 +97,19 @@ pub fn create() void {
|
|||||||
"",
|
"",
|
||||||
1600,
|
1600,
|
||||||
900,
|
900,
|
||||||
sdl.WINDOW_VULKAN | sdl.WINDOW_RESIZABLE,
|
sdl.WINDOW_VULKAN | sdl.WINDOW_RESIZABLE | sdl.WINDOW_HIGH_PIXEL_DENSITY,
|
||||||
) orelse err.sdl();
|
) orelse err.sdl();
|
||||||
|
if (!sdl.GetWindowSizeInPixels(Graphics.window, @ptrCast(&Graphics.window_width), @ptrCast(&Graphics.window_height))) {
|
||||||
|
Graphics.window_width = 1600;
|
||||||
|
Graphics.window_height = 900;
|
||||||
|
}
|
||||||
|
const scale = sdl.GetWindowDisplayScale(Graphics.window);
|
||||||
|
Graphics.pixel_width = @intFromFloat(@round(scale * @as(f32, @floatFromInt(Graphics.window_width))));
|
||||||
|
Graphics.pixel_height = @intFromFloat(@round(scale * @as(f32, @floatFromInt(Graphics.window_height))));
|
||||||
|
Graphics.render_width = pixel_width;
|
||||||
|
Graphics.render_height = pixel_height;
|
||||||
|
|
||||||
|
Graphics.antialias = .none;
|
||||||
|
|
||||||
// Device
|
// Device
|
||||||
Graphics.device = sdl.CreateGPUDevice(
|
Graphics.device = sdl.CreateGPUDevice(
|
||||||
@@ -81,23 +144,24 @@ pub fn create() void {
|
|||||||
const target_format = sdl.GetGPUSwapchainTextureFormat(Graphics.device, Graphics.window);
|
const target_format = sdl.GetGPUSwapchainTextureFormat(Graphics.device, Graphics.window);
|
||||||
if (target_format == sdl.GPU_TEXTUREFORMAT_INVALID) err.sdl();
|
if (target_format == sdl.GPU_TEXTUREFORMAT_INVALID) err.sdl();
|
||||||
|
|
||||||
// TODO: Clean
|
Graphics.depth_texture = sdl.CreateGPUTexture(device, &.{
|
||||||
if (!sdl.GetWindowSizeInPixels(Graphics.window, @ptrCast(&Graphics.window_width), @ptrCast(&Graphics.window_height))) err.sdl();
|
.width = Graphics.render_width * Graphics.antialias.getFsaaScale(),
|
||||||
|
.height = Graphics.render_height * Graphics.antialias.getFsaaScale(),
|
||||||
Graphics.depth_texture = createTexture(
|
.layer_count_or_depth = 1,
|
||||||
@as(u32, @intCast(Graphics.window_width)) * Graphics.fsaa_scale,
|
.format = DEPTH_FORMAT,
|
||||||
@as(u32, @intCast(Graphics.window_height)) * Graphics.fsaa_scale,
|
.usage = sdl.GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET,
|
||||||
DEPTH_FORMAT,
|
.num_levels = 1,
|
||||||
sdl.GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET,
|
.sample_count = Graphics.antialias.getMsaaSamples(),
|
||||||
1,
|
}) orelse err.sdl();
|
||||||
);
|
Graphics.aa_target = sdl.CreateGPUTexture(device, &.{
|
||||||
Graphics.fsaa_target = createTexture(
|
.width = Graphics.render_width * Graphics.antialias.getFsaaScale(),
|
||||||
@as(u32, @intCast(Graphics.window_width)) * Graphics.fsaa_scale,
|
.height = Graphics.render_height * Graphics.antialias.getFsaaScale(),
|
||||||
@as(u32, @intCast(Graphics.window_height)) * Graphics.fsaa_scale,
|
.layer_count_or_depth = 1,
|
||||||
target_format,
|
.format = target_format,
|
||||||
sdl.GPU_TEXTUREUSAGE_COLOR_TARGET | sdl.GPU_TEXTUREUSAGE_SAMPLER,
|
.usage = if (Graphics.antialias == .fsaa) sdl.GPU_TEXTUREUSAGE_COLOR_TARGET | sdl.GPU_TEXTUREUSAGE_SAMPLER else sdl.GPU_TEXTUREUSAGE_COLOR_TARGET,
|
||||||
fsaa_level,
|
.num_levels = Graphics.antialias.getFsaaLevel(),
|
||||||
);
|
.sample_count = Graphics.antialias.getMsaaSamples(),
|
||||||
|
}) orelse err.sdl();
|
||||||
|
|
||||||
Graphics.pipeline = sdl.CreateGPUGraphicsPipeline(Graphics.device, &.{
|
Graphics.pipeline = sdl.CreateGPUGraphicsPipeline(Graphics.device, &.{
|
||||||
.vertex_shader = Graphics.shader_vert,
|
.vertex_shader = Graphics.shader_vert,
|
||||||
@@ -125,6 +189,9 @@ pub fn create() void {
|
|||||||
},
|
},
|
||||||
.num_vertex_attributes = 2,
|
.num_vertex_attributes = 2,
|
||||||
},
|
},
|
||||||
|
.multisample_state = .{
|
||||||
|
.sample_count = Graphics.antialias.getMsaaSamples(),
|
||||||
|
},
|
||||||
.primitive_type = sdl.GPU_PRIMITIVETYPE_TRIANGLELIST,
|
.primitive_type = sdl.GPU_PRIMITIVETYPE_TRIANGLELIST,
|
||||||
.rasterizer_state = presets.RASTERIZER_CULL,
|
.rasterizer_state = presets.RASTERIZER_CULL,
|
||||||
.depth_stencil_state = presets.DEPTH_ENABLED,
|
.depth_stencil_state = presets.DEPTH_ENABLED,
|
||||||
@@ -139,10 +206,11 @@ pub fn create() void {
|
|||||||
},
|
},
|
||||||
}) orelse err.sdl();
|
}) orelse err.sdl();
|
||||||
|
|
||||||
|
Graphics.batches = Batches.empty;
|
||||||
|
|
||||||
Graphics.camera = Camera{
|
Graphics.camera = Camera{
|
||||||
.transform = .{},
|
.transform = .{},
|
||||||
.near = 1.0 / 16.0,
|
.near = 1.0 / 16.0,
|
||||||
.far = 128.0,
|
|
||||||
.lens = 1.5,
|
.lens = 1.5,
|
||||||
.aspect = 16.0 / 9.0,
|
.aspect = 16.0 / 9.0,
|
||||||
.matrix = undefined,
|
.matrix = undefined,
|
||||||
@@ -154,7 +222,7 @@ pub fn destroy() void {
|
|||||||
sdl.DestroyWindow(Graphics.window);
|
sdl.DestroyWindow(Graphics.window);
|
||||||
|
|
||||||
sdl.ReleaseGPUGraphicsPipeline(Graphics.device, Graphics.pipeline);
|
sdl.ReleaseGPUGraphicsPipeline(Graphics.device, Graphics.pipeline);
|
||||||
sdl.ReleaseGPUTexture(Graphics.device, Graphics.fsaa_target);
|
sdl.ReleaseGPUTexture(Graphics.device, Graphics.aa_target);
|
||||||
sdl.ReleaseGPUTexture(Graphics.device, Graphics.depth_texture);
|
sdl.ReleaseGPUTexture(Graphics.device, Graphics.depth_texture);
|
||||||
|
|
||||||
sdl.ReleaseGPUShader(Graphics.device, Graphics.shader_vert);
|
sdl.ReleaseGPUShader(Graphics.device, Graphics.shader_vert);
|
||||||
@@ -165,6 +233,7 @@ pub fn destroy() void {
|
|||||||
Graphics.command_buffer = null;
|
Graphics.command_buffer = null;
|
||||||
}
|
}
|
||||||
sdl.DestroyGPUDevice(Graphics.device);
|
sdl.DestroyGPUDevice(Graphics.device);
|
||||||
|
Graphics.batches.clearAndFree(Game.alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If window is minimized returns `false`, `render_pass` remains null
|
/// If window is minimized returns `false`, `render_pass` remains null
|
||||||
@@ -178,22 +247,23 @@ pub fn beginDraw() bool {
|
|||||||
// Window is probably hidden
|
// Window is probably hidden
|
||||||
if (Graphics.render_target == null or width == 0 or height == 0) return false;
|
if (Graphics.render_target == null or width == 0 or height == 0) return false;
|
||||||
|
|
||||||
if (width != Graphics.window_width or height != Graphics.window_height) {
|
if (Graphics.render_width != Graphics.pixel_width or Graphics.render_height != Graphics.pixel_height) {
|
||||||
Graphics.resetTextures(width, height);
|
Graphics.render_width = Graphics.pixel_width;
|
||||||
Graphics.camera.aspect = @as(f32, @floatFromInt(width)) / @as(f32, @floatFromInt(height));
|
Graphics.render_height = Graphics.pixel_height;
|
||||||
Graphics.window_width = width;
|
Graphics.resetTextures(Graphics.render_width, Graphics.render_height);
|
||||||
Graphics.window_height = height;
|
Graphics.camera.aspect = @as(f32, @floatFromInt(Graphics.render_width)) / @as(f32, @floatFromInt(Graphics.render_height));
|
||||||
}
|
}
|
||||||
|
|
||||||
Graphics.render_pass = sdl.BeginGPURenderPass(Graphics.command_buffer.?, &.{
|
Graphics.render_pass = sdl.BeginGPURenderPass(Graphics.command_buffer.?, &.{
|
||||||
.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
|
.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
|
||||||
.cycle = false,
|
.cycle = false,
|
||||||
.load_op = sdl.GPU_LOADOP_CLEAR,
|
.load_op = sdl.GPU_LOADOP_DONT_CARE,
|
||||||
.store_op = sdl.GPU_STOREOP_STORE,
|
.store_op = if (Graphics.antialias == .msaa) sdl.GPU_STOREOP_RESOLVE else sdl.GPU_STOREOP_STORE,
|
||||||
.mip_level = 0,
|
.mip_level = 0,
|
||||||
.texture = Graphics.fsaa_target,
|
.texture = if (Graphics.antialias == .fsaa or Graphics.antialias == .msaa) Graphics.aa_target else Graphics.render_target,
|
||||||
|
.resolve_texture = if (Graphics.antialias == .msaa) Graphics.render_target else null,
|
||||||
}, 1, &.{
|
}, 1, &.{
|
||||||
.clear_depth = 1.0,
|
.clear_depth = 0.0,
|
||||||
.load_op = sdl.GPU_LOADOP_CLEAR,
|
.load_op = sdl.GPU_LOADOP_CLEAR,
|
||||||
.store_op = sdl.GPU_STOREOP_DONT_CARE,
|
.store_op = sdl.GPU_STOREOP_DONT_CARE,
|
||||||
.stencil_load_op = sdl.GPU_STOREOP_DONT_CARE,
|
.stencil_load_op = sdl.GPU_STOREOP_DONT_CARE,
|
||||||
@@ -208,34 +278,13 @@ pub fn beginDraw() bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clearDepth() void {
|
fn finishPass() void {
|
||||||
sdl.EndGPURenderPass(Graphics.render_pass.?);
|
std.sort.block(Batch, Graphics.batches.items, {}, Batch.orderLessThan);
|
||||||
|
|
||||||
Graphics.render_pass = sdl.BeginGPURenderPass(Graphics.command_buffer.?, &.{
|
for (Graphics.batches.items) |*batch| {
|
||||||
.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
|
const asset_object = batch.object.get() orelse continue;
|
||||||
.cycle = false,
|
|
||||||
.load_op = sdl.GPU_LOADOP_LOAD,
|
|
||||||
.store_op = sdl.GPU_STOREOP_STORE,
|
|
||||||
.mip_level = 0,
|
|
||||||
.texture = Graphics.fsaa_target,
|
|
||||||
}, 1, &.{
|
|
||||||
.clear_depth = 1.0,
|
|
||||||
.load_op = sdl.GPU_LOADOP_CLEAR,
|
|
||||||
.store_op = sdl.GPU_STOREOP_DONT_CARE,
|
|
||||||
.stencil_load_op = sdl.GPU_STOREOP_DONT_CARE,
|
|
||||||
.stencil_store_op = sdl.GPU_STOREOP_DONT_CARE,
|
|
||||||
.texture = Graphics.depth_texture,
|
|
||||||
}) orelse err.sdl();
|
|
||||||
|
|
||||||
sdl.BindGPUGraphicsPipeline(Graphics.render_pass, Graphics.pipeline);
|
sdl.PushGPUVertexUniformData(Graphics.command_buffer, 1, &batch.transform.matrix(), 16 * 4);
|
||||||
sdl.PushGPUVertexUniformData(Graphics.command_buffer, 0, &Graphics.camera.matrix, 16 * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn drawObject(object: *Assets.Object, transform: Transform) void {
|
|
||||||
if (Graphics.render_pass == null) return;
|
|
||||||
const asset_object = object.get() orelse return;
|
|
||||||
|
|
||||||
sdl.PushGPUVertexUniformData(Graphics.command_buffer, 1, &transform.matrix(), 16 * 4);
|
|
||||||
for (asset_object.nodes) |node| {
|
for (asset_object.nodes) |node| {
|
||||||
const mesh = &asset_object.meshes[node.mesh];
|
const mesh = &asset_object.meshes[node.mesh];
|
||||||
|
|
||||||
@@ -251,25 +300,76 @@ pub fn drawObject(object: *Assets.Object, transform: Transform) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Graphics.batches.clearRetainingCapacity();
|
||||||
|
|
||||||
|
sdl.EndGPURenderPass(Graphics.render_pass.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clearDepth() void {
|
||||||
|
Graphics.finishPass();
|
||||||
|
|
||||||
|
Graphics.render_pass = sdl.BeginGPURenderPass(Graphics.command_buffer.?, &.{
|
||||||
|
.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
|
||||||
|
.cycle = false,
|
||||||
|
.load_op = sdl.GPU_LOADOP_LOAD,
|
||||||
|
.store_op = if (Graphics.antialias == .msaa) sdl.GPU_STOREOP_RESOLVE else sdl.GPU_STOREOP_STORE,
|
||||||
|
.mip_level = 0,
|
||||||
|
.texture = if (Graphics.antialias == .fsaa or Graphics.antialias == .msaa) Graphics.aa_target else Graphics.render_target,
|
||||||
|
.resolve_texture = if (Graphics.antialias == .msaa) Graphics.render_target else null,
|
||||||
|
}, 1, &.{
|
||||||
|
.clear_depth = 0.0,
|
||||||
|
.load_op = sdl.GPU_LOADOP_CLEAR,
|
||||||
|
.store_op = sdl.GPU_STOREOP_DONT_CARE,
|
||||||
|
.stencil_load_op = sdl.GPU_STOREOP_DONT_CARE,
|
||||||
|
.stencil_store_op = sdl.GPU_STOREOP_DONT_CARE,
|
||||||
|
.texture = Graphics.depth_texture,
|
||||||
|
}) orelse err.sdl();
|
||||||
|
|
||||||
|
sdl.BindGPUGraphicsPipeline(Graphics.render_pass, Graphics.pipeline);
|
||||||
|
sdl.PushGPUVertexUniformData(Graphics.command_buffer, 0, &Graphics.camera.matrix, 16 * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `object`: pointer MUST be vaild until current render pass ends
|
||||||
|
pub fn drawObject(object: *Assets.Object, transform: Transform) void {
|
||||||
|
if (Graphics.render_pass == null) return;
|
||||||
|
|
||||||
|
@setFloatMode(.optimized);
|
||||||
|
const z = Graphics.camera.matrix[8] * transform.position[0] +
|
||||||
|
Graphics.camera.matrix[9] * transform.position[1] +
|
||||||
|
Graphics.camera.matrix[10] * transform.position[2] +
|
||||||
|
Graphics.camera.matrix[11];
|
||||||
|
var w = Graphics.camera.matrix[12] * transform.position[0] +
|
||||||
|
Graphics.camera.matrix[13] * transform.position[1] +
|
||||||
|
Graphics.camera.matrix[14] * transform.position[2] +
|
||||||
|
Graphics.camera.matrix[15];
|
||||||
|
if (w == 0) w = 1;
|
||||||
|
|
||||||
|
Graphics.batches.append(Game.alloc, .{
|
||||||
|
.object = object,
|
||||||
|
.transform = transform,
|
||||||
|
.z = z / w,
|
||||||
|
}) catch err.oom();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn endDraw() void {
|
pub fn endDraw() void {
|
||||||
defer Graphics.command_buffer = null;
|
defer Graphics.command_buffer = null;
|
||||||
defer Graphics.render_pass = null;
|
defer Graphics.render_pass = null;
|
||||||
if (Graphics.render_pass) |pass| {
|
|
||||||
sdl.EndGPURenderPass(pass);
|
|
||||||
|
|
||||||
if (Graphics.fsaa_level > 1) sdl.GenerateMipmapsForGPUTexture(Graphics.command_buffer, Graphics.fsaa_target);
|
Graphics.finishPass();
|
||||||
|
|
||||||
|
if (Graphics.antialias == .fsaa) {
|
||||||
|
sdl.GenerateMipmapsForGPUTexture(Graphics.command_buffer, Graphics.aa_target);
|
||||||
sdl.BlitGPUTexture(Graphics.command_buffer, &.{
|
sdl.BlitGPUTexture(Graphics.command_buffer, &.{
|
||||||
.source = .{
|
.source = .{
|
||||||
.texture = Graphics.fsaa_target,
|
.texture = Graphics.aa_target,
|
||||||
.w = Graphics.window_width,
|
.w = Graphics.render_width,
|
||||||
.h = Graphics.window_height,
|
.h = Graphics.render_height,
|
||||||
.mip_level = fsaa_level - 1,
|
.mip_level = Graphics.antialias.getFsaaLevel() - 1,
|
||||||
},
|
},
|
||||||
.destination = .{
|
.destination = .{
|
||||||
.texture = Graphics.render_target,
|
.texture = Graphics.render_target,
|
||||||
.w = Graphics.window_width,
|
.w = Graphics.render_width,
|
||||||
.h = Graphics.window_height,
|
.h = Graphics.render_height,
|
||||||
},
|
},
|
||||||
.load_op = sdl.GPU_LOADOP_DONT_CARE,
|
.load_op = sdl.GPU_LOADOP_DONT_CARE,
|
||||||
.filter = sdl.GPU_FILTER_NEAREST,
|
.filter = sdl.GPU_FILTER_NEAREST,
|
||||||
@@ -282,7 +382,7 @@ fn loadShader(path: []const u8, info: sdl.GPUShaderCreateInfo) *sdl.GPUShader {
|
|||||||
const file = std.fs.cwd().openFile(path, .{}) catch |e| err.file(e, path);
|
const file = std.fs.cwd().openFile(path, .{}) catch |e| err.file(e, path);
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const code = file.readToEndAllocOptions(std.heap.c_allocator, std.math.maxInt(usize), null, 1, 0) catch |e| err.file(e, path);
|
const code = file.readToEndAllocOptions(std.heap.c_allocator, std.math.maxInt(usize), null, .@"1", 0) catch |e| err.file(e, path);
|
||||||
defer std.heap.c_allocator.free(code);
|
defer std.heap.c_allocator.free(code);
|
||||||
|
|
||||||
var updated_info = info;
|
var updated_info = info;
|
||||||
@@ -291,18 +391,6 @@ fn loadShader(path: []const u8, info: sdl.GPUShaderCreateInfo) *sdl.GPUShader {
|
|||||||
return sdl.CreateGPUShader(device, &updated_info) orelse err.sdl();
|
return sdl.CreateGPUShader(device, &updated_info) orelse err.sdl();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createTexture(width: u32, height: u32, format: c_uint, usage: c_uint, mip_level: u32) *sdl.GPUTexture {
|
|
||||||
return sdl.CreateGPUTexture(device, &.{
|
|
||||||
.format = format,
|
|
||||||
.layer_count_or_depth = 1,
|
|
||||||
.width = width,
|
|
||||||
.height = height,
|
|
||||||
.num_levels = mip_level,
|
|
||||||
.sample_count = sdl.GPU_SAMPLECOUNT_1,
|
|
||||||
.usage = usage,
|
|
||||||
}) orelse err.sdl();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn freeTexture(texture: *sdl.GPUTexture) void {
|
pub fn freeTexture(texture: *sdl.GPUTexture) void {
|
||||||
sdl.ReleaseGPUTexture(Graphics.device, texture);
|
sdl.ReleaseGPUTexture(Graphics.device, texture);
|
||||||
}
|
}
|
||||||
@@ -327,24 +415,32 @@ pub fn freeSampler(sampler: *sdl.GPUSampler) void {
|
|||||||
|
|
||||||
fn resetTextures(width: u32, height: u32) void {
|
fn resetTextures(width: u32, height: u32) void {
|
||||||
sdl.ReleaseGPUTexture(Graphics.device, Graphics.depth_texture);
|
sdl.ReleaseGPUTexture(Graphics.device, Graphics.depth_texture);
|
||||||
Graphics.depth_texture = createTexture(
|
Graphics.depth_texture = sdl.CreateGPUTexture(device, &.{
|
||||||
width * Graphics.fsaa_scale,
|
.width = width * Graphics.antialias.getFsaaScale(),
|
||||||
height * Graphics.fsaa_scale,
|
.height = height * Graphics.antialias.getFsaaScale(),
|
||||||
DEPTH_FORMAT,
|
.layer_count_or_depth = 1,
|
||||||
sdl.GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET,
|
.format = DEPTH_FORMAT,
|
||||||
1,
|
.usage = sdl.GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET,
|
||||||
);
|
.num_levels = 1,
|
||||||
|
.sample_count = Graphics.antialias.getMsaaSamples(),
|
||||||
|
}) orelse err.sdl();
|
||||||
|
|
||||||
const target_format = sdl.GetGPUSwapchainTextureFormat(Graphics.device, Graphics.window);
|
const target_format = sdl.GetGPUSwapchainTextureFormat(Graphics.device, Graphics.window);
|
||||||
|
|
||||||
sdl.ReleaseGPUTexture(Graphics.device, Graphics.fsaa_target);
|
sdl.ReleaseGPUTexture(Graphics.device, Graphics.aa_target);
|
||||||
Graphics.fsaa_target = createTexture(
|
Graphics.aa_target = sdl.CreateGPUTexture(device, &.{
|
||||||
width * Graphics.fsaa_scale,
|
.width = width * Graphics.antialias.getFsaaScale(),
|
||||||
height * Graphics.fsaa_scale,
|
.height = height * Graphics.antialias.getFsaaScale(),
|
||||||
target_format,
|
.layer_count_or_depth = 1,
|
||||||
sdl.GPU_TEXTUREUSAGE_COLOR_TARGET | sdl.GPU_TEXTUREUSAGE_SAMPLER,
|
.format = target_format,
|
||||||
fsaa_level,
|
.usage = switch (Graphics.antialias) {
|
||||||
);
|
.none => sdl.GPU_TEXTUREUSAGE_COLOR_TARGET,
|
||||||
|
.fsaa => sdl.GPU_TEXTUREUSAGE_COLOR_TARGET | sdl.GPU_TEXTUREUSAGE_SAMPLER,
|
||||||
|
.msaa => sdl.GPU_TEXTUREUSAGE_COLOR_TARGET,
|
||||||
|
},
|
||||||
|
.num_levels = Graphics.antialias.getFsaaLevel(),
|
||||||
|
.sample_count = Graphics.antialias.getMsaaSamples(),
|
||||||
|
}) orelse err.sdl();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn windowId() sdl.WindowID {
|
pub fn windowId() sdl.WindowID {
|
||||||
|
@@ -8,7 +8,6 @@ transform: Transform,
|
|||||||
/// tangent of the half of the view angle (90 degress = 1 "lens")
|
/// tangent of the half of the view angle (90 degress = 1 "lens")
|
||||||
lens: f32,
|
lens: f32,
|
||||||
near: f32,
|
near: f32,
|
||||||
far: f32,
|
|
||||||
/// width = height * aspect
|
/// width = height * aspect
|
||||||
aspect: f32,
|
aspect: f32,
|
||||||
|
|
||||||
@@ -19,13 +18,10 @@ pub fn computeMatrix(camera: *Camera) void {
|
|||||||
|
|
||||||
const xx = 1.0 / (camera.lens * camera.aspect);
|
const xx = 1.0 / (camera.lens * camera.aspect);
|
||||||
const yy = 1.0 / camera.lens;
|
const yy = 1.0 / camera.lens;
|
||||||
const fnmod = 1.0 / (camera.far - camera.near);
|
|
||||||
const zz = camera.far * fnmod;
|
|
||||||
const wz = -camera.near * camera.far * fnmod;
|
|
||||||
const projection = @Vector(16, f32){
|
const projection = @Vector(16, f32){
|
||||||
xx, 0, 0, 0,
|
xx, 0, 0, 0,
|
||||||
0, yy, 0, 0,
|
0, yy, 0, 0,
|
||||||
0, 0, -zz, wz,
|
0, 0, 0, camera.near,
|
||||||
0, 0, -1, 0,
|
0, 0, -1, 0,
|
||||||
};
|
};
|
||||||
camera.matrix = Transform.multiplyMatrix(projection, camera.transform.inverseMatrix());
|
camera.matrix = Transform.multiplyMatrix(projection, camera.transform.inverseMatrix());
|
||||||
|
@@ -12,7 +12,7 @@ pub const BLEND_NORMAL = sdl.GPUColorTargetBlendState{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const DEPTH_ENABLED = sdl.GPUDepthStencilState{
|
pub const DEPTH_ENABLED = sdl.GPUDepthStencilState{
|
||||||
.compare_op = sdl.GPU_COMPAREOP_LESS,
|
.compare_op = sdl.GPU_COMPAREOP_GREATER,
|
||||||
.enable_depth_test = true,
|
.enable_depth_test = true,
|
||||||
.enable_depth_write = true,
|
.enable_depth_write = true,
|
||||||
};
|
};
|
||||||
|
@@ -459,7 +459,7 @@ pub fn draw() void {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Graphics.drawObject(&World.cubemap, .{
|
Graphics.drawObject(&World.cubemap, .{
|
||||||
.scale = Graphics.camera.far,
|
.scale = 1e20,
|
||||||
.position = Graphics.camera.transform.position,
|
.position = Graphics.camera.transform.position,
|
||||||
});
|
});
|
||||||
Graphics.clearDepth();
|
Graphics.clearDepth();
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const sdl = @cImport({
|
const sdl = @cImport({
|
||||||
@cInclude("SDL3/SDL.h");
|
@cInclude("SDL3/SDL.h");
|
||||||
|
@cInclude("SDL3_image/SDL_image.h");
|
||||||
});
|
});
|
||||||
|
|
||||||
const PREFIX = "SDL_";
|
const PREFIX = "SDL_";
|
||||||
@@ -23,12 +24,8 @@ pub fn main() !void {
|
|||||||
try std.fs.cwd().createFile(output, .{});
|
try std.fs.cwd().createFile(output, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const writer = file.writer();
|
var writer_buffer: [4096]u8 = undefined;
|
||||||
|
var writer = file.writer(&writer_buffer);
|
||||||
const stdout = std.io.getStdOut();
|
|
||||||
defer stdout.close();
|
|
||||||
|
|
||||||
const out = stdout.writer();
|
|
||||||
|
|
||||||
var renamed_count: usize = 0;
|
var renamed_count: usize = 0;
|
||||||
for (@typeInfo(sdl).@"struct".decls) |decl| {
|
for (@typeInfo(sdl).@"struct".decls) |decl| {
|
||||||
@@ -36,7 +33,7 @@ pub fn main() !void {
|
|||||||
|
|
||||||
const new_name: []const u8 = decl.name[PREFIX.len..];
|
const new_name: []const u8 = decl.name[PREFIX.len..];
|
||||||
|
|
||||||
try writer.print(
|
try writer.interface.print(
|
||||||
\\#define {1s} {0s}
|
\\#define {1s} {0s}
|
||||||
\\
|
\\
|
||||||
, .{ decl.name, new_name });
|
, .{ decl.name, new_name });
|
||||||
@@ -45,5 +42,4 @@ pub fn main() !void {
|
|||||||
if (renamed_count == 0) {
|
if (renamed_count == 0) {
|
||||||
@panic("No SDL definitions renamed");
|
@panic("No SDL definitions renamed");
|
||||||
}
|
}
|
||||||
try out.print("[SDL Translator] {} SDL definitions renamed\n", .{renamed_count});
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user