Mesh loading WIP
This commit is contained in:
parent
afa00106e4
commit
bd903da009
@ -4,6 +4,32 @@
|
|||||||
|
|
||||||
#include "global.glsl"
|
#include "global.glsl"
|
||||||
|
|
||||||
|
layout(std430, buffer_reference, buffer_reference_align = 4) readonly buffer PositionBuffer
|
||||||
|
{
|
||||||
|
vec3 positions[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OtherData
|
||||||
|
{
|
||||||
|
vec3 normal;
|
||||||
|
vec3 tangent;
|
||||||
|
vec2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, buffer_reference, buffer_reference_align = 4) readonly buffer OtherDataBuffer
|
||||||
|
{
|
||||||
|
OtherData other_data[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(push_constant, std430) uniform constants
|
||||||
|
{
|
||||||
|
mat4 local_to_world;
|
||||||
|
PositionBuffer positions;
|
||||||
|
OtherDataBuffer other_data;
|
||||||
|
uint color_texture;
|
||||||
|
uint color_sampler;
|
||||||
|
} PushConstants;
|
||||||
|
|
||||||
#if VERTEX_SHADER
|
#if VERTEX_SHADER
|
||||||
|
|
||||||
// QUAD
|
// QUAD
|
||||||
@ -20,10 +46,12 @@ vec2 positions[6] = vec2[](
|
|||||||
layout(location = 0) out vec2 OutUV;
|
layout(location = 0) out vec2 OutUV;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
OutUV = positions[gl_VertexIndex] * 0.5 + 0.5;
|
PositionBuffer positions_ptr = PushConstants.positions;
|
||||||
OutUV.y = 1 - OutUV.y;
|
OtherDataBuffer other_data_ptr = PushConstants.other_data;
|
||||||
|
|
||||||
gl_Position = vec4(positions[gl_VertexIndex] + vec2(gl_InstanceIndex, 0), gl_InstanceIndex, 1.0) * Global.view.world_to_clip;
|
OutUV = other_data_ptr.other_data[gl_VertexIndex].uv;
|
||||||
|
|
||||||
|
gl_Position = vec4(positions_ptr.positions[gl_VertexIndex], 1.0) * PushConstants.local_to_world * Global.view.world_to_clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -31,16 +59,10 @@ void main() {
|
|||||||
#if FRAGMENT_SHADER
|
#if FRAGMENT_SHADER
|
||||||
|
|
||||||
layout(location = 0) in vec2 InUV;
|
layout(location = 0) in vec2 InUV;
|
||||||
|
|
||||||
layout(location = 0) out vec4 FragColor;
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
layout(push_constant, std430) uniform constants {
|
|
||||||
uint color_texture;
|
|
||||||
uint color_sampler;
|
|
||||||
} PushConstants;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
FragColor = vec4(texture(sampler2D(global_textures2d[PushConstants.color_texture], global_samplers[PushConstants.color_sampler]), InUV).rgb, 1.0);
|
FragColor = vec4(1); // vec4(texture(sampler2D(global_textures2d[PushConstants.color_texture], global_samplers[PushConstants.color_sampler]), InUV).rgb, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -182,7 +182,7 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, gc: *G
|
|||||||
.frame_arena = frame_arena,
|
.frame_arena = frame_arena,
|
||||||
.exe_dir = exe_dir,
|
.exe_dir = exe_dir,
|
||||||
.texture_heap = try BuddyAllocator.init(allocator, 64, 22), // 256MB
|
.texture_heap = try BuddyAllocator.init(allocator, 64, 22), // 256MB
|
||||||
.vertex_heap = VertexBufferHeap.init(allocator) catch @panic("OOM"),
|
.vertex_heap = VertexBufferHeap.init(allocator, gc) catch @panic("OOM"),
|
||||||
.gc = gc,
|
.gc = gc,
|
||||||
.descriptorman = descriptorman,
|
.descriptorman = descriptorman,
|
||||||
.frame_state = frame_state,
|
.frame_state = frame_state,
|
||||||
@ -283,6 +283,20 @@ pub fn resolveShaderProgram(self: *AssetManager, handle: Handle.ShaderProgram) L
|
|||||||
pub fn resolveMesh(self: *AssetManager, handle: Handle.Mesh) LoadedMesh {
|
pub fn resolveMesh(self: *AssetManager, handle: Handle.Mesh) LoadedMesh {
|
||||||
if (handle.id == 0) return NullMesh;
|
if (handle.id == 0) return NullMesh;
|
||||||
|
|
||||||
|
if (self.resolveLoadingAsset(handle.id)) |loading_mesh| {
|
||||||
|
const status = self.gc.device.getFenceStatus(loading_mesh.mesh.transfer_fence) catch @panic("getFenceStatus");
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
.success => {
|
||||||
|
self.finishLoadingAsset(handle.id);
|
||||||
|
},
|
||||||
|
.not_ready => {
|
||||||
|
return NullMesh;
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (self.resolveAsset(handle.id)) |asset| {
|
if (self.resolveAsset(handle.id)) |asset| {
|
||||||
switch (asset.*) {
|
switch (asset.*) {
|
||||||
.mesh => |mesh| {
|
.mesh => |mesh| {
|
||||||
@ -552,34 +566,10 @@ const NullShaderProgram = LoadedShaderProgram{
|
|||||||
|
|
||||||
const NullMesh = LoadedMesh{
|
const NullMesh = LoadedMesh{
|
||||||
.aabb = .{},
|
.aabb = .{},
|
||||||
.heap_handle = .{},
|
.allocation = .{},
|
||||||
.positions = BufferSlice{
|
.positions = 0,
|
||||||
.buffer = 0,
|
.other_data = 0,
|
||||||
.offset = 0,
|
.indices_offset = 0,
|
||||||
.stride = 0,
|
|
||||||
},
|
|
||||||
.normals = BufferSlice{
|
|
||||||
.buffer = 0,
|
|
||||||
.offset = 0,
|
|
||||||
.stride = 0,
|
|
||||||
},
|
|
||||||
.tangents = BufferSlice{
|
|
||||||
.buffer = 0,
|
|
||||||
.offset = 0,
|
|
||||||
.stride = 0,
|
|
||||||
},
|
|
||||||
.uvs = BufferSlice{
|
|
||||||
.buffer = 0,
|
|
||||||
.offset = 0,
|
|
||||||
.stride = 0,
|
|
||||||
},
|
|
||||||
.indices = IndexSlice{
|
|
||||||
.buffer = 0,
|
|
||||||
.offset = 0,
|
|
||||||
.count = 0,
|
|
||||||
.type = gl.UNSIGNED_SHORT,
|
|
||||||
.base_vertex = 0,
|
|
||||||
},
|
|
||||||
.material = .{},
|
.material = .{},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -609,67 +599,194 @@ fn loadMeshErr(self: *AssetManager, id: AssetId) !LoadedMesh {
|
|||||||
defer self.frame_arena.free(data.bytes);
|
defer self.frame_arena.free(data.bytes);
|
||||||
const mesh = formats.Mesh.fromBuffer(data.bytes);
|
const mesh = formats.Mesh.fromBuffer(data.bytes);
|
||||||
|
|
||||||
const vertices_len = mesh.vertices.len;
|
const vertices_len = mesh.positions.len;
|
||||||
const allocation = try self.vertex_heap.alloc(vertices_len, mesh.indices.len);
|
const allocation = try self.vertex_heap.alloc(vertices_len, mesh.indices.len);
|
||||||
|
const positions_size = @sizeOf(formats.Vector3) * vertices_len;
|
||||||
|
const other_data_size = @sizeOf(formats.Mesh.VertexDataForBasePass) * vertices_len;
|
||||||
|
const indices_size = @sizeOf(formats.Index) * mesh.indices.len;
|
||||||
|
|
||||||
const vertex_offset = allocation.vertex.offset;
|
const data_size = positions_size + other_data_size + indices_size;
|
||||||
|
|
||||||
gl.namedBufferSubData(self.vertex_heap.vertices.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.vertices.ptr));
|
const staging_buffer = try self.gc.device.createBuffer(&.{
|
||||||
checkGLError();
|
.usage = .{ .transfer_src_bit = true },
|
||||||
gl.namedBufferSubData(self.vertex_heap.normals.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.normals.ptr));
|
.sharing_mode = .exclusive,
|
||||||
checkGLError();
|
.size = data_size,
|
||||||
gl.namedBufferSubData(self.vertex_heap.tangents.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.tangents.ptr));
|
}, null);
|
||||||
checkGLError();
|
errdefer self.gc.device.destroyBuffer(staging_buffer, null);
|
||||||
gl.namedBufferSubData(self.vertex_heap.uvs.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector2)), @intCast(vertices_len * @sizeOf(formats.Vector2)), @ptrCast(mesh.uvs.ptr));
|
|
||||||
checkGLError();
|
|
||||||
|
|
||||||
const index_offset = allocation.index.offset;
|
const staging_mem_reqs = self.gc.device.getBufferMemoryRequirements(staging_buffer);
|
||||||
gl.namedBufferSubData(self.vertex_heap.indices.buffer, @intCast(index_offset * @sizeOf(formats.Index)), @intCast(mesh.indices.len * @sizeOf(formats.Index)), @ptrCast(mesh.indices.ptr));
|
|
||||||
|
|
||||||
const loaded_mesh = LoadedMesh{
|
const staging_mem = try self.gc.device.allocateMemory(&.{
|
||||||
|
.memory_type_index = self.gc.memory_config.cpu.type_index,
|
||||||
|
.allocation_size = staging_mem_reqs.size,
|
||||||
|
}, null);
|
||||||
|
errdefer self.gc.device.freeMemory(staging_mem, null);
|
||||||
|
|
||||||
|
try self.gc.device.bindBufferMemory(staging_buffer, staging_mem, 0);
|
||||||
|
|
||||||
|
const staging_bytes: []u8 = @as([*]u8, @ptrCast(try self.gc.device.mapMemory(staging_mem, 0, data_size, .{})))[0..data_size];
|
||||||
|
const positions_offset = 0;
|
||||||
|
var size = positions_size;
|
||||||
|
const positions = std.mem.bytesAsSlice(formats.Vector3, staging_bytes[positions_offset .. positions_offset + size]);
|
||||||
|
|
||||||
|
const other_data_offset = positions_offset + positions_size;
|
||||||
|
size = other_data_size;
|
||||||
|
const other_data = std.mem.bytesAsSlice(formats.Mesh.VertexDataForBasePass, staging_bytes[other_data_offset .. other_data_offset + size]);
|
||||||
|
|
||||||
|
const indices_offset = other_data_offset + other_data_size;
|
||||||
|
size = indices_size;
|
||||||
|
const indices = std.mem.bytesAsSlice(formats.Index, staging_bytes[indices_offset .. indices_offset + size]);
|
||||||
|
|
||||||
|
@memcpy(positions, mesh.positions);
|
||||||
|
@memcpy(other_data, mesh.other_data);
|
||||||
|
@memcpy(indices, mesh.indices);
|
||||||
|
|
||||||
|
self.gc.device.unmapMemory(staging_mem);
|
||||||
|
|
||||||
|
const cmds = try self.command_pool.allocateCommandBuffer();
|
||||||
|
|
||||||
|
try cmds.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||||
|
|
||||||
|
{
|
||||||
|
cmds.pipelineBarrier2(&.{
|
||||||
|
.memory_barrier_count = 0,
|
||||||
|
.buffer_memory_barrier_count = 4,
|
||||||
|
.p_buffer_memory_barriers = &.{
|
||||||
|
vk.BufferMemoryBarrier2{
|
||||||
|
.buffer = staging_buffer,
|
||||||
|
.src_stage_mask = .{ .host_bit = true },
|
||||||
|
.src_access_mask = .{ .host_write_bit = true },
|
||||||
|
.dst_stage_mask = .{ .copy_bit = true },
|
||||||
|
.dst_access_mask = .{ .transfer_read_bit = true },
|
||||||
|
.offset = 0,
|
||||||
|
.size = data_size,
|
||||||
|
.src_queue_family_index = 0,
|
||||||
|
.dst_queue_family_index = 0,
|
||||||
|
},
|
||||||
|
vk.BufferMemoryBarrier2{
|
||||||
|
.buffer = self.vertex_heap.heap_buffer,
|
||||||
|
.src_stage_mask = .{},
|
||||||
|
.src_access_mask = .{},
|
||||||
|
.dst_stage_mask = .{ .copy_bit = true },
|
||||||
|
.dst_access_mask = .{ .transfer_write_bit = true },
|
||||||
|
.offset = allocation.positions.offset,
|
||||||
|
.size = positions_size,
|
||||||
|
.src_queue_family_index = 0,
|
||||||
|
.dst_queue_family_index = 0,
|
||||||
|
},
|
||||||
|
vk.BufferMemoryBarrier2{
|
||||||
|
.buffer = self.vertex_heap.heap_buffer,
|
||||||
|
.src_stage_mask = .{},
|
||||||
|
.src_access_mask = .{},
|
||||||
|
.dst_stage_mask = .{ .copy_bit = true },
|
||||||
|
.dst_access_mask = .{ .transfer_write_bit = true },
|
||||||
|
.offset = allocation.other_data.offset,
|
||||||
|
.size = other_data_size,
|
||||||
|
.src_queue_family_index = 0,
|
||||||
|
.dst_queue_family_index = 0,
|
||||||
|
},
|
||||||
|
vk.BufferMemoryBarrier2{
|
||||||
|
.buffer = self.vertex_heap.heap_buffer,
|
||||||
|
.src_stage_mask = .{},
|
||||||
|
.src_access_mask = .{},
|
||||||
|
.dst_stage_mask = .{ .copy_bit = true },
|
||||||
|
.dst_access_mask = .{ .transfer_write_bit = true },
|
||||||
|
.offset = allocation.indices.offset,
|
||||||
|
.size = indices_size,
|
||||||
|
.src_queue_family_index = 0,
|
||||||
|
.dst_queue_family_index = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
cmds.copyBuffer(staging_buffer, self.vertex_heap.heap_buffer, 3, &.{
|
||||||
|
vk.BufferCopy{
|
||||||
|
.src_offset = positions_offset,
|
||||||
|
.dst_offset = allocation.positions.offset,
|
||||||
|
.size = positions_size,
|
||||||
|
},
|
||||||
|
vk.BufferCopy{
|
||||||
|
.src_offset = other_data_offset,
|
||||||
|
.dst_offset = allocation.other_data.offset,
|
||||||
|
.size = other_data_size,
|
||||||
|
},
|
||||||
|
vk.BufferCopy{
|
||||||
|
.src_offset = indices_offset,
|
||||||
|
.dst_offset = allocation.indices.offset,
|
||||||
|
.size = indices_size,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
cmds.pipelineBarrier2(&.{
|
||||||
|
.buffer_memory_barrier_count = 3,
|
||||||
|
.p_buffer_memory_barriers = &.{
|
||||||
|
vk.BufferMemoryBarrier2{
|
||||||
|
.buffer = self.vertex_heap.heap_buffer,
|
||||||
|
.src_stage_mask = .{ .copy_bit = true },
|
||||||
|
.src_access_mask = .{ .transfer_write_bit = true },
|
||||||
|
.dst_stage_mask = .{ .vertex_shader_bit = true, .fragment_shader_bit = true, .compute_shader_bit = true },
|
||||||
|
.dst_access_mask = .{ .shader_storage_read_bit = true },
|
||||||
|
.src_queue_family_index = self.queue.family,
|
||||||
|
.dst_queue_family_index = self.gc.queues.graphics.family,
|
||||||
|
.offset = allocation.positions.offset,
|
||||||
|
.size = positions_size,
|
||||||
|
},
|
||||||
|
vk.BufferMemoryBarrier2{
|
||||||
|
.buffer = self.vertex_heap.heap_buffer,
|
||||||
|
.src_stage_mask = .{ .copy_bit = true },
|
||||||
|
.src_access_mask = .{ .transfer_write_bit = true },
|
||||||
|
.dst_stage_mask = .{ .vertex_shader_bit = true, .fragment_shader_bit = true, .compute_shader_bit = true },
|
||||||
|
.dst_access_mask = .{ .shader_storage_read_bit = true },
|
||||||
|
.src_queue_family_index = self.queue.family,
|
||||||
|
.dst_queue_family_index = self.gc.queues.graphics.family,
|
||||||
|
.offset = allocation.other_data.offset,
|
||||||
|
.size = other_data_size,
|
||||||
|
},
|
||||||
|
vk.BufferMemoryBarrier2{
|
||||||
|
.buffer = self.vertex_heap.heap_buffer,
|
||||||
|
.src_stage_mask = .{ .copy_bit = true },
|
||||||
|
.src_access_mask = .{ .transfer_write_bit = true },
|
||||||
|
.dst_stage_mask = .{ .vertex_shader_bit = true, .fragment_shader_bit = true, .compute_shader_bit = true, .index_input_bit = true },
|
||||||
|
.dst_access_mask = .{ .shader_storage_read_bit = true, .index_read_bit = true },
|
||||||
|
.src_queue_family_index = self.queue.family,
|
||||||
|
.dst_queue_family_index = self.gc.queues.graphics.family,
|
||||||
|
.offset = allocation.indices.offset,
|
||||||
|
.size = indices_size,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
try cmds.endCommandBuffer();
|
||||||
|
|
||||||
|
const copy_fence = try self.gc.device.createFence(&.{}, null);
|
||||||
|
|
||||||
|
try self.queue.submit(&.{ .command_buffers = &.{cmds.handle} }, copy_fence);
|
||||||
|
|
||||||
|
const loading_mesh = LoadingMesh{
|
||||||
.aabb = .{
|
.aabb = .{
|
||||||
.min = Vec3.new(mesh.aabb.min.x, mesh.aabb.min.y, mesh.aabb.min.z),
|
.min = Vec3.new(mesh.aabb.min.x, mesh.aabb.min.y, mesh.aabb.min.z),
|
||||||
.max = Vec3.new(mesh.aabb.max.x, mesh.aabb.max.y, mesh.aabb.max.z),
|
.max = Vec3.new(mesh.aabb.max.x, mesh.aabb.max.y, mesh.aabb.max.z),
|
||||||
},
|
},
|
||||||
.heap_handle = allocation,
|
|
||||||
.material = mesh.material,
|
.material = mesh.material,
|
||||||
.positions = .{
|
.vertex_count = @intCast(vertices_len),
|
||||||
.buffer = self.vertex_heap.vertices.buffer,
|
.index_count = @intCast(mesh.indices.len),
|
||||||
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)),
|
.allocation = allocation,
|
||||||
.stride = @sizeOf(formats.Vector3),
|
.transfer_fence = copy_fence,
|
||||||
},
|
.staging_buf = staging_buffer,
|
||||||
.normals = .{
|
.staging_memory = staging_mem,
|
||||||
.buffer = self.vertex_heap.normals.buffer,
|
.command_buffer = cmds.handle,
|
||||||
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)),
|
|
||||||
.stride = @sizeOf(formats.Vector3),
|
|
||||||
},
|
|
||||||
.tangents = .{
|
|
||||||
.buffer = self.vertex_heap.tangents.buffer,
|
|
||||||
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)),
|
|
||||||
.stride = @sizeOf(formats.Vector3),
|
|
||||||
},
|
|
||||||
.uvs = .{
|
|
||||||
.buffer = self.vertex_heap.uvs.buffer,
|
|
||||||
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector2)),
|
|
||||||
.stride = @sizeOf(formats.Vector2),
|
|
||||||
},
|
|
||||||
.indices = .{
|
|
||||||
.buffer = self.vertex_heap.indices.buffer,
|
|
||||||
.offset = @intCast(index_offset * @sizeOf(formats.Index)),
|
|
||||||
.count = @intCast(mesh.indices.len),
|
|
||||||
.type = gl.UNSIGNED_INT,
|
|
||||||
.base_vertex = @intCast(vertex_offset),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
self.rw_lock.lock();
|
self.rw_lock.lock();
|
||||||
defer self.rw_lock.unlock();
|
defer self.rw_lock.unlock();
|
||||||
|
|
||||||
try self.loaded_assets.put(self.allocator, id, .{ .mesh = loaded_mesh });
|
try self.loading_assets.put(self.allocator, id, .{ .mesh = loading_mesh });
|
||||||
try self.modified_times.put(self.allocator, id, data.modified);
|
try self.modified_times.put(self.allocator, id, data.modified);
|
||||||
}
|
}
|
||||||
return loaded_mesh;
|
|
||||||
|
return NullMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadTexture(self: *AssetManager, id: AssetId) LoadedTexture {
|
fn loadTexture(self: *AssetManager, id: AssetId) LoadedTexture {
|
||||||
@ -770,6 +887,8 @@ fn loadTextureErr(self: *AssetManager, id: AssetId) !LoadedTexture {
|
|||||||
offset += texture.data[mip].len;
|
offset += texture.data[mip].len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.gc.device.unmapMemory(staging_mem);
|
||||||
|
|
||||||
const cmds = try self.command_pool.allocateCommandBuffer();
|
const cmds = try self.command_pool.allocateCommandBuffer();
|
||||||
|
|
||||||
try cmds.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
try cmds.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||||
@ -881,56 +1000,6 @@ fn loadTextureErr(self: *AssetManager, id: AssetId) !LoadedTexture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return NullTexture;
|
return NullTexture;
|
||||||
|
|
||||||
// return loaded_texture;
|
|
||||||
|
|
||||||
// var name: gl.GLuint = 0;
|
|
||||||
// gl.createTextures(gl.TEXTURE_2D, 1, &name);
|
|
||||||
// if (name == 0) {
|
|
||||||
// return error.GLCreateTexture;
|
|
||||||
// }
|
|
||||||
// errdefer gl.deleteTextures(1, &name);
|
|
||||||
|
|
||||||
// const gl_format: gl.GLenum = switch (texture.header.format) {
|
|
||||||
// .bc7 => gl.COMPRESSED_RGBA_BPTC_UNORM,
|
|
||||||
// .bc5 => gl.COMPRESSED_RG_RGTC2,
|
|
||||||
// .bc6 => gl.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// gl.textureStorage2D(
|
|
||||||
// name,
|
|
||||||
// @intCast(texture.mipLevels()),
|
|
||||||
// gl_format,
|
|
||||||
// @intCast(texture.header.padded_width),
|
|
||||||
// @intCast(texture.header.padded_height),
|
|
||||||
// );
|
|
||||||
// checkGLError();
|
|
||||||
|
|
||||||
// for (0..texture.mipLevels()) |mip_level| {
|
|
||||||
// const desc = texture.getMipDesc(mip_level);
|
|
||||||
// gl.compressedTextureSubImage2D(
|
|
||||||
// name,
|
|
||||||
// @intCast(mip_level),
|
|
||||||
// 0,
|
|
||||||
// 0,
|
|
||||||
// @intCast(desc.width),
|
|
||||||
// @intCast(desc.height),
|
|
||||||
// gl_format,
|
|
||||||
// @intCast(texture.data[mip_level].len),
|
|
||||||
// @ptrCast(texture.data[mip_level].ptr),
|
|
||||||
// );
|
|
||||||
// checkGLError();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const uv_scale = Vec2.new(
|
|
||||||
// @as(f32, @floatFromInt(texture.header.width)) / @as(f32, @floatFromInt(texture.header.padded_width)),
|
|
||||||
// @as(f32, @floatFromInt(texture.header.height)) / @as(f32, @floatFromInt(texture.header.padded_height)),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const handle = gl.GL_ARB_bindless_texture.getTextureHandleARB(name);
|
|
||||||
// gl.GL_ARB_bindless_texture.makeTextureHandleResidentARB(handle);
|
|
||||||
// errdefer gl.GL_ARB_bindless_texture.makeTextureHandleNonResidentARB(handle);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadScene(self: *AssetManager, id: AssetId) LoadedScene {
|
fn loadScene(self: *AssetManager, id: AssetId) LoadedScene {
|
||||||
@ -1002,6 +1071,32 @@ fn loadMaterialErr(self: *AssetManager, id: AssetId) !formats.Material {
|
|||||||
fn finishLoadingAsset(self: *AssetManager, id: AssetId) void {
|
fn finishLoadingAsset(self: *AssetManager, id: AssetId) void {
|
||||||
if (self.resolveLoadingAsset(id)) |loading_asset| {
|
if (self.resolveLoadingAsset(id)) |loading_asset| {
|
||||||
switch (loading_asset.*) {
|
switch (loading_asset.*) {
|
||||||
|
.mesh => |loading_mesh| {
|
||||||
|
{
|
||||||
|
self.rw_lock.lock();
|
||||||
|
defer self.rw_lock.unlock();
|
||||||
|
|
||||||
|
_ = self.loading_assets.remove(id);
|
||||||
|
|
||||||
|
self.loaded_assets.put(self.allocator, id, LoadedAsset{
|
||||||
|
.mesh = LoadedMesh{
|
||||||
|
.aabb = loading_mesh.aabb,
|
||||||
|
.material = loading_mesh.material,
|
||||||
|
.vertex_count = loading_mesh.vertex_count,
|
||||||
|
.index_count = loading_mesh.index_count,
|
||||||
|
.allocation = loading_mesh.allocation,
|
||||||
|
.positions = self.vertex_heap.heap_address + loading_mesh.allocation.positions.offset,
|
||||||
|
.other_data = self.vertex_heap.heap_address + loading_mesh.allocation.other_data.offset,
|
||||||
|
.indices_offset = loading_mesh.allocation.indices.offset,
|
||||||
|
},
|
||||||
|
}) catch @panic("OOM");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.gc.device.freeCommandBuffers(self.command_pool.handle, 1, &.{loading_mesh.command_buffer});
|
||||||
|
self.gc.device.destroyBuffer(loading_mesh.staging_buf, null);
|
||||||
|
self.gc.device.freeMemory(loading_mesh.staging_memory, null);
|
||||||
|
self.gc.device.destroyFence(loading_mesh.transfer_fence, null);
|
||||||
|
},
|
||||||
.texture => |loading_texture| {
|
.texture => |loading_texture| {
|
||||||
{
|
{
|
||||||
self.rw_lock.lock();
|
self.rw_lock.lock();
|
||||||
@ -1037,7 +1132,7 @@ const AssetType = enum {
|
|||||||
const LoadingAsset = union(AssetType) {
|
const LoadingAsset = union(AssetType) {
|
||||||
shader: void,
|
shader: void,
|
||||||
shaderProgram: void,
|
shaderProgram: void,
|
||||||
mesh: void,
|
mesh: LoadingMesh,
|
||||||
texture: LoadingTexture,
|
texture: LoadingTexture,
|
||||||
scene: void,
|
scene: void,
|
||||||
material: void,
|
material: void,
|
||||||
@ -1061,15 +1156,32 @@ const LoadedShaderProgram = struct {
|
|||||||
pipeline: vk.Pipeline,
|
pipeline: vk.Pipeline,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const LoadingMesh = struct {
|
||||||
|
aabb: AABB,
|
||||||
|
material: formats.Material,
|
||||||
|
vertex_count: u32 = 0,
|
||||||
|
index_count: u32 = 0,
|
||||||
|
allocation: VertexBufferHeap.Alloc,
|
||||||
|
|
||||||
|
transfer_fence: vk.Fence,
|
||||||
|
staging_buf: vk.Buffer,
|
||||||
|
staging_memory: vk.DeviceMemory,
|
||||||
|
command_buffer: vk.CommandBuffer,
|
||||||
|
};
|
||||||
|
|
||||||
pub const LoadedMesh = struct {
|
pub const LoadedMesh = struct {
|
||||||
aabb: AABB,
|
aabb: AABB,
|
||||||
heap_handle: VertexBufferHeap.Alloc,
|
allocation: VertexBufferHeap.Alloc,
|
||||||
positions: BufferSlice,
|
|
||||||
normals: BufferSlice,
|
|
||||||
tangents: BufferSlice,
|
|
||||||
uvs: BufferSlice,
|
|
||||||
indices: IndexSlice,
|
|
||||||
material: formats.Material,
|
material: formats.Material,
|
||||||
|
|
||||||
|
vertex_count: u32 = 0,
|
||||||
|
index_count: u32 = 0,
|
||||||
|
|
||||||
|
positions: u64, // Buffer Device Address
|
||||||
|
other_data: u64,
|
||||||
|
|
||||||
|
// Offset from start of buffer
|
||||||
|
indices_offset: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoadingTexture = struct {
|
const LoadingTexture = struct {
|
||||||
@ -1129,53 +1241,6 @@ pub const AABB = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const BufferSlice = struct {
|
|
||||||
buffer: gl.GLuint,
|
|
||||||
offset: gl.GLintptr,
|
|
||||||
stride: gl.GLsizei,
|
|
||||||
|
|
||||||
pub fn bind(self: *const BufferSlice, index: gl.GLuint) void {
|
|
||||||
gl.bindVertexBuffer(index, self.buffer, 0, self.stride);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const IndexSlice = struct {
|
|
||||||
buffer: gl.GLuint,
|
|
||||||
offset: gl.GLuint,
|
|
||||||
count: gl.GLuint,
|
|
||||||
type: gl.GLenum,
|
|
||||||
base_vertex: gl.GLint,
|
|
||||||
|
|
||||||
pub fn bind(self: *const IndexSlice) void {
|
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.buffer);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ShaderType = enum {
|
|
||||||
vertex,
|
|
||||||
fragment,
|
|
||||||
compute,
|
|
||||||
|
|
||||||
pub fn goGLType(self: ShaderType) gl.GLenum {
|
|
||||||
return switch (self) {
|
|
||||||
.vertex => gl.VERTEX_SHADER,
|
|
||||||
.fragment => gl.FRAGMENT_SHADER,
|
|
||||||
.compute => gl.COMPUTE_SHADER,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const VERTEX_DEFINES = "#version 460 core\n#define VERTEX_SHADER 1\n#define VERTEX_EXPORT out\n";
|
|
||||||
const FRAGMENT_DEFINES = "#version 460 core\n#define FRAGMENT_SHADER 1\n#define VERTEX_EXPORT in\n";
|
|
||||||
const COMPUTE_DEFINES = "#version 460 core\n#define COMPUTE_SHADER 1\n";
|
|
||||||
pub fn getDefines(self: ShaderType) []const u8 {
|
|
||||||
return switch (self) {
|
|
||||||
.vertex => VERTEX_DEFINES,
|
|
||||||
.fragment => FRAGMENT_DEFINES,
|
|
||||||
.compute => COMPUTE_DEFINES,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const AssetData = struct {
|
const AssetData = struct {
|
||||||
bytes: []u8,
|
bytes: []u8,
|
||||||
modified: i128,
|
modified: i128,
|
||||||
@ -1190,13 +1255,6 @@ fn loadFile(self: *AssetManager, allocator: std.mem.Allocator, path: []const u8,
|
|||||||
return .{ .bytes = bytes, .modified = meta.modified() };
|
return .{ .bytes = bytes, .modified = meta.modified() };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadShader(self: *AssetManager, id: AssetId, permuted_id: AssetId, defines: []const DefinePair) LoadedShader {
|
|
||||||
return self.loadShaderErr(id, permuted_id, defines) catch |err| {
|
|
||||||
std.log.err("Error: {} when loading shader id {} {s}", .{ err, id, asset_manifest.getPath(id) });
|
|
||||||
return NullShader;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const ShaderTokenizer = struct {
|
const ShaderTokenizer = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
@ -1732,124 +1790,6 @@ test "ShaderTokenizer" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadShaderErr(self: *AssetManager, id: AssetId, permuted_id: AssetId, defines: []const DefinePair) !LoadedShader {
|
|
||||||
const path = asset_manifest.getPath(id);
|
|
||||||
const dir = std.fs.path.dirname(path) orelse @panic("No dir");
|
|
||||||
|
|
||||||
const data = try self.loadFile(self.frame_arena, path, SHADER_MAX_BYTES);
|
|
||||||
|
|
||||||
var included_asset_ids = std.ArrayList(AssetId).init(self.frame_arena);
|
|
||||||
var preprocessed_segments = std.SegmentedList([]const u8, 64){};
|
|
||||||
var final_len: usize = 0;
|
|
||||||
|
|
||||||
// Just append defines here, no need to manually preprocess
|
|
||||||
for (defines) |define| {
|
|
||||||
const define_str = try std.fmt.allocPrint(self.frame_arena, "#define {s} {s}\n", .{ define.key, define.value });
|
|
||||||
try preprocessed_segments.append(self.frame_arena, define_str);
|
|
||||||
final_len += define_str.len;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preprocess
|
|
||||||
{
|
|
||||||
var tokenizer = ShaderTokenizer.init(data.bytes);
|
|
||||||
|
|
||||||
var last_offset: usize = 0;
|
|
||||||
|
|
||||||
var token = tokenizer.next();
|
|
||||||
while (token.type != .End) : (token = tokenizer.next()) {
|
|
||||||
switch (token.type) {
|
|
||||||
.Directive => {
|
|
||||||
if (std.mem.eql(u8, token.text, "include")) {
|
|
||||||
// Append section of text up to this directive
|
|
||||||
try preprocessed_segments.append(self.frame_arena, data.bytes[last_offset..token.start]);
|
|
||||||
final_len += token.start - last_offset;
|
|
||||||
|
|
||||||
const include_path = tokenizer.next();
|
|
||||||
// Next section will start after this directive, this allows replacing #include with its content
|
|
||||||
last_offset = include_path.end;
|
|
||||||
|
|
||||||
if (include_path.type != .String) {
|
|
||||||
return error.InvalidInclude;
|
|
||||||
}
|
|
||||||
|
|
||||||
const included_file_path = try std.fs.path.resolve(self.frame_arena, &.{ dir, include_path.text });
|
|
||||||
|
|
||||||
const included_asset_id = assets.AssetPath.fromString(included_file_path).hash();
|
|
||||||
if (included_asset_id != 0) {
|
|
||||||
const included_shader = self.resolveShaderWithDefines(.{ .id = included_asset_id }, defines);
|
|
||||||
try included_asset_ids.append(included_shader.permuted_id);
|
|
||||||
try preprocessed_segments.append(self.frame_arena, included_shader.source);
|
|
||||||
final_len += included_shader.source.len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const remaining = data.bytes.len - last_offset;
|
|
||||||
if (remaining > 0) {
|
|
||||||
try preprocessed_segments.append(self.frame_arena, data.bytes[last_offset..data.bytes.len]);
|
|
||||||
final_len += remaining;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var result_source = try self.allocator.alloc(u8, final_len);
|
|
||||||
|
|
||||||
// Join source sections
|
|
||||||
{
|
|
||||||
var cursor: usize = 0;
|
|
||||||
var iter = preprocessed_segments.constIterator(0);
|
|
||||||
|
|
||||||
while (iter.next()) |slice| {
|
|
||||||
@memcpy(result_source[cursor .. cursor + slice.len], slice.*);
|
|
||||||
cursor += slice.len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loaded_shader = LoadedShader{ .source = result_source, .permuted_id = permuted_id };
|
|
||||||
{
|
|
||||||
self.rw_lock.lock();
|
|
||||||
defer self.rw_lock.unlock();
|
|
||||||
|
|
||||||
try self.loaded_assets.put(self.allocator, permuted_id, .{ .shader = loaded_shader });
|
|
||||||
try self.modified_times.put(self.allocator, id, data.modified);
|
|
||||||
|
|
||||||
try self.addDependencies(permuted_id, &.{id});
|
|
||||||
try self.addDependencies(permuted_id, included_asset_ids.items);
|
|
||||||
}
|
|
||||||
|
|
||||||
return loaded_shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compileShader(self: *AssetManager, source: []const u8, shader_type: ShaderType) !gl.GLuint {
|
|
||||||
const shader = gl.createShader(shader_type.goGLType());
|
|
||||||
errdefer gl.deleteShader(shader);
|
|
||||||
std.debug.assert(shader != 0); // should only happen if incorect shader type is passed
|
|
||||||
const defines = shader_type.getDefines();
|
|
||||||
// Spirv
|
|
||||||
gl.shaderBinary(1, &shader, 0x9551, source.ptr, @intCast(source.len));
|
|
||||||
gl.compileShader(shader);
|
|
||||||
var success: c_int = 0;
|
|
||||||
gl.getShaderiv(shader, gl.COMPILE_STATUS, &success);
|
|
||||||
if (success == 0) {
|
|
||||||
var info_len: gl.GLint = 0;
|
|
||||||
gl.getShaderiv(shader, gl.INFO_LOG_LENGTH, &info_len);
|
|
||||||
if (info_len > 0) {
|
|
||||||
const info_log = try self.frame_arena.allocSentinel(u8, @intCast(info_len - 1), 0);
|
|
||||||
gl.getShaderInfoLog(shader, @intCast(info_log.len), null, info_log);
|
|
||||||
std.log.err("ERROR::SHADER::COMPILATION_FAILED\n{s}\n{s}\n", .{ defines, info_log });
|
|
||||||
} else {
|
|
||||||
std.log.err("ERROR::SHADER::COMPILIATION_FAILED\n{s}\nNo info log.\n", .{defines});
|
|
||||||
}
|
|
||||||
return error.ShaderCompilationFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn addDependencies(self: *AssetManager, id: AssetId, dependencies: []const AssetId) !void {
|
fn addDependencies(self: *AssetManager, id: AssetId, dependencies: []const AssetId) !void {
|
||||||
{
|
{
|
||||||
const gop = try self.dependencies.getOrPut(self.allocator, id);
|
const gop = try self.dependencies.getOrPut(self.allocator, id);
|
||||||
@ -1882,7 +1822,7 @@ fn freeAsset(self: *AssetManager, asset: *LoadedAsset) void {
|
|||||||
const destroy_queue = &self.frame_state.frame_data[self.frame_state.frame].destroy_queue;
|
const destroy_queue = &self.frame_state.frame_data[self.frame_state.frame].destroy_queue;
|
||||||
switch (asset.*) {
|
switch (asset.*) {
|
||||||
.mesh => |*mesh| {
|
.mesh => |*mesh| {
|
||||||
self.vertex_heap.free(mesh.heap_handle);
|
self.vertex_heap.free(mesh.allocation);
|
||||||
},
|
},
|
||||||
.shader => |*shader| {
|
.shader => |*shader| {
|
||||||
self.allocator.free(shader.source);
|
self.allocator.free(shader.source);
|
||||||
@ -1922,122 +1862,84 @@ const VertexBufferHeap = struct {
|
|||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
pub const Alloc = struct {
|
pub const Alloc = struct {
|
||||||
vertex: BuddyAllocator.Alloc = .{},
|
positions: BuddyAllocator.Alloc = .{},
|
||||||
index: BuddyAllocator.Alloc = .{},
|
other_data: BuddyAllocator.Alloc = .{},
|
||||||
|
indices: BuddyAllocator.Alloc = .{},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Buffer = struct {
|
gc: *GraphicsContext,
|
||||||
buffer: gl.GLuint,
|
buddy: BuddyAllocator,
|
||||||
stride: gl.GLsizei,
|
// Heap contains both vertex and index data, split manually in two
|
||||||
|
heap_memory: vk.DeviceMemory,
|
||||||
|
heap_buffer: vk.Buffer,
|
||||||
|
heap_address: vk.DeviceAddress,
|
||||||
|
|
||||||
pub fn init(name: gl.GLuint, stride: usize) Buffer {
|
pub fn init(allocator: std.mem.Allocator, gc: *GraphicsContext) !Self {
|
||||||
return .{
|
const device = gc.device;
|
||||||
.buffer = name,
|
|
||||||
.stride = @intCast(stride),
|
var buddy = try BuddyAllocator.init(allocator, 64, 23); // 512MB
|
||||||
};
|
errdefer buddy.deinit();
|
||||||
|
|
||||||
|
const heap_buffer = try device.createBuffer(&vk.BufferCreateInfo{
|
||||||
|
.size = buddy.getSize(),
|
||||||
|
.sharing_mode = .exclusive,
|
||||||
|
.usage = .{ .shader_device_address_bit = true, .storage_buffer_bit = true, .transfer_dst_bit = true, .index_buffer_bit = true },
|
||||||
|
}, null);
|
||||||
|
errdefer device.destroyBuffer(heap_buffer, null);
|
||||||
|
const mem_reqs = device.getBufferMemoryRequirements(heap_buffer);
|
||||||
|
|
||||||
|
const heap_memory = try device.allocateMemory(&vk.MemoryAllocateInfo{
|
||||||
|
.p_next = &vk.MemoryAllocateFlagsInfo{
|
||||||
|
.flags = .{ .device_address_bit = true },
|
||||||
|
.device_mask = 0,
|
||||||
|
},
|
||||||
|
.allocation_size = mem_reqs.size,
|
||||||
|
.memory_type_index = gc.memory_config.gpu.type_index,
|
||||||
|
}, null);
|
||||||
|
errdefer device.freeMemory(heap_memory, null);
|
||||||
|
|
||||||
|
try device.bindBufferMemory(heap_buffer, heap_memory, 0);
|
||||||
|
|
||||||
|
const heap_address = device.getBufferDeviceAddress(&vk.BufferDeviceAddressInfo{
|
||||||
|
.buffer = heap_buffer,
|
||||||
|
});
|
||||||
|
if (heap_address == 0) {
|
||||||
|
return error.InvalidBDA;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind(self: *const Buffer, index: gl.GLuint) void {
|
|
||||||
gl.bindVertexBuffer(index, self.buffer, 0, self.stride);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
vertex_buddy: BuddyAllocator,
|
|
||||||
index_buddy: BuddyAllocator,
|
|
||||||
vertices: Buffer,
|
|
||||||
normals: Buffer,
|
|
||||||
tangents: Buffer,
|
|
||||||
uvs: Buffer,
|
|
||||||
indices: Buffer,
|
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator) !Self {
|
|
||||||
var vertex_buddy = try BuddyAllocator.init(allocator, 4096, 13);
|
|
||||||
errdefer vertex_buddy.deinit();
|
|
||||||
|
|
||||||
var index_buddy = try BuddyAllocator.init(allocator, 4096, 13);
|
|
||||||
errdefer index_buddy.deinit();
|
|
||||||
|
|
||||||
// const vertex_buf_size = vertex_buddy.getSize();
|
|
||||||
// const index_buf_size = index_buddy.getSize();
|
|
||||||
|
|
||||||
const bufs = [_]gl.GLuint{ 0, 0, 0, 0, 0 };
|
|
||||||
// gl.createBuffers(bufs.len, &bufs);
|
|
||||||
// errdefer gl.deleteBuffers(bufs.len, &bufs);
|
|
||||||
|
|
||||||
// for (bufs) |buf| {
|
|
||||||
// if (buf == 0) {
|
|
||||||
// return error.BufferAllocationFailed;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
const vertices = Buffer.init(bufs[0], @sizeOf(formats.Vector3));
|
|
||||||
const normals = Buffer.init(bufs[1], @sizeOf(formats.Vector3));
|
|
||||||
const tangents = Buffer.init(bufs[2], @sizeOf(formats.Vector3));
|
|
||||||
const uvs = Buffer.init(bufs[3], @sizeOf(formats.Vector2));
|
|
||||||
const indices = Buffer.init(bufs[4], @sizeOf(formats.Index));
|
|
||||||
|
|
||||||
// gl.namedBufferStorage(
|
|
||||||
// vertices.buffer,
|
|
||||||
// @intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
|
||||||
// null,
|
|
||||||
// gl.DYNAMIC_STORAGE_BIT,
|
|
||||||
// );
|
|
||||||
// gl.namedBufferStorage(
|
|
||||||
// normals.buffer,
|
|
||||||
// @intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
|
||||||
// null,
|
|
||||||
// gl.DYNAMIC_STORAGE_BIT,
|
|
||||||
// );
|
|
||||||
// gl.namedBufferStorage(
|
|
||||||
// tangents.buffer,
|
|
||||||
// @intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
|
||||||
// null,
|
|
||||||
// gl.DYNAMIC_STORAGE_BIT,
|
|
||||||
// );
|
|
||||||
// gl.namedBufferStorage(
|
|
||||||
// uvs.buffer,
|
|
||||||
// @intCast(vertex_buf_size * @sizeOf(formats.Vector2)),
|
|
||||||
// null,
|
|
||||||
// gl.DYNAMIC_STORAGE_BIT,
|
|
||||||
// );
|
|
||||||
// gl.namedBufferStorage(
|
|
||||||
// indices.buffer,
|
|
||||||
// @intCast(index_buf_size * @sizeOf(formats.Index)),
|
|
||||||
// null,
|
|
||||||
// gl.DYNAMIC_STORAGE_BIT,
|
|
||||||
// );
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.vertex_buddy = vertex_buddy,
|
.gc = gc,
|
||||||
.index_buddy = index_buddy,
|
.buddy = buddy,
|
||||||
.vertices = vertices,
|
.heap_memory = heap_memory,
|
||||||
.normals = normals,
|
.heap_buffer = heap_buffer,
|
||||||
.tangents = tangents,
|
.heap_address = heap_address,
|
||||||
.uvs = uvs,
|
|
||||||
.indices = indices,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
self.index_buddy.deinit();
|
self.buddy.deinit();
|
||||||
self.vertex_buddy.deinit();
|
|
||||||
|
|
||||||
const bufs = [_]gl.GLuint{ self.vertices, self.normals, self.tangents, self.uvs, self.indices };
|
|
||||||
gl.deleteBuffers(bufs.len, &bufs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alloc(self: *Self, vertex_len: usize, index_len: usize) !Alloc {
|
pub fn alloc(self: *Self, vertex_len: usize, index_len: usize) !Alloc {
|
||||||
const vertex_alloc = try self.vertex_buddy.alloc(vertex_len);
|
const positions_alloc = try self.buddy.alloc(@sizeOf(formats.Vector3) * vertex_len);
|
||||||
errdefer self.vertex_buddy.free(vertex_alloc);
|
errdefer self.buddy.free(positions_alloc);
|
||||||
|
|
||||||
const index_alloc = try self.index_buddy.alloc(index_len);
|
const other_data_alloc = try self.buddy.alloc(@sizeOf(formats.Mesh.VertexDataForBasePass) * vertex_len);
|
||||||
errdefer self.index_buddy.free(index_alloc);
|
errdefer self.buddy.free(other_data_alloc);
|
||||||
|
|
||||||
return Alloc{ .vertex = vertex_alloc, .index = index_alloc };
|
const index_alloc = try self.buddy.alloc(index_len);
|
||||||
|
errdefer self.buddy.free(index_alloc);
|
||||||
|
|
||||||
|
return Alloc{
|
||||||
|
.positions = positions_alloc,
|
||||||
|
.other_data = other_data_alloc,
|
||||||
|
.indices = index_alloc,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free(self: *Self, allocation: Alloc) void {
|
pub fn free(self: *Self, allocation: Alloc) void {
|
||||||
self.vertex_buddy.free(allocation.vertex);
|
self.buddy.free(allocation.positions);
|
||||||
self.index_buddy.free(allocation.index);
|
self.buddy.free(allocation.other_data);
|
||||||
|
self.buddy.free(allocation.indices);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1177,7 +1177,7 @@ pub fn finish(self: *Render) void {
|
|||||||
gl.bindVertexArray(self.z_prepass_vao);
|
gl.bindVertexArray(self.z_prepass_vao);
|
||||||
gl.depthFunc(gl.LESS);
|
gl.depthFunc(gl.LESS);
|
||||||
|
|
||||||
self.assetman.vertex_heap.vertices.bind(Render.Attrib.Position.value());
|
self.assetman.vertex_heap.vertex_data.bind(Render.Attrib.Position.value());
|
||||||
checkGLError();
|
checkGLError();
|
||||||
self.assetman.vertex_heap.uvs.bind(Render.Attrib.UV.value());
|
self.assetman.vertex_heap.uvs.bind(Render.Attrib.UV.value());
|
||||||
checkGLError();
|
checkGLError();
|
||||||
@ -1210,7 +1210,7 @@ pub fn finish(self: *Render) void {
|
|||||||
checkGLError();
|
checkGLError();
|
||||||
self.assetman.vertex_heap.uvs.bind(Render.Attrib.UV.value());
|
self.assetman.vertex_heap.uvs.bind(Render.Attrib.UV.value());
|
||||||
checkGLError();
|
checkGLError();
|
||||||
self.assetman.vertex_heap.vertices.bind(Render.Attrib.Position.value());
|
self.assetman.vertex_heap.vertex_data.bind(Render.Attrib.Position.value());
|
||||||
checkGLError();
|
checkGLError();
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.assetman.vertex_heap.indices.buffer);
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.assetman.vertex_heap.indices.buffer);
|
||||||
checkGLError();
|
checkGLError();
|
||||||
@ -1439,7 +1439,7 @@ fn renderShadow(self: *Render, frustum: *const math.Frustum) void {
|
|||||||
_ = frustum; // autofix
|
_ = frustum; // autofix
|
||||||
const zone = tracy.initZone(@src(), .{ .name = "Render.renderShadow" });
|
const zone = tracy.initZone(@src(), .{ .name = "Render.renderShadow" });
|
||||||
defer zone.deinit();
|
defer zone.deinit();
|
||||||
self.assetman.vertex_heap.vertices.bind(Render.Attrib.Position.value());
|
self.assetman.vertex_heap.vertex_data.bind(Render.Attrib.Position.value());
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.assetman.vertex_heap.indices.buffer);
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.assetman.vertex_heap.indices.buffer);
|
||||||
|
|
||||||
// TODO: this wastes space in temp allocator
|
// TODO: this wastes space in temp allocator
|
||||||
|
@ -8,6 +8,7 @@ const za = @import("zalgebra");
|
|||||||
const Vec3 = za.Vec3;
|
const Vec3 = za.Vec3;
|
||||||
const Mat4 = za.Mat4;
|
const Mat4 = za.Mat4;
|
||||||
const common = @import("common.zig");
|
const common = @import("common.zig");
|
||||||
|
const formats = @import("formats.zig");
|
||||||
const render_common = @import("render_common.zig");
|
const render_common = @import("render_common.zig");
|
||||||
const MAX_FRAME_LAG = render_common.MAX_FRAME_LAG;
|
const MAX_FRAME_LAG = render_common.MAX_FRAME_LAG;
|
||||||
const DeferredDestroyQueue = render_common.DeferredDestroyQueue;
|
const DeferredDestroyQueue = render_common.DeferredDestroyQueue;
|
||||||
@ -44,6 +45,9 @@ command_pool: GraphicsContext.CommandPool,
|
|||||||
vulkan_frame_arena: VulkanPerFrameArena,
|
vulkan_frame_arena: VulkanPerFrameArena,
|
||||||
camera: *Camera = &default_camera,
|
camera: *Camera = &default_camera,
|
||||||
|
|
||||||
|
draw_commands: [4096]DrawCommand = undefined,
|
||||||
|
draw_command_count: u32 = 0,
|
||||||
|
|
||||||
// Global sampler to use for reading screen color in post processing
|
// Global sampler to use for reading screen color in post processing
|
||||||
screen_color_sampler: vk.Sampler = .null_handle,
|
screen_color_sampler: vk.Sampler = .null_handle,
|
||||||
screen_color_sampler_descriptor_handle: DescriptorManager.DescriptorHandle = .{},
|
screen_color_sampler_descriptor_handle: DescriptorManager.DescriptorHandle = .{},
|
||||||
@ -424,7 +428,18 @@ fn pushConstants(self: *Render2, cmds: GraphicsContext.CommandBuffer, stage_flag
|
|||||||
cmds.pushConstants(self.descriptorman.pipeline_layout, stage_flags, 0, @sizeOf(@TypeOf(value)), &value);
|
cmds.pushConstants(self.descriptorman.pipeline_layout, stage_flags, 0, @sizeOf(@TypeOf(value)), &value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(self: *Render2) !void {
|
pub const DrawCommand = struct {
|
||||||
|
mesh: AssetManager.Handle.Mesh,
|
||||||
|
material_override: ?formats.Material,
|
||||||
|
transform: Mat4,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn draw(self: *Render2, cmd: DrawCommand) void {
|
||||||
|
self.draw_commands[self.draw_command_count] = cmd;
|
||||||
|
self.draw_command_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self: *Render2) !void {
|
||||||
const gc = self.gc;
|
const gc = self.gc;
|
||||||
const device = gc.device;
|
const device = gc.device;
|
||||||
const frame = &self.frame_state.frame_data[self.frame_state.frame];
|
const frame = &self.frame_state.frame_data[self.frame_state.frame];
|
||||||
@ -573,11 +588,6 @@ pub fn draw(self: *Render2) !void {
|
|||||||
cmds.bindPipeline(.graphics, unlit.pipeline);
|
cmds.bindPipeline(.graphics, unlit.pipeline);
|
||||||
cmds.bindDescriptorSets(.graphics, self.descriptorman.pipeline_layout, 0, 1, &.{global_descriptor_set}, 0, null);
|
cmds.bindDescriptorSets(.graphics, self.descriptorman.pipeline_layout, 0, 1, &.{global_descriptor_set}, 0, null);
|
||||||
|
|
||||||
self.pushConstants(cmds, .{ .vertex_bit = true, .fragment_bit = true }, UnlitPushConstants{
|
|
||||||
.color_texture = self.assetman.resolveTexture(a.Textures.bunny_tex1).descriptor_handle.index,
|
|
||||||
.color_sampler = self.screen_color_sampler_descriptor_handle.index,
|
|
||||||
});
|
|
||||||
|
|
||||||
cmds.setViewportWithCount(1, &.{vk.Viewport{
|
cmds.setViewportWithCount(1, &.{vk.Viewport{
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
@ -591,7 +601,21 @@ pub fn draw(self: *Render2) !void {
|
|||||||
.extent = gc.swapchain_extent,
|
.extent = gc.swapchain_extent,
|
||||||
}});
|
}});
|
||||||
|
|
||||||
cmds.draw(6, 2, 0, 0);
|
cmds.bindIndexBuffer(self.assetman.vertex_heap.heap_buffer, 0, vk.IndexType.uint32);
|
||||||
|
|
||||||
|
for (self.draw_commands[0..self.draw_command_count]) |cmd| {
|
||||||
|
const mesh = self.assetman.resolveMesh(cmd.mesh);
|
||||||
|
|
||||||
|
self.pushConstants(cmds, .{ .vertex_bit = true, .fragment_bit = true }, UnlitPushConstants{
|
||||||
|
.local_to_world = cmd.transform,
|
||||||
|
.positions_address = mesh.positions,
|
||||||
|
.other_data_address = mesh.other_data,
|
||||||
|
.color_texture = self.assetman.resolveTexture(a.Textures.bunny_tex1).descriptor_handle.index,
|
||||||
|
.color_sampler = self.screen_color_sampler_descriptor_handle.index,
|
||||||
|
});
|
||||||
|
|
||||||
|
cmds.drawIndexed(mesh.index_count, 1, mesh.indices_offset, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post process and convert from f16 to rgba8_unorm
|
// Post process and convert from f16 to rgba8_unorm
|
||||||
@ -668,6 +692,8 @@ pub fn draw(self: *Render2) !void {
|
|||||||
}
|
}
|
||||||
try cmds.endCommandBuffer();
|
try cmds.endCommandBuffer();
|
||||||
|
|
||||||
|
self.draw_command_count = 0;
|
||||||
|
|
||||||
try gc.queues.graphics.submit(
|
try gc.queues.graphics.submit(
|
||||||
&GraphicsContext.SubmitInfo{
|
&GraphicsContext.SubmitInfo{
|
||||||
.wait_semaphores = &.{frame.acquire_swapchain_image},
|
.wait_semaphores = &.{frame.acquire_swapchain_image},
|
||||||
@ -716,6 +742,9 @@ const GlobalUniform = extern struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const UnlitPushConstants = extern struct {
|
const UnlitPushConstants = extern struct {
|
||||||
|
local_to_world: Mat4,
|
||||||
|
positions_address: u64,
|
||||||
|
other_data_address: u64,
|
||||||
color_texture: u32,
|
color_texture: u32,
|
||||||
color_sampler: u32,
|
color_sampler: u32,
|
||||||
};
|
};
|
||||||
|
@ -23,14 +23,19 @@ pub const AABB = extern struct {
|
|||||||
};
|
};
|
||||||
pub const Index = u32;
|
pub const Index = u32;
|
||||||
|
|
||||||
|
/// On gpu positions will go packed into one buffer normals, tangents and uvs will go to another
|
||||||
|
/// buffer. This is to allow a more efficient depth only pass that requires positions only.
|
||||||
pub const Mesh = struct {
|
pub const Mesh = struct {
|
||||||
|
pub const VertexDataForBasePass = extern struct {
|
||||||
|
normal: Vector3,
|
||||||
|
tangent: Vector3,
|
||||||
|
uv: Vector2,
|
||||||
|
};
|
||||||
|
|
||||||
aabb: AABB,
|
aabb: AABB,
|
||||||
material: Material,
|
material: Material,
|
||||||
|
positions: []align(1) Vector3,
|
||||||
vertices: []align(1) Vector3,
|
other_data: []align(1) VertexDataForBasePass,
|
||||||
normals: []align(1) Vector3,
|
|
||||||
tangents: []align(1) Vector3,
|
|
||||||
uvs: []align(1) Vector2,
|
|
||||||
indices: []align(1) Index,
|
indices: []align(1) Index,
|
||||||
|
|
||||||
// This will panic if data is incorrect
|
// This will panic if data is incorrect
|
||||||
@ -61,15 +66,11 @@ pub const Mesh = struct {
|
|||||||
offset += @sizeOf(usize);
|
offset += @sizeOf(usize);
|
||||||
|
|
||||||
size = vert_len * @sizeOf(Vector3);
|
size = vert_len * @sizeOf(Vector3);
|
||||||
const vertices = std.mem.bytesAsSlice(Vector3, buffer[offset .. offset + size]);
|
const positions = std.mem.bytesAsSlice(Vector3, buffer[offset .. offset + size]);
|
||||||
offset += size;
|
|
||||||
const normals = std.mem.bytesAsSlice(Vector3, buffer[offset .. offset + size]);
|
|
||||||
offset += size;
|
|
||||||
const tangents = std.mem.bytesAsSlice(Vector3, buffer[offset .. offset + size]);
|
|
||||||
offset += size;
|
offset += size;
|
||||||
|
|
||||||
size = vert_len * @sizeOf(Vector2);
|
size = vert_len * @sizeOf(VertexDataForBasePass);
|
||||||
const uvs = std.mem.bytesAsSlice(Vector2, buffer[offset .. offset + size]);
|
const other_data = std.mem.bytesAsSlice(VertexDataForBasePass, buffer[offset .. offset + size]);
|
||||||
offset += size;
|
offset += size;
|
||||||
|
|
||||||
size = ind_len * @sizeOf(Index);
|
size = ind_len * @sizeOf(Index);
|
||||||
@ -79,17 +80,15 @@ pub const Mesh = struct {
|
|||||||
return .{
|
return .{
|
||||||
.aabb = aabb,
|
.aabb = aabb,
|
||||||
.material = material.*,
|
.material = material.*,
|
||||||
.vertices = vertices,
|
.positions = positions,
|
||||||
.normals = normals,
|
.other_data = other_data,
|
||||||
.tangents = tangents,
|
|
||||||
.uvs = uvs,
|
|
||||||
.indices = indices,
|
.indices = indices,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn writeMesh(writer: anytype, value: Mesh, endian: std.builtin.Endian) !void {
|
pub fn writeMesh(writer: anytype, value: Mesh, endian: std.builtin.Endian) !void {
|
||||||
std.debug.assert(value.vertices.len == value.normals.len);
|
std.debug.assert(value.positions.len == value.other_data.len);
|
||||||
|
|
||||||
// AABB
|
// AABB
|
||||||
{
|
{
|
||||||
@ -100,20 +99,16 @@ pub fn writeMesh(writer: anytype, value: Mesh, endian: std.builtin.Endian) !void
|
|||||||
try writer.writeStruct(value.material);
|
try writer.writeStruct(value.material);
|
||||||
|
|
||||||
// Sizes
|
// Sizes
|
||||||
try writer.writeInt(usize, value.vertices.len, endian);
|
try writer.writeInt(usize, value.positions.len, endian);
|
||||||
try writer.writeInt(usize, value.indices.len, endian);
|
try writer.writeInt(usize, value.indices.len, endian);
|
||||||
|
|
||||||
for (value.vertices) |v| {
|
for (value.positions) |v| {
|
||||||
try writeVector3(writer, v, endian);
|
try writeVector3(writer, v, endian);
|
||||||
}
|
}
|
||||||
for (value.normals) |n| {
|
for (value.other_data) |d| {
|
||||||
try writeVector3(writer, n, endian);
|
try writeVector3(writer, d.normal, endian);
|
||||||
}
|
try writeVector3(writer, d.tangent, endian);
|
||||||
for (value.tangents) |t| {
|
try writeVector2(writer, d.uv, endian);
|
||||||
try writeVector3(writer, t, endian);
|
|
||||||
}
|
|
||||||
for (value.uvs) |uv| {
|
|
||||||
try writeVector2(writer, uv, endian);
|
|
||||||
}
|
}
|
||||||
for (value.indices) |i| {
|
for (value.indices) |i| {
|
||||||
try writer.writeInt(Index, i, endian);
|
try writer.writeInt(Index, i, endian);
|
||||||
|
162
src/game.zig
162
src/game.zig
@ -79,6 +79,8 @@ fn game_init_window_err(global_allocator: std.mem.Allocator) !void {
|
|||||||
.height = globals.DEFAULT_HEIGHT,
|
.height = globals.DEFAULT_HEIGHT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: move this into game_init so that if game is recreated vulkan device is also recreated.
|
||||||
|
// This means all gpu resources will be destroyed together with the device. Seems like an easier way to handle this case
|
||||||
try globals.g_init.gc.init(global_allocator, window);
|
try globals.g_init.gc.init(global_allocator, window);
|
||||||
|
|
||||||
const version = &globals.g_init.syswm_info.version;
|
const version = &globals.g_init.syswm_info.version;
|
||||||
@ -234,62 +236,62 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
// Plane
|
// Plane
|
||||||
// _ = globals.g_mem.world.addEntity(.{
|
_ = globals.g_mem.world.addEntity(.{
|
||||||
// .flags = .{ .mesh = true },
|
.flags = .{ .mesh = true },
|
||||||
// .transform = .{ .scale = Vec3.one().scale(10) },
|
.transform = .{ .scale = Vec3.one().scale(10) },
|
||||||
// .mesh = .{
|
.mesh = .{
|
||||||
// .handle = a.Meshes.plane.Plane,
|
.handle = a.Meshes.plane.Plane,
|
||||||
// .material = .{
|
.material = .{
|
||||||
// .albedo = Vec4.one(),
|
.albedo = Vec4.one(),
|
||||||
// .normal_map = a.Textures.@"tile.norm",
|
.normal_map = a.Textures.@"tile.norm",
|
||||||
// },
|
},
|
||||||
// .override_material = true,
|
.override_material = true,
|
||||||
// },
|
},
|
||||||
// });
|
});
|
||||||
|
|
||||||
// 10 dielectric bunnies
|
// 10 dielectric bunnies
|
||||||
// {
|
{
|
||||||
// for (0..100) |y| {
|
for (0..100) |y| {
|
||||||
// for (0..1) |x| {
|
for (0..1) |x| {
|
||||||
// _ = globals.g_mem.world.addEntity(.{
|
_ = 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) },
|
.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 },
|
.flags = .{ .mesh = true },
|
||||||
// .mesh = .{
|
.mesh = .{
|
||||||
// .handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1,
|
.handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1,
|
||||||
// .material = .{
|
.material = .{
|
||||||
// .albedo_map = a.Textures.bunny_tex1,
|
.albedo_map = a.Textures.bunny_tex1,
|
||||||
// // .normal_map = a.Textures.@"tile.norm",
|
// .normal_map = a.Textures.@"tile.norm",
|
||||||
// .roughness = @as(f32, @floatFromInt(y)) / 100.0,
|
.roughness = @as(f32, @floatFromInt(y)) / 100.0,
|
||||||
// },
|
},
|
||||||
// .override_material = true,
|
.override_material = true,
|
||||||
// },
|
},
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// // 10 metallic bunnies
|
// 10 metallic bunnies
|
||||||
// {
|
{
|
||||||
// for (0..10) |i| {
|
for (0..10) |i| {
|
||||||
// _ = globals.g_mem.world.addEntity(.{
|
_ = globals.g_mem.world.addEntity(.{
|
||||||
// .transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(i)) * 0.3 - 0.3 * 4.5, 0.3, 0) },
|
.transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(i)) * 0.3 - 0.3 * 4.5, 0.3, 0) },
|
||||||
|
|
||||||
// .flags = .{ .mesh = true },
|
.flags = .{ .mesh = true },
|
||||||
// .mesh = .{
|
.mesh = .{
|
||||||
// .handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1,
|
.handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1,
|
||||||
// .material = .{
|
.material = .{
|
||||||
// .blend_mode = .AlphaBlend,
|
.blend_mode = .AlphaBlend,
|
||||||
// .albedo = Vec4.new(1.000, 0.766, 0.336, 0.5),
|
.albedo = Vec4.new(1.000, 0.766, 0.336, 0.5),
|
||||||
// // .albedo_map = a.Textures.bunny_tex1,
|
// .albedo_map = a.Textures.bunny_tex1,
|
||||||
// // .normal_map = a.Textures.@"tile.norm",
|
// .normal_map = a.Textures.@"tile.norm",
|
||||||
// .roughness = @as(f32, @floatFromInt(i + 1)) / 10.0,
|
.roughness = @as(f32, @floatFromInt(i + 1)) / 10.0,
|
||||||
// .metallic = 1.0,
|
.metallic = 1.0,
|
||||||
// },
|
},
|
||||||
// .override_material = true,
|
.override_material = true,
|
||||||
// },
|
},
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// const scene = globals.g_mem.world.createScene(globals.g_assetman.resolveScene(a.Scenes.bistro.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");
|
// const ent = globals.g_mem.world.getEntity(scene) orelse @panic("WTF");
|
||||||
@ -461,14 +463,11 @@ export fn game_update() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gmem.render2.draw() catch @panic("RENDER ERROR");
|
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
if (false) {
|
{
|
||||||
const zone = tracy.initZone(@src(), .{ .name = "game.render()" });
|
const zone = tracy.initZone(@src(), .{ .name = "game.render()" });
|
||||||
defer zone.deinit();
|
defer zone.deinit();
|
||||||
gmem.render.begin();
|
defer gmem.render2.finish() catch @panic("render.finish()");
|
||||||
defer gmem.render.finish();
|
|
||||||
|
|
||||||
// Collect point lights
|
// Collect point lights
|
||||||
{
|
{
|
||||||
@ -478,46 +477,43 @@ export fn game_update() bool {
|
|||||||
|
|
||||||
if (ent.data.flags.mesh) {
|
if (ent.data.flags.mesh) {
|
||||||
const mat_override: ?formats.Material = if (ent.data.mesh.override_material) ent.data.mesh.material else null;
|
const mat_override: ?formats.Material = if (ent.data.mesh.override_material) ent.data.mesh.material else null;
|
||||||
gmem.render.draw(.{
|
gmem.render2.draw(.{
|
||||||
.mesh = ent.data.mesh.handle,
|
.mesh = ent.data.mesh.handle,
|
||||||
.material_override = mat_override,
|
.material_override = mat_override,
|
||||||
.transform = ent.globalMatrix(&gmem.world).*,
|
.transform = ent.globalMatrix(&gmem.world).*,
|
||||||
});
|
});
|
||||||
} else if (ent.data.flags.point_light) {
|
} else if (ent.data.flags.point_light) {
|
||||||
gmem.render.draw(.{
|
gmem.render2.draw(.{
|
||||||
.mesh = a.Meshes.sphere.Icosphere,
|
.mesh = a.Meshes.sphere.Icosphere,
|
||||||
.material_override = .{ .albedo = Vec4.new(0, 0, 0, 1), .emission = ent.data.light.premultipliedColor() },
|
.material_override = .{ .albedo = Vec4.new(0, 0, 0, 1), .emission = ent.data.light.premultipliedColor() },
|
||||||
.transform = ent.globalMatrix(&gmem.world).*,
|
.transform = ent.globalMatrix(&gmem.world).*,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ent.data.flags.point_light) {
|
// if (ent.data.flags.point_light) {
|
||||||
const pos = ent.globalMatrix(&gmem.world).extractTranslation();
|
// const pos = ent.globalMatrix(&gmem.world).extractTranslation();
|
||||||
const color = ent.data.light.premultipliedColor();
|
// const color = ent.data.light.premultipliedColor();
|
||||||
|
|
||||||
gmem.render.drawLight(.{
|
// gmem.render.drawLight(.{
|
||||||
.point = .{
|
// .point = .{
|
||||||
.pos = pos,
|
// .pos = pos,
|
||||||
.radius = ent.data.point_light.radius,
|
// .radius = ent.data.point_light.radius,
|
||||||
.color = color,
|
// .color = color,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
if (ent.data.flags.dir_light) {
|
// if (ent.data.flags.dir_light) {
|
||||||
const dir4 = ent.globalMatrix(&gmem.world).mulByVec4(Vec4.forward());
|
// const dir4 = ent.globalMatrix(&gmem.world).mulByVec4(Vec4.forward());
|
||||||
const color = ent.data.light.premultipliedColor();
|
// const color = ent.data.light.premultipliedColor();
|
||||||
|
|
||||||
gmem.render.drawLight(.{
|
// gmem.render.drawLight(.{
|
||||||
.directional = .{
|
// .directional = .{
|
||||||
.dir = dir4.toVec3(),
|
// .dir = dir4.toVec3(),
|
||||||
.color = color,
|
// .color = color,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: get rid of this
|
|
||||||
gmem.render.flushUBOs();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,10 @@ const scene_formats = [_][]const u8{
|
|||||||
".glb",
|
".glb",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn float(int: anytype) f32 {
|
||||||
|
return @floatFromInt(int);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resolveAssetTypeByExtension(path: []const u8) ?AssetType {
|
pub fn resolveAssetTypeByExtension(path: []const u8) ?AssetType {
|
||||||
for (scene_formats) |ext| {
|
for (scene_formats) |ext| {
|
||||||
if (std.mem.endsWith(u8, path, ext)) {
|
if (std.mem.endsWith(u8, path, ext)) {
|
||||||
@ -498,30 +502,28 @@ fn processMesh(allocator: std.mem.Allocator, scene: *const c.aiScene, material_o
|
|||||||
if (mesh.mTextureCoords[0] == null) return error.MissingUVs;
|
if (mesh.mTextureCoords[0] == null) return error.MissingUVs;
|
||||||
if (mesh.mNumUVComponents[0] != 2) return error.WrongUVComponents;
|
if (mesh.mNumUVComponents[0] != 2) return error.WrongUVComponents;
|
||||||
|
|
||||||
var vertices = try allocator.alloc(Vector3, @intCast(mesh.mNumVertices));
|
var positions = try allocator.alloc(Vector3, @intCast(mesh.mNumVertices));
|
||||||
var normals = try allocator.alloc(Vector3, @intCast(mesh.mNumVertices));
|
var other_data = try allocator.alloc(formats.Mesh.VertexDataForBasePass, @intCast(mesh.mNumVertices));
|
||||||
var tangents = try allocator.alloc(Vector3, @intCast(mesh.mNumVertices));
|
|
||||||
var uvs = try allocator.alloc(Vector2, @intCast(mesh.mNumVertices));
|
|
||||||
|
|
||||||
var indices = try allocator.alloc(formats.Index, @intCast(mesh.mNumFaces * 3)); // triangles
|
var indices = try allocator.alloc(formats.Index, @intCast(mesh.mNumFaces * 3)); // triangles
|
||||||
|
|
||||||
for (0..mesh.mNumVertices) |i| {
|
for (0..mesh.mNumVertices) |i| {
|
||||||
vertices[i] = .{
|
positions[i] = .{
|
||||||
.x = mesh.mVertices[i].x,
|
.x = mesh.mVertices[i].x,
|
||||||
.y = mesh.mVertices[i].y,
|
.y = mesh.mVertices[i].y,
|
||||||
.z = mesh.mVertices[i].z,
|
.z = mesh.mVertices[i].z,
|
||||||
};
|
};
|
||||||
normals[i] = .{
|
other_data[i].normal = .{
|
||||||
.x = mesh.mNormals[i].x,
|
.x = mesh.mNormals[i].x,
|
||||||
.y = mesh.mNormals[i].y,
|
.y = mesh.mNormals[i].y,
|
||||||
.z = mesh.mNormals[i].z,
|
.z = mesh.mNormals[i].z,
|
||||||
};
|
};
|
||||||
tangents[i] = .{
|
other_data[i].tangent = .{
|
||||||
.x = mesh.mTangents[i].x,
|
.x = mesh.mTangents[i].x,
|
||||||
.y = mesh.mTangents[i].y,
|
.y = mesh.mTangents[i].y,
|
||||||
.z = mesh.mTangents[i].z,
|
.z = mesh.mTangents[i].z,
|
||||||
};
|
};
|
||||||
uvs[i] = .{
|
other_data[i].uv = .{
|
||||||
.x = mesh.mTextureCoords[0][i].x,
|
.x = mesh.mTextureCoords[0][i].x,
|
||||||
.y = mesh.mTextureCoords[0][i].y,
|
.y = mesh.mTextureCoords[0][i].y,
|
||||||
};
|
};
|
||||||
@ -554,10 +556,8 @@ fn processMesh(allocator: std.mem.Allocator, scene: *const c.aiScene, material_o
|
|||||||
.z = mesh.mAABB.mMax.z,
|
.z = mesh.mAABB.mMax.z,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.vertices = vertices,
|
.positions = positions,
|
||||||
.normals = normals,
|
.other_data = other_data,
|
||||||
.tangents = tangents,
|
|
||||||
.uvs = uvs,
|
|
||||||
.indices = indices,
|
.indices = indices,
|
||||||
.material = material,
|
.material = material,
|
||||||
};
|
};
|
||||||
@ -593,7 +593,7 @@ fn processShader(allocator: std.mem.Allocator, flags: []const []const u8, input:
|
|||||||
const compile_result = try std.process.Child.run(.{
|
const compile_result = try std.process.Child.run(.{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.argv = try std.mem.concat(allocator, []const u8, &.{
|
.argv = try std.mem.concat(allocator, []const u8, &.{
|
||||||
&.{ "glslc", "--target-env=vulkan1.3", "-std=460core", "-g", "-o", "-" },
|
&.{ "glslc", "--target-env=vulkan1.3", "-std=460core", "-g", "-O0", "-o", "-" },
|
||||||
if (maybe_dep_file) |dep| &.{ "-MD", "-MF", dep } else &.{},
|
if (maybe_dep_file) |dep| &.{ "-MD", "-MF", dep } else &.{},
|
||||||
flags,
|
flags,
|
||||||
&.{input},
|
&.{input},
|
||||||
@ -821,7 +821,7 @@ fn processTexture(allocator: std.mem.Allocator, texture_type: TextureType, conte
|
|||||||
|
|
||||||
const mip_levels_to_gen = 1 + @as(
|
const mip_levels_to_gen = 1 + @as(
|
||||||
u32,
|
u32,
|
||||||
@intFromFloat(@log2(@as(f32, @floatFromInt(@max(width, height))))),
|
@intFromFloat(@log2(float(@max(width, height)))),
|
||||||
);
|
);
|
||||||
var actual_mip_count: usize = 1;
|
var actual_mip_count: usize = 1;
|
||||||
|
|
||||||
@ -972,10 +972,10 @@ fn premultiplyAlpha(img: []u8) void {
|
|||||||
for (0..img.len / 4) |i| {
|
for (0..img.len / 4) |i| {
|
||||||
const pixel = img[i * 4 .. i * 4 + 4];
|
const pixel = img[i * 4 .. i * 4 + 4];
|
||||||
|
|
||||||
const r = @as(f32, @floatFromInt(pixel[0])) / 255.0;
|
const r = float(pixel[0]) / 255.0;
|
||||||
const g = @as(f32, @floatFromInt(pixel[1])) / 255.0;
|
const g = float(pixel[1]) / 255.0;
|
||||||
const b = @as(f32, @floatFromInt(pixel[2])) / 255.0;
|
const b = float(pixel[2]) / 255.0;
|
||||||
const a = @as(f32, @floatFromInt(pixel[3])) / 255.0;
|
const a = float(pixel[3]) / 255.0;
|
||||||
|
|
||||||
pixel[0] = @intFromFloat(r * a * 255.0);
|
pixel[0] = @intFromFloat(r * a * 255.0);
|
||||||
pixel[1] = @intFromFloat(g * a * 255.0);
|
pixel[1] = @intFromFloat(g * a * 255.0);
|
||||||
@ -1040,8 +1040,8 @@ inline fn loadColorVec2(pixel: []const u8) @Vector(2, f32) {
|
|||||||
std.debug.assert(pixel.len >= 2);
|
std.debug.assert(pixel.len >= 2);
|
||||||
|
|
||||||
return @Vector(2, f32){
|
return @Vector(2, f32){
|
||||||
@as(f32, @floatFromInt(pixel[0])),
|
float(pixel[0]),
|
||||||
@as(f32, @floatFromInt(pixel[1])),
|
float(pixel[1]),
|
||||||
} / @as(@Vector(2, f32), @splat(255.0));
|
} / @as(@Vector(2, f32), @splat(255.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1060,10 +1060,10 @@ inline fn loadColorVec4(pixel: []const u8) @Vector(4, f32) {
|
|||||||
std.debug.assert(pixel.len >= 4);
|
std.debug.assert(pixel.len >= 4);
|
||||||
|
|
||||||
return @Vector(4, f32){
|
return @Vector(4, f32){
|
||||||
@as(f32, @floatFromInt(pixel[0])),
|
float(pixel[0]),
|
||||||
@as(f32, @floatFromInt(pixel[1])),
|
float(pixel[1]),
|
||||||
@as(f32, @floatFromInt(pixel[2])),
|
float(pixel[2]),
|
||||||
@as(f32, @floatFromInt(pixel[3])),
|
float(pixel[3]),
|
||||||
} / @as(@Vector(4, f32), @splat(255.0));
|
} / @as(@Vector(4, f32), @splat(255.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user