Add tracy profiler, use multi draw indirect for shadows, use Bistro scene

This commit is contained in:
sergeypdev 2024-07-28 16:39:46 +04:00
parent 551f92c64e
commit b4c3bcba94
9 changed files with 305 additions and 224 deletions

BIN
assets/bistro.glb (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -154,7 +154,7 @@ EvalMaterial evalMaterial() {
result.albedo = textureSize(materials[materialIdx].albedo_map, 0) == ivec2(0) ? vec4(pow(materials[materialIdx].albedo.rgb, vec3(2.2)), materials[materialIdx].albedo.a) : texture(materials[materialIdx].albedo_map, VertexOut.uv * materials[materialIdx].albedo_map_uv_scale);
float fMetallic = textureSize(materials[materialIdx].metallic_map, 0) == ivec2(0) ? materials[materialIdx].metallic : texture(materials[materialIdx].metallic_map, VertexOut.uv * materials[materialIdx].metallic_map_uv_scale).b;
result.metallic = fMetallic > 0.1;
result.roughness = max(1.0, textureSize(materials[materialIdx].roughness_map, 0) == ivec2(0) ? materials[materialIdx].roughness : texture(materials[materialIdx].roughness_map, VertexOut.uv * materials[materialIdx].roughness_map_uv_scale).g);
result.roughness = max(0.01, textureSize(materials[materialIdx].roughness_map, 0) == ivec2(0) ? materials[materialIdx].roughness : texture(materials[materialIdx].roughness_map, VertexOut.uv * materials[materialIdx].roughness_map_uv_scale).g);
result.emission = textureSize(materials[materialIdx].emission_map, 0) == ivec2(0) ? materials[materialIdx].emission : texture(materials[materialIdx].emission_map, VertexOut.uv * materials[materialIdx].emission_map_uv_scale).rgb;
return result;
@ -169,7 +169,7 @@ vec3 schlickFresnel(EvalMaterial mat, float LDotH) {
return f0 + (1 - f0) * pow(1.0 - LDotH, 5);
}
const float eps = 0.0000001;
const float eps = 0.0001;
float geomSmith(EvalMaterial mat, float DotVal) {
float k = (mat.roughness + 1.0) * (mat.roughness + 1.0) / 8.0;
@ -299,7 +299,7 @@ vec3 microfacetModel(EvalMaterial mat, int light_idx, vec3 P, vec3 N) {
shadow_mult = sum / 16.0;
}
shadow_mult = clamp(shadow_mult, 0.2, 1.0);
shadow_mult = clamp(shadow_mult, 0.3, 1.0);
vec3 specBrdf = 0.25 * ggxDistribution(mat, NDotH) * schlickFresnel(mat, LDotH) * geomSmith(mat, NDotL) * geomSmith(mat, NDotV);
@ -311,6 +311,7 @@ void main() {
sampler2D normal_map = materials[materialIdx].normal_map;
vec2 normal_map_uv_scale = materials[materialIdx].normal_map_uv_scale;
EvalMaterial material = evalMaterial();
material.roughness = material.albedo.a < 1.0 ? 1.0 : material.roughness;
vec3 N = textureSize(normal_map, 0) == ivec2(0) ? vec3(0.5) : vec3(texture(normal_map, VertexOut.uv * normal_map_uv_scale).xy, 0);
N = N * 2.0 - 1.0;

View File

@ -4,8 +4,10 @@ layout(std140, binding = 0) uniform Matrices {
mat4 view;
};
// Uniforms
layout(location = 1) uniform mat4 model;
layout(std430, binding = 3) readonly buffer DrawCmdDatas {
// Access by gl_DrawID
mat4 transforms[];
};
// Input, output blocks
@ -14,6 +16,7 @@ layout(location = 1) uniform mat4 model;
layout(location = 0) in vec3 aPos;
void main() {
mat4 model = transforms[gl_DrawID];
gl_Position = projection * view * model * vec4(aPos.xyz, 1.0);
}
#endif // VERTEX_SHADER

View File

@ -23,6 +23,10 @@ pub fn build(b: *Build) void {
"Prioritize performance, safety, or binary size for build time tools",
) orelse .Debug;
const tracy = b.dependency("zig-tracy", .{
.target = target,
.optimize = optimize,
});
const zalgebra_dep = b.dependency("zalgebra", .{});
const assets_mod = b.addModule("assets", .{ .root_source_file = .{ .src_path = .{ .owner = b, .sub_path = "src/assets/root.zig" } } });
@ -62,6 +66,8 @@ pub fn build(b: *Build) void {
l.root_module.addImport("zalgebra", zalgebra_dep.module("zalgebra"));
l.root_module.addImport("assets", assets_mod);
l.root_module.addImport("asset_manifest", asset_manifest_mod);
l.root_module.addImport("tracy", tracy.module("tracy"));
l.linkLibrary(tracy.artifact("tracy"));
}
const install_lib = b.addInstallArtifact(lib, .{ .dest_dir = .{ .override = .prefix } });
@ -150,6 +156,8 @@ const asset_extensions = [_][]const u8{
"glsl",
"prog",
"png",
"dds",
"tga",
"jpg",
"exr",
"fbx",

View File

@ -27,6 +27,10 @@
.url = "https://github.com/sergeypdev/zalgebra/tarball/43371bf211ad574cde90f653fea171f1cccb1716",
.hash = "1220e1439198c5206dbb924420aac0f57dd11fd4b6639e1aa9559abc09f91bfd2c9a",
},
.@"zig-tracy" = .{
.url = "https://github.com/sergeypdev/zig-tracy/tarball/2b818574810a66deacc424298c1a7679ca6e4375",
.hash = "1220638bc94d67225a620e1abd71d85b299c8b764490fd51233ed73d76ee44cc5835",
},
},
.paths = .{
// This makes *all* files, recursively, included in this package. It is generally

View File

@ -24,6 +24,7 @@ const checkGLError = @import("Render.zig").checkGLError;
const BuddyAllocator = @import("BuddyAllocator.zig");
const Vec2 = @import("zalgebra").Vec2;
const Vec3 = @import("zalgebra").Vec3;
const tracy = @import("tracy");
pub const AssetId = assets.AssetId;
pub const Handle = assets.Handle;
@ -158,6 +159,9 @@ pub fn resolveMaterial(self: *AssetManager, handle: Handle.Material) formats.Mat
// TODO: proper watching
pub fn watchChanges(self: *AssetManager) void {
const zone = tracy.initZone(@src(), .{ .name = "AssetManager.watchChanges" });
defer zone.deinit();
var iter = self.loaded_assets.iterator();
while (iter.next()) |entry| {
const gop = self.modified_times.getOrPut(self.allocator, entry.key_ptr.*) catch return;

View File

@ -7,6 +7,7 @@ const globals = @import("globals.zig");
pub const Material = @import("formats.zig").Material;
const math = @import("math.zig");
const formats = @import("formats.zig");
const tracy = @import("tracy");
const za = @import("zalgebra");
const Vec2 = za.Vec2;
@ -438,13 +439,17 @@ pub fn draw(self: *Render, cmd: DrawCommand) void {
}
pub fn finish(self: *Render) void {
const ginit = globals.g_init;
const zone = tracy.initZone(@src(), .{ .name = "Render.finish" });
defer zone.deinit();
const camera_projection = self.camera.projection();
const view_proj = camera_projection.mul(self.camera.view_mat);
// Sort draw calls: opaque -> blended
{
const zoneSort = tracy.initZone(@src(), .{ .name = "Render.finish_sortDraws" });
defer zoneSort.deinit();
const cmds = self.command_buffer[0..self.command_count];
std.mem.sortUnstable(DrawCommand, cmds, self, struct {
pub fn lessThan(render: *const Render, lhs: DrawCommand, rhs: DrawCommand) bool {
@ -500,6 +505,9 @@ pub fn finish(self: *Render) void {
// Light shadow maps
{
const zoneShadowmaps = tracy.initZone(@src(), .{ .name = "Render.finish_shadowmaps" });
defer zoneShadowmaps.deinit();
gl.enable(gl.DEPTH_CLAMP);
defer gl.disable(gl.DEPTH_CLAMP);
@ -737,55 +745,62 @@ pub fn finish(self: *Render) void {
checkGLError();
defer gl.deleteBuffers(1, &draw_cmd_data_buf);
const materials = self.materials_pbr_ssbo.getInstance(self.tripple_buffer_index);
materials.count.* = 0;
var material_map = std.StringHashMap(i32).init(self.frame_arena);
var materials_count: usize = 0;
var rendered_count: usize = 0;
cmds: for (self.command_buffer[0..self.command_count]) |*cmd| {
const mesh = self.assetman.resolveMesh(cmd.mesh);
const aabb = math.AABB.fromMinMax(mesh.aabb.min, mesh.aabb.max);
if (!self.world_camera_frustum.intersectAABB(aabb.transform(cmd.transform))) {
continue;
// Prepare indirect draw commands
{
const zonePrepareInidirectDraws = tracy.initZone(@src(), .{ .name = "Render.finish_PrepareInidirectDraws" });
defer zonePrepareInidirectDraws.deinit();
const materials = self.materials_pbr_ssbo.getInstance(self.tripple_buffer_index);
materials.count.* = 0;
var material_map = std.StringHashMap(i32).init(self.frame_arena);
var materials_count: usize = 0;
cmds: for (self.command_buffer[0..self.command_count]) |*cmd| {
const mesh = self.assetman.resolveMesh(cmd.mesh);
// const aabb = math.AABB.fromMinMax(mesh.aabb.min, mesh.aabb.max);
// if (!self.world_camera_frustum.intersectAABB(aabb.transform(cmd.transform))) {
// continue;
// }
const material: Material = if (cmd.material_override) |mat| mat else mesh.material;
// Opaque objects are drawn, start rendering alpha blended objects
if (material.blend_mode == .AlphaBlend and !switched_to_alpha_blend) {
break :cmds;
// switched_to_alpha_blend = true;
// gl.enable(gl.BLEND);
// gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
}
const material_bytes = std.mem.asBytes(&material);
const material_copy = self.frame_arena.alloc(u8, material_bytes.len) catch @panic("OOM");
@memcpy(material_copy, material_bytes);
const gop = material_map.getOrPut(material_copy) catch @panic("OOM");
if (!gop.found_existing) {
gop.value_ptr.* = @intCast(materials_count);
materials.data[materials_count] = MaterialPBR.fromMaterial(self.assetman, &material);
materials_count += 1;
}
draw_cmd_data[rendered_count] = DrawCommandData{
.transform = cmd.transform,
.material_index = gop.value_ptr.*,
};
draw_indirect_cmds[rendered_count] = DrawIndirectCmd{
.count = mesh.indices.count,
.instance_count = 1,
.first_index = mesh.indices.offset / 4,
.base_vertex = mesh.indices.base_vertex,
.base_instance = 0,
};
rendered_count += 1;
}
const material: Material = if (cmd.material_override) |mat| mat else mesh.material;
// Opaque objects are drawn, start rendering alpha blended objects
if (material.blend_mode == .AlphaBlend and !switched_to_alpha_blend) {
break :cmds;
// switched_to_alpha_blend = true;
// gl.enable(gl.BLEND);
// gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
}
const material_bytes = std.mem.asBytes(&material);
const material_copy = self.frame_arena.alloc(u8, material_bytes.len) catch @panic("OOM");
@memcpy(material_copy, material_bytes);
const gop = material_map.getOrPut(material_copy) catch @panic("OOM");
if (!gop.found_existing) {
gop.value_ptr.* = @intCast(materials_count);
materials.data[materials_count] = MaterialPBR.fromMaterial(self.assetman, &material);
materials_count += 1;
}
draw_cmd_data[rendered_count] = DrawCommandData{
.transform = cmd.transform,
.material_index = gop.value_ptr.*,
};
draw_indirect_cmds[rendered_count] = DrawIndirectCmd{
.count = mesh.indices.count,
.instance_count = 1,
.first_index = mesh.indices.offset / 4,
.base_vertex = mesh.indices.base_vertex,
.base_instance = 0,
};
rendered_count += 1;
}
{
@ -992,8 +1007,6 @@ pub fn finish(self: *Render) void {
}
self.gl_fences[self.tripple_buffer_index] = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
c.SDL_GL_SwapWindow(ginit.window);
//c.SDL_Delay(1);
}
pub fn pointLightRange(self: *const PointLight) f32 {
@ -1044,26 +1057,50 @@ const cube_camera_dirs = [6]CubeCameraDir{
};
fn renderShadow(self: *Render, frustum: *const math.Frustum) void {
const zone = tracy.initZone(@src(), .{ .name = "Render.renderShadow" });
defer zone.deinit();
_ = frustum; // autofix
self.assetman.vertex_heap.vertices.bind(Render.Attrib.Position.value());
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.assetman.vertex_heap.indices.buffer);
// TODO: this wastes space in temp allocator
var draw_indirect_cmds = std.ArrayList(DrawIndirectCmd).init(self.frame_arena);
var transforms = std.ArrayList(Mat4).init(self.frame_arena);
for (self.command_buffer[0..self.command_count]) |*cmd| {
const mesh = self.assetman.resolveMesh(cmd.mesh);
const aabb = math.AABB.fromMinMax(mesh.aabb.min, mesh.aabb.max);
// const aabb = math.AABB.fromMinMax(mesh.aabb.min, mesh.aabb.max);
if (!frustum.intersectAABBSkipNear(aabb.transform(cmd.transform))) {
continue;
}
// if (!frustum.intersectAABBSkipNear(aabb.transform(cmd.transform))) {
// continue;
// }
gl.uniformMatrix4fv(Uniform.ModelMatrix.value(), 1, gl.FALSE, @ptrCast(&cmd.transform.data));
mesh.positions.bind(Render.Attrib.Position.value());
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indices.buffer);
const draw_indirect_cmd = draw_indirect_cmds.addOne() catch @panic("OOM");
const transform = transforms.addOne() catch @panic("OOM");
gl.drawElementsBaseVertex(
gl.TRIANGLES,
@intCast(mesh.indices.count),
mesh.indices.type,
@ptrFromInt(mesh.indices.offset),
mesh.indices.base_vertex,
);
draw_indirect_cmd.* = .{
.count = mesh.indices.count,
.instance_count = 1,
.first_index = mesh.indices.offset / 4,
.base_vertex = mesh.indices.base_vertex,
.base_instance = 0,
};
transform.* = cmd.transform;
}
var bufs = [2]gl.GLuint{ 0, 0 };
gl.createBuffers(bufs.len, &bufs);
checkGLError();
defer _ = gl.deleteBuffers(bufs.len, &bufs);
gl.namedBufferStorage(bufs[0], @intCast(@sizeOf(DrawIndirectCmd) * draw_indirect_cmds.items.len), draw_indirect_cmds.items.ptr, 0);
gl.namedBufferStorage(bufs[1], @intCast(@sizeOf(Mat4) * transforms.items.len), transforms.items.ptr, 0);
gl.bindBuffer(gl.DRAW_INDIRECT_BUFFER, bufs[0]);
gl.bindBufferBase(gl.SHADER_STORAGE_BUFFER, SSBO.DrawCommandData.value(), bufs[1]);
gl.multiDrawElementsIndirect(gl.TRIANGLES, gl.UNSIGNED_INT, null, @intCast(draw_indirect_cmds.items.len), 0);
}
pub fn checkGLError() void {

View File

@ -15,6 +15,7 @@ const Mat4 = za.Mat4;
const Quat = za.Quat;
const a = @import("asset_manifest");
const windows = std.os.windows;
const tracy = @import("tracy");
pub extern "dwmapi" fn DwmEnableMMCSS(fEnableMMCSS: windows.BOOL) callconv(windows.WINAPI) windows.HRESULT;
pub extern "dwmapi" fn DwmFlush() callconv(windows.WINAPI) void;
@ -161,6 +162,7 @@ const mesh_program = a.ShaderPrograms.mesh;
export fn game_init(global_allocator: *std.mem.Allocator) void {
loadGL();
tracy.startupProfiler();
std.log.debug("game_init\n", .{});
globals.g_mem = global_allocator.create(GameMemory) catch @panic("OOM");
@ -188,8 +190,8 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
_ = globals.g_mem.world.addEntity(.{
.flags = .{ .dir_light = true, .rotate = true },
.transform = .{ .rot = Quat.fromEulerAngles(Vec3.new(20, 0, 0)) },
.light = .{ .color_intensity = Vec4.new(1, 1, 0.83, 0.7) },
.transform = .{ .rot = Quat.fromEulerAngles(Vec3.new(70, 0, 0)) },
.light = .{ .color_intensity = Vec4.new(std.math.pow(f32, 1, 2.2), std.math.pow(f32, 0.9568627450980393, 2.2), std.math.pow(f32, 0.9176470588235294, 2.2), 1.0) },
.rotate = .{ .axis = Vec3.up(), .rate = -10 },
});
@ -224,70 +226,72 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
// });
// Plane
_ = globals.g_mem.world.addEntity(.{
.flags = .{ .mesh = true },
.transform = .{ .scale = Vec3.one().scale(10) },
.mesh = .{
.handle = a.Meshes.plane.Plane,
.material = .{
.albedo = Vec4.one(),
.normal_map = a.Textures.@"tile.norm",
},
.override_material = true,
},
});
// _ = globals.g_mem.world.addEntity(.{
// .flags = .{ .mesh = true },
// .transform = .{ .scale = Vec3.one().scale(10) },
// .mesh = .{
// .handle = a.Meshes.plane.Plane,
// .material = .{
// .albedo = Vec4.one(),
// .normal_map = a.Textures.@"tile.norm",
// },
// .override_material = true,
// },
// });
// 10 dielectric bunnies
{
for (0..100) |y| {
for (0..10) |x| {
_ = globals.g_mem.world.addEntity(.{
.transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(x)) * 0.3 - 0.3 * 4.5, 0, @as(f32, @floatFromInt(y)) * 0.3 - 0.3 * 4.5) },
// {
// for (0..100) |y| {
// for (0..1) |x| {
// _ = globals.g_mem.world.addEntity(.{
// .transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(x)) * 0.3 - 0.3 * 4.5, 0, @as(f32, @floatFromInt(y)) * 0.3 - 0.3 * 4.5) },
.flags = .{ .mesh = true },
.mesh = .{
.handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1,
.material = .{
.albedo_map = a.Textures.bunny_tex1,
// .normal_map = a.Textures.@"tile.norm",
.roughness = @as(f32, @floatFromInt(y)) / 100.0,
},
.override_material = true,
},
});
}
}
}
// 10 metallic bunnies
{
for (0..10) |i| {
_ = globals.g_mem.world.addEntity(.{
.transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(i)) * 0.3 - 0.3 * 4.5, 0.3, 0) },
// .flags = .{ .mesh = true },
// .mesh = .{
// .handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1,
// .material = .{
// .albedo_map = a.Textures.bunny_tex1,
// // .normal_map = a.Textures.@"tile.norm",
// .roughness = @as(f32, @floatFromInt(y)) / 100.0,
// },
// .override_material = true,
// },
// });
// }
// }
// }
// // 10 metallic bunnies
// {
// for (0..10) |i| {
// _ = globals.g_mem.world.addEntity(.{
// .transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(i)) * 0.3 - 0.3 * 4.5, 0.3, 0) },
.flags = .{ .mesh = true },
.mesh = .{
.handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1,
.material = .{
.blend_mode = .AlphaBlend,
.albedo = Vec4.new(1.000, 0.766, 0.336, 0.5),
// .albedo_map = a.Textures.bunny_tex1,
// .normal_map = a.Textures.@"tile.norm",
.roughness = @as(f32, @floatFromInt(i + 1)) / 10.0,
.metallic = 1.0,
},
.override_material = true,
},
});
}
}
// .flags = .{ .mesh = true },
// .mesh = .{
// .handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1,
// .material = .{
// .blend_mode = .AlphaBlend,
// .albedo = Vec4.new(1.000, 0.766, 0.336, 0.5),
// // .albedo_map = a.Textures.bunny_tex1,
// // .normal_map = a.Textures.@"tile.norm",
// .roughness = @as(f32, @floatFromInt(i + 1)) / 10.0,
// .metallic = 1.0,
// },
// .override_material = true,
// },
// });
// }
// }
const scene = globals.g_mem.world.createScene(globals.g_assetman.resolveScene(a.Scenes.amd_ryzen_9.scene));
const scene = globals.g_mem.world.createScene(globals.g_assetman.resolveScene(a.Scenes.bistro.scene));
const ent = globals.g_mem.world.getEntity(scene) orelse @panic("WTF");
ent.data.transform.pos = Vec3.new(0, 1, 0);
ent.data.transform.scale = Vec3.one().scale(0.2);
ent.data.transform.pos = Vec3.new(0, 0, 0);
// ent.data.transform.scale = Vec3.one().scale(1.0);
}
export fn game_update() bool {
const zoneGameUpdate = tracy.initZone(@src(), .{});
defer zoneGameUpdate.deinit();
const ginit = globals.g_init;
const gmem = globals.g_mem;
// std.debug.print("FPS: {d}\n", .{1.0 / g_mem.delta_time});
@ -298,108 +302,112 @@ export fn game_update() bool {
var move = Vec3.zero();
var look = Vec2.zero();
while (c.SDL_PollEvent(&event) != 0) {
switch (event.type) {
c.SDL_QUIT => {
return false;
},
c.SDL_MOUSEMOTION => {
if (gmem.mouse_focus) {
look.xMut().* += @floatFromInt(event.motion.xrel);
look.yMut().* += @floatFromInt(event.motion.yrel);
}
},
c.SDL_MOUSEBUTTONUP => {
if (!gmem.mouse_focus) {
_ = c.SDL_SetRelativeMouseMode(c.SDL_TRUE);
{
const zone = tracy.initZone(@src(), .{ .name = "SDL poll events" });
defer zone.deinit();
while (c.SDL_PollEvent(&event) != 0) {
switch (event.type) {
c.SDL_QUIT => {
return false;
},
c.SDL_MOUSEMOTION => {
if (gmem.mouse_focus) {
look.xMut().* += @floatFromInt(event.motion.xrel);
look.yMut().* += @floatFromInt(event.motion.yrel);
}
},
c.SDL_MOUSEBUTTONUP => {
if (!gmem.mouse_focus) {
_ = c.SDL_SetRelativeMouseMode(c.SDL_TRUE);
gmem.mouse_focus = true;
}
},
c.SDL_MOUSEWHEEL => {
if (gmem.mouse_focus) {
gmem.free_cam.move_speed = @max(gmem.free_cam.move_speed + event.wheel.preciseY * 0.1, 0);
}
},
c.SDL_KEYUP, c.SDL_KEYDOWN => {
const pressed = event.key.state == c.SDL_PRESSED;
gmem.mouse_focus = true;
}
},
c.SDL_MOUSEWHEEL => {
if (gmem.mouse_focus) {
gmem.free_cam.move_speed = @max(gmem.free_cam.move_speed + event.wheel.preciseY * 0.1, 0);
}
},
c.SDL_KEYUP, c.SDL_KEYDOWN => {
const pressed = event.key.state == c.SDL_PRESSED;
switch (event.key.keysym.scancode) {
// Toggle fullscreen
c.SDL_SCANCODE_RETURN => {
if (event.type == c.SDL_KEYDOWN and event.key.keysym.mod & c.KMOD_ALT > 0) {
toggleFullScreen() catch continue;
}
},
// Toggle vsync
c.SDL_SCANCODE_F10 => {
if (event.type == c.SDL_KEYDOWN) {
const newSwap: c_int = if (ginit.vsync) 0 else 1;
sdl_try(c.SDL_GL_SetSwapInterval(newSwap)) catch continue;
ginit.vsync = !ginit.vsync;
}
},
// Freeze view frustum
c.SDL_SCANCODE_F8 => {
if (event.type == c.SDL_KEYDOWN) {
gmem.render.update_view_frustum = !gmem.render.update_view_frustum;
}
},
// Expand camera far
c.SDL_SCANCODE_F7 => {
if (event.type == c.SDL_KEYDOWN) {
if (gmem.render.camera.far == 10) {
gmem.render.camera.far = 50;
} else {
gmem.render.camera.far = 10;
}
}
},
c.SDL_SCANCODE_ESCAPE => {
if (event.type == c.SDL_KEYUP) {
if (ginit.fullscreen) {
switch (event.key.keysym.scancode) {
// Toggle fullscreen
c.SDL_SCANCODE_RETURN => {
if (event.type == c.SDL_KEYDOWN and event.key.keysym.mod & c.KMOD_ALT > 0) {
toggleFullScreen() catch continue;
} else if (gmem.mouse_focus) {
_ = c.SDL_SetRelativeMouseMode(c.SDL_FALSE);
gmem.mouse_focus = false;
} else {
return false;
}
}
},
c.SDL_SCANCODE_W => {
gmem.input_state.forward = pressed;
},
c.SDL_SCANCODE_S => {
gmem.input_state.backward = pressed;
},
c.SDL_SCANCODE_A => {
gmem.input_state.left = pressed;
},
c.SDL_SCANCODE_D => {
gmem.input_state.right = pressed;
},
c.SDL_SCANCODE_SPACE => {
gmem.input_state.up = pressed;
},
c.SDL_SCANCODE_LCTRL => {
gmem.input_state.down = pressed;
},
else => {},
}
},
c.SDL_WINDOWEVENT => {
switch (event.window.event) {
c.SDL_WINDOWEVENT_SIZE_CHANGED => {
c.SDL_GL_GetDrawableSize(ginit.window, &ginit.width, &ginit.height);
std.log.debug("w: {}, h: {}\n", .{ ginit.width, ginit.height });
},
// Toggle vsync
c.SDL_SCANCODE_F10 => {
if (event.type == c.SDL_KEYDOWN) {
const newSwap: c_int = if (ginit.vsync) 0 else 1;
sdl_try(c.SDL_GL_SetSwapInterval(newSwap)) catch continue;
ginit.vsync = !ginit.vsync;
}
},
// Freeze view frustum
c.SDL_SCANCODE_F8 => {
if (event.type == c.SDL_KEYDOWN) {
gmem.render.update_view_frustum = !gmem.render.update_view_frustum;
}
},
// Expand camera far
c.SDL_SCANCODE_F7 => {
if (event.type == c.SDL_KEYDOWN) {
if (gmem.render.camera.far == 10) {
gmem.render.camera.far = 50;
} else {
gmem.render.camera.far = 10;
}
}
},
c.SDL_SCANCODE_ESCAPE => {
if (event.type == c.SDL_KEYUP) {
if (ginit.fullscreen) {
toggleFullScreen() catch continue;
} else if (gmem.mouse_focus) {
_ = c.SDL_SetRelativeMouseMode(c.SDL_FALSE);
gmem.mouse_focus = false;
} else {
return false;
}
}
},
c.SDL_SCANCODE_W => {
gmem.input_state.forward = pressed;
},
c.SDL_SCANCODE_S => {
gmem.input_state.backward = pressed;
},
c.SDL_SCANCODE_A => {
gmem.input_state.left = pressed;
},
c.SDL_SCANCODE_D => {
gmem.input_state.right = pressed;
},
c.SDL_SCANCODE_SPACE => {
gmem.input_state.up = pressed;
},
c.SDL_SCANCODE_LCTRL => {
gmem.input_state.down = pressed;
},
else => {},
}
},
c.SDL_WINDOWEVENT => {
switch (event.window.event) {
c.SDL_WINDOWEVENT_SIZE_CHANGED => {
c.SDL_GL_GetDrawableSize(ginit.window, &ginit.width, &ginit.height);
std.log.debug("w: {}, h: {}\n", .{ ginit.width, ginit.height });
gl.viewport(0, 0, ginit.width, ginit.height);
},
else => {},
}
},
else => {},
gl.viewport(0, 0, ginit.width, ginit.height);
},
else => {},
}
},
else => {},
}
}
}
@ -438,6 +446,8 @@ export fn game_update() bool {
// Update
{
const zone = tracy.initZone(@src(), .{ .name = "update entities" });
defer zone.deinit();
for (gmem.world.entities[0..gmem.world.entity_count]) |*ent| {
if (!ent.data.flags.active) continue;
@ -449,6 +459,8 @@ export fn game_update() bool {
// Render
{
const zone = tracy.initZone(@src(), .{ .name = "game.render()" });
defer zone.deinit();
gmem.render.begin();
defer gmem.render.finish();
@ -503,7 +515,15 @@ export fn game_update() bool {
}
}
globals.g_assetman.watchChanges();
{
const zone = tracy.initZone(@src(), .{ .name = "SDL_GL_SwapWindow" });
defer zone.deinit();
c.SDL_GL_SwapWindow(ginit.window);
}
tracy.frameMark();
//c.SDL_Delay(1);
// globals.g_assetman.watchChanges();
return true;
}
@ -514,6 +534,7 @@ export fn game_shutdown() void {
gmem.global_allocator.free(gmem.frame_fba.buffer);
gmem.global_allocator.destroy(gmem);
gl.disable(gl.DEBUG_OUTPUT);
tracy.shutdownProfiler();
}
export fn game_shutdown_window() void {

View File

@ -44,7 +44,7 @@ pub fn resolveAssetTypeByExtension(path: []const u8) ?AssetType {
if (std.mem.endsWith(u8, path, ".glsl")) {
return .Shader;
}
if (std.mem.endsWith(u8, path, ".png") or std.mem.endsWith(u8, path, ".jpg") or std.mem.endsWith(u8, path, ".exr")) {
if (std.mem.endsWith(u8, path, ".png") or std.mem.endsWith(u8, path, ".jpg") or std.mem.endsWith(u8, path, ".exr") or std.mem.endsWith(u8, path, ".dds") or std.mem.endsWith(u8, path, ".tga")) {
return .Texture;
}
return null;