diff options
Diffstat (limited to 'src/renderer')
-rw-r--r-- | src/renderer/backends/backend_opengl.c | 4 | ||||
-rw-r--r-- | src/renderer/backends/backend_vulkan.c | 133 | ||||
-rw-r--r-- | src/renderer/render.c | 181 | ||||
-rw-r--r-- | src/renderer/render.h | 4 | ||||
-rw-r--r-- | src/renderer/render_backend.h | 2 | ||||
-rw-r--r-- | src/renderer/render_types.h | 114 |
6 files changed, 324 insertions, 114 deletions
diff --git a/src/renderer/backends/backend_opengl.c b/src/renderer/backends/backend_opengl.c index ffeb051..7467416 100644 --- a/src/renderer/backends/backend_opengl.c +++ b/src/renderer/backends/backend_opengl.c @@ -1,4 +1,5 @@ #include <stdlib.h> +#include "camera.h" #define CEL_PLATFORM_LINUX #include "defines.h" @@ -42,6 +43,9 @@ bool gfx_backend_init(renderer *ren) { return true; } + +void gfx_backend_draw_frame(renderer *ren, camera *cam, mat4 model, texture *tex) {} + void gfx_backend_shutdown(renderer *ren) {} void uniform_vec3f(u32 program_id, const char *uniform_name, vec3 *value) { diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 4a4b09e..4d3a14e 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -145,6 +145,22 @@ typedef struct global_object_uniform { f32 padding[32]; } global_object_uniform; +typedef struct object_uniform { + vec4 diffuse_colour; + vec4 v_reserved0; + vec4 v_reserved1; + vec4 v_reserved2; +} object_uniform; + +#define MAX_OBJECT_COUNT 1024 +#define VULKAN_OBJECT_SHADER_DESCRIPTOR_COUNT 1 + +typedef struct geometry_render_data { + u32 id; + mat4 model; + texture* textures[16]; +} geometry_render_data; + typedef struct vulkan_buffer { u64 total_size; VkBuffer handle; @@ -171,6 +187,8 @@ typedef struct vulkan_shader { // Data that's global for all objects drawn global_object_uniform global_ubo; + object_uniform object_ubo; + vulkan_texture_data* texture_data; } vulkan_shader; typedef struct vulkan_context { @@ -324,7 +342,7 @@ bool vulkan_graphics_pipeline_create(vulkan_context* context, vulkan_renderpass* // Vertex input VkVertexInputBindingDescription binding_desc; binding_desc.binding = 0; - binding_desc.stride = sizeof(vertex_pos); + binding_desc.stride = sizeof(vertex); binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; VkPipelineVertexInputStateCreateInfo vertex_input_info = { @@ -436,6 +454,8 @@ bool vulkan_buffer_create(vulkan_context* context, u64 size, VkBufferUsageFlagBi vulkan_buffer_bind(context, out_buffer, 0); } + DEBUG("Created buffer."); + return true; } @@ -512,11 +532,21 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha global_ubo_layout_binding.pImmutableSamplers = 0; global_ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + VkDescriptorSetLayoutBinding sampler_layout_binding; + sampler_layout_binding.binding = 1; + sampler_layout_binding.descriptorCount = 1; + sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + sampler_layout_binding.pImmutableSamplers = 0; + sampler_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + VkDescriptorSetLayoutCreateInfo global_layout_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; - global_layout_info.bindingCount = 1; - global_layout_info.pBindings = &global_ubo_layout_binding; + + VkDescriptorSetLayoutBinding bindings[2] = { global_ubo_layout_binding, sampler_layout_binding }; + + global_layout_info.bindingCount = 2; + global_layout_info.pBindings = bindings; VK_CHECK(vkCreateDescriptorSetLayout(context->device.logical_device, &global_layout_info, context->allocator, &out_shader->descriptor_set_layout)); @@ -525,9 +555,15 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha global_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; global_pool_size.descriptorCount = 3; + VkDescriptorPoolSize sampler_pool_size; + sampler_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + sampler_pool_size.descriptorCount = 3; + + VkDescriptorPoolSize pool_sizes[2] = { global_pool_size, sampler_pool_size }; + VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; - pool_info.poolSizeCount = 1; - pool_info.pPoolSizes = &global_pool_size; + pool_info.poolSizeCount = 2; + pool_info.pPoolSizes = pool_sizes; pool_info.maxSets = 3; VK_CHECK(vkCreateDescriptorPool(context->device.logical_device, &pool_info, context->allocator, @@ -549,12 +585,13 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha // Attributes u32 offset = 0; - const i32 attribute_count = 2; - VkVertexInputAttributeDescription attribute_descs[2]; + const i32 attribute_count = 3; + VkVertexInputAttributeDescription attribute_descs[3]; // Position - VkFormat formats[2] = { VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT }; + VkFormat formats[3] = { VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT, + VK_FORMAT_R32G32_SFLOAT }; - u64 sizes[2] = { sizeof(vec3), sizeof(vec3) }; + u64 sizes[3] = { sizeof(vec3), sizeof(vec3), sizeof(vec2) }; for (u32 i = 0; i < attribute_count; i++) { attribute_descs[i].binding = 0; @@ -629,15 +666,30 @@ void vulkan_object_shader_update_global_state(vulkan_context* context, vulkan_sh buffer_info.offset = offset; buffer_info.range = range; - VkWriteDescriptorSet descriptor_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - descriptor_write.dstSet = shader->descriptor_sets[image_index]; - descriptor_write.dstBinding = 0; - descriptor_write.dstArrayElement = 0; - descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_write.descriptorCount = 1; - descriptor_write.pBufferInfo = &buffer_info; + VkDescriptorImageInfo image_info; + image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_info.imageView = shader->texture_data->image.view; + image_info.sampler = shader->texture_data->sampler; + + VkWriteDescriptorSet uniform_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + uniform_write.dstSet = shader->descriptor_sets[image_index]; + uniform_write.dstBinding = 0; + uniform_write.dstArrayElement = 0; + uniform_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uniform_write.descriptorCount = 1; + uniform_write.pBufferInfo = &buffer_info; + + VkWriteDescriptorSet texture_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + texture_write.dstSet = shader->descriptor_sets[image_index]; + texture_write.dstBinding = 1; + texture_write.dstArrayElement = 0; + texture_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + texture_write.descriptorCount = 1; + texture_write.pImageInfo = &image_info; - vkUpdateDescriptorSets(context->device.logical_device, 1, &descriptor_write, 0, 0); + VkWriteDescriptorSet writes[2] = { uniform_write, texture_write }; + + vkUpdateDescriptorSets(context->device.logical_device, 2, writes, 0, 0); vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, shader->pipeline.layout, 0, 1, &global_descriptors, 0, 0); @@ -871,6 +923,10 @@ void vulkan_image_transition_layout(vulkan_context* context, vulkan_command_buff vulkan_image* image, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) { VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; +void vulkan_image_transition_layout(vulkan_context* context, vulkan_command_buffer* command_buffer, + vulkan_image* image, VkFormat format, VkImageLayout old_layout, + VkImageLayout new_layout) { + VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; barrier.oldLayout = old_layout; barrier.newLayout = new_layout; barrier.srcQueueFamilyIndex = context->device.graphics_queue_index; @@ -891,8 +947,10 @@ void vulkan_image_transition_layout(vulkan_context* context, vulkan_command_buff new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { barrier.srcAccessMask = 0; barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - dest_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + dest_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; + } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -912,10 +970,16 @@ void vulkan_image_copy_from_buffer(vulkan_image* image, VkBuffer buffer, vulkan_command_buffer* command_buffer) { VkBufferImageCopy region; region.bufferOffset = 0; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.mipLevel = 0; region.imageSubresource.baseArrayLayer = 0; region.imageSubresource.layerCount = 1; + printf("Image details width: %d height %d\n", image->width, image->height); + region.imageOffset.x = 0; + region.imageOffset.y = 0; + region.imageOffset.z = 0; region.imageExtent.width = image->width; region.imageExtent.height = image->height; region.imageExtent.depth = 1; @@ -938,7 +1002,7 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi image_create_info.extent.width = width; image_create_info.extent.height = height; image_create_info.extent.depth = 1; - image_create_info.mipLevels = 4; + image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.format = format; image_create_info.tiling = tiling; @@ -947,8 +1011,8 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - vkCreateImage(context->device.logical_device, &image_create_info, context->allocator, - &out_image->handle); + VK_CHECK(vkCreateImage(context->device.logical_device, &image_create_info, context->allocator, + &out_image->handle)); VkMemoryRequirements memory_reqs; vkGetImageMemoryRequirements(context->device.logical_device, out_image->handle, &memory_reqs); @@ -1645,12 +1709,13 @@ bool gfx_backend_init(renderer* ren) { mesh cube = prim_cube_mesh_create(); - vertex_pos* verts = malloc(sizeof(vertex_pos) * cube.vertices->len); + vertex* verts = malloc(sizeof(vertex) * cube.vertices->len); f32 scale = 3.0; for (size_t i = 0; i < cube.vertices->len; i++) { - verts[i].pos = vec3_mult(cube.vertices->data[i].position, scale); + verts[i].position = vec3_mult(cube.vertices->data[i].position, scale); verts[i].normal = cube.vertices->data[i].normal; + verts[i].uv = cube.vertices->data[i].uv; } // const f32 s = 1.0; @@ -1673,14 +1738,16 @@ bool gfx_backend_init(renderer* ren) { // u32 indices[6] = { 0, 1, 2, 0, 3, 1 }; upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, - &context.object_vertex_buffer, 0, sizeof(vertex_pos) * cube.vertices->len, - verts); + &context.object_vertex_buffer, 0, sizeof(vertex) * cube.vertices->len, verts); TRACE("Uploaded vertex data"); upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, &context.object_index_buffer, 0, sizeof(u32) * cube.indices_len, cube.indices); TRACE("Uploaded index data"); vertex_darray_free(cube.vertices); free(cube.indices); + + // upload texture + // --- End test code INFO("Vulkan renderer initialisation succeeded"); @@ -1746,16 +1813,22 @@ void texture_data_upload(texture* tex) { printf("Texture name %s\n", tex->name); tex->backend_data = malloc(sizeof(vulkan_texture_data)); vulkan_texture_data* data = (vulkan_texture_data*)tex->backend_data; - VkDeviceSize image_size = tex->width * tex->height * tex->channel_count; + printf("Texture (%s) details: \n width %d\n height %d\n channel count %d\n", tex->name, + tex->width, tex->height, tex->channel_count); + VkDeviceSize image_size = tex->width * tex->height * max(tex->channel_count, 4); + + TRACE("Creating buffer of size %ld", image_size); - VkFormat image_format = VK_FORMAT_R8G8B8A8_SNORM; + VkFormat image_format = VK_FORMAT_R8G8B8A8_SRGB; VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; VkMemoryPropertyFlags memory_prop_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; vulkan_buffer staging; vulkan_buffer_create(&context, image_size, usage, memory_prop_flags, true, &staging); + DEBUG("Uploading image data"); vulkan_buffer_load_data(&context, &staging, 0, image_size, 0, tex->image_data); + INFO("Loaded iamge data!"); vulkan_image_create( &context, VK_IMAGE_TYPE_2D, tex->width, tex->height, image_format, VK_IMAGE_TILING_OPTIMAL, @@ -1802,6 +1875,8 @@ void texture_data_upload(texture* tex) { ERROR("Error creating texture sampler for image %s", tex->name); return; } + + tex->image_data = (void*)data; } // TODO: destroy texture @@ -1844,7 +1919,7 @@ void backend_end_frame(renderer* ren, f32 delta_time) { context.queue_complete_semaphores[context.current_frame], context.image_index); } -void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model) { +void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model, texture* tex) { backend_begin_frame(ren, 16.0); mat4 proj; @@ -1852,7 +1927,9 @@ void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model) { camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); + context.object_shader.texture_data = (vulkan_texture_data*)tex->image_data; gfx_backend_update_global_state(proj, view, cam->position, vec4(1.0, 1.0, 1.0, 1.0), 0); + vulkan_object_shader_update_object(&context, &context.object_shader, model); backend_end_frame(ren, 16.0); diff --git a/src/renderer/render.c b/src/renderer/render.c index 2b7f95c..b1e2a46 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -1,4 +1,8 @@ +#include <assert.h> #include <stdlib.h> +#include <string.h> +#include "animation.h" +#include "maths_types.h" #include "mem.h" #include "transform_hierarchy.h" #define STB_IMAGE_IMPLEMENTATION @@ -61,6 +65,9 @@ bool renderer_init(renderer* ren) { ren->blinn_phong = shader_create_separate("assets/shaders/blinn_phong.vert", "assets/shaders/blinn_phong.frag"); + ren->skinned = + shader_create_separate("assets/shaders/skinned.vert", "assets/shaders/blinn_phong.frag"); + default_material_init(); return true; @@ -91,6 +98,22 @@ void default_material_init() { texture_data_upload(&DEFAULT_MATERIAL.specular_texture); } +void model_destroy(model* model) { + TRACE("Freeing all data for model %s", model->name); + arena_free_all(&model->animation_data_arena); + arena_free_storage(&model->animation_data_arena); + mesh_darray_free(model->meshes); + material_darray_free(model->materials); + if (model->is_uploaded) { + // Delete gpu buffer data + for (u32 i = 0; i < mesh_darray_len(model->meshes); i++) { + // FIXME: dont leak Opengl + glDeleteBuffers(1, &model->meshes->data[i].vbo); + glDeleteVertexArrays(1, &model->meshes->data[i].vao); + } + } +} + typedef struct draw_ctx { model_darray* models; renderer* ren; @@ -153,14 +176,8 @@ void draw_mesh(renderer* ren, mesh* mesh, mat4* model_tf, material* mat, mat4* v bind_texture(lighting_shader, &mat->specular_texture, 1); // bind to slot 1 uniform_f32(lighting_shader.program_id, "material.shininess", 32.); - // upload model transform - // mat4 trans = mat4_translation(tf.position); - // mat4 rot = mat4_rotation(tf.rotation); - // mat4 scale = mat4_scale(tf.scale); - // mat4 model_tf = mat4_mult(trans, mat4_mult(rot, scale)); - + // upload model, view, and projection matrices uniform_mat4f(lighting_shader.program_id, "model", model_tf); - // upload view & projection matrices uniform_mat4f(lighting_shader.program_id, "view", view); uniform_mat4f(lighting_shader.program_id, "projection", proj); @@ -169,6 +186,89 @@ void draw_mesh(renderer* ren, mesh* mesh, mat4* model_tf, material* mat, mat4* v draw_primitives(CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, 0, num_vertices); } +void draw_skinned_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* view, + mat4* proj) { + shader lighting_shader = ren->skinned; + + // bind buffer + bind_mesh_vertex_buffer(ren->backend_state, mesh); + + // bind textures + bind_texture(lighting_shader, &mat->diffuse_texture, 0); // bind to slot 0 + bind_texture(lighting_shader, &mat->specular_texture, 1); // bind to slot 1 + + // Uniforms + uniform_f32(lighting_shader.program_id, "material.shininess", 32.); + mat4 trans = mat4_translation(tf.position); + mat4 rot = mat4_rotation(tf.rotation); + mat4 scale = mat4_scale(tf.scale); + mat4 model_tf = mat4_mult(trans, mat4_mult(rot, scale)); + uniform_mat4f(lighting_shader.program_id, "model", &model_tf); + uniform_mat4f(lighting_shader.program_id, "view", view); + uniform_mat4f(lighting_shader.program_id, "projection", proj); + + // bone transforms + size_t n_bones = mesh->bones->len; + + // for now assume correct ordering + mat4* bone_transforms = malloc(n_bones * sizeof(mat4)); + mat4 parent = mat4_ident(); + for (int bone_i = 0; bone_i < n_bones; bone_i++) { + joint j = mesh->bones->data[bone_i]; + transform tf = mesh->bones->data[bone_i].transform_components; + tf.position.y = -tf.position.y; + mat4 local = transform_to_mat(&tf); + mat4 inverse = j.inverse_bind_matrix; + inverse.data[13] = -inverse.data[13]; + mat4 intemediate = mat4_mult(local, inverse); + + bone_transforms[bone_i] = intemediate; + parent = bone_transforms[bone_i]; + } + + // premultiply the inverses + // for (int bone_i = 0; bone_i < n_bones; bone_i++) { + // joint j = mesh->bones->data[bone_i]; + // // bone_transforms[bone_i] = mat4_mult(bone_transforms[bone_i], j.inverse_bind_matrix); + // bone_transforms[bone_i] = mat4_mult(bone_transforms[bone_i], j.inverse_bind_matrix); + // } + + glUniformMatrix4fv(glGetUniformLocation(lighting_shader.program_id, "boneMatrices"), n_bones, + GL_FALSE, &bone_transforms->data[0]); + + free(bone_transforms); + + // draw triangles + u32 num_vertices = vertex_darray_len(mesh->vertices); + draw_primitives(CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, 0, num_vertices); +} + +void draw_skinned_model(renderer* ren, camera* cam, model* model, transform tf, scene* scene) { + mat4 view; + mat4 proj; + camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); + + set_shader(ren->skinned); + + // set camera uniform + uniform_vec3f(ren->skinned.program_id, "viewPos", &cam->position); + // set light uniforms + dir_light_upload_uniforms(ren->skinned, &scene->dir_light); + for (int i = 0; i < scene->n_point_lights; i++) { + point_light_upload_uniforms(ren->skinned, &scene->point_lights[i], '0' + i); + } + + for (size_t i = 0; i < mesh_darray_len(model->meshes); i++) { + mesh* m = &model->meshes->data[i]; + if (vertex_darray_len(m->vertices) == 0) { + continue; + } + // material* mat = &model->materials->data[m->material_index]; + material* mat = &DEFAULT_MATERIAL; + draw_skinned_mesh(ren, m, tf, mat, &view, &proj); + } +} + void model_upload_meshes(renderer* ren, model* model) { INFO("Upload mesh vertex data to GPU for model %s", model->name); @@ -184,6 +284,7 @@ void model_upload_meshes(renderer* ren, model* model) { // upload each mesh to the GPU for (int mesh_i = 0; mesh_i < num_meshes; mesh_i++) { + mesh mesh = model->meshes->data[mesh_i]; model->meshes->data[mesh_i].vao = VAOs[mesh_i]; model->meshes->data[mesh_i].vbo = VBOs[mesh_i]; // 3. bind buffers @@ -193,49 +294,53 @@ void model_upload_meshes(renderer* ren, model* model) { // TRACE("Uploading vertex array data: %d verts", num_vertices); total_verts += num_vertices; - // TODO: convert this garbage into a function - f32 verts[num_vertices * 8]; - // for each face - for (int i = 0; i < (num_vertices / 3); i++) { - // for each vert in face - for (int j = 0; j < 3; j++) { - size_t stride = (i * 24) + j * 8; - // printf("i: %d, stride: %ld, loc %d\n", i, stride, i * 3 + j); - vertex vert = model->meshes->data[mesh_i].vertices->data[i]; - // printf("pos %f %f %f\n", vert.position.x, vert.position.y, vert.position.z); - // printf("norm %f %f %f\n", vert.normal.x, vert.normal.y, vert.normal.z); - // printf("tex %f %f\n", vert.uv.x, vert.uv.y); - verts[stride + 0] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.x; - verts[stride + 1] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.y; - verts[stride + 2] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].position.z; - verts[stride + 3] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.x; - verts[stride + 4] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.y; - verts[stride + 5] = - ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].normal.z; - verts[stride + 6] = ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].uv.x; - verts[stride + 7] = ((vertex*)model->meshes->data[mesh_i].vertices->data)[i * 3 + j].uv.y; + size_t static_vertex_size = 2 * sizeof(vec3) + sizeof(vec2); + size_t skinned_vertex_size = 2 * sizeof(vec3) + sizeof(vec2) + 4 * sizeof(u32) + sizeof(vec4); + size_t vertex_size = mesh.is_skinned ? skinned_vertex_size : static_vertex_size; + + // TRACE("sizeof(vertex) -> %ld, vertex_size -> %ld\n", sizeof(vertex), vertex_size); + if (mesh.is_skinned) { + assert(vertex_size == (12 + 12 + 8 + 16 + 16)); + } else { + assert(vertex_size == sizeof(vertex)); + assert(vertex_size == 8 * sizeof(float)); + } + + size_t buffer_size = vertex_size * num_vertices; + u8* bytes = malloc(buffer_size); + + for (int i = 0; i < num_vertices; i++) { + u8* p = bytes + vertex_size * i; + memcpy(p, &mesh.vertices->data[i], static_vertex_size); + if (mesh.is_skinned) { + u8* bone_data_offset = p + static_vertex_size; + memcpy(bone_data_offset, &mesh.vertex_bone_data->data[i], sizeof(vertex_bone_data)); } } // 4. upload data - glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, buffer_size, bytes, GL_STATIC_DRAW); // 5. cont. set mesh vertex layout glBindVertexArray(model->meshes->data[mesh_i].vao); // position attribute - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertex_size, (void*)0); glEnableVertexAttribArray(0); // normal vector attribute - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertex_size, (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); // tex coords - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertex_size, (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); + + // skinning (optional) + if (mesh.is_skinned) { + glEnableVertexAttribArray(3); + glVertexAttribIPointer(3, 4, GL_INT, vertex_size, (void*)(8 * sizeof(float))); + + glEnableVertexAttribArray(4); + glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, vertex_size, (void*)(12 * sizeof(float))); + } } INFO("Uploaded %d submeshes with a total of %d vertices\n", num_meshes, total_verts); @@ -253,7 +358,7 @@ texture texture_data_load(const char* path, bool invert_y) { stbi_set_flip_vertically_on_load(invert_y); #pragma GCC diagnostic ignored "-Wpointer-sign" - char* data = stbi_load(path, &width, &height, &num_channels, 0); + char* data = stbi_load(path, &width, &height, &num_channels, 0); // STBI_rgb_alpha); if (data) { DEBUG("loaded texture: %s", path); } else { diff --git a/src/renderer/render.h b/src/renderer/render.h index b687ad1..31cf3b0 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -38,5 +38,9 @@ void draw_mesh(renderer* ren, mesh* mesh, mat4* tf, material* mat, mat4* view, m void draw_scene(arena* frame, model_darray* models, renderer* ren, camera* camera, transform_hierarchy* tfh, scene* scene); +void draw_skinned_model(renderer* ren, camera* cam, model* model, transform tf, scene* scene); + +void model_destroy(model* model); + // --- texture texture_data_load(const char* path, bool invert_y); // #frontend diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h index af62f9f..da30bcc 100644 --- a/src/renderer/render_backend.h +++ b/src/renderer/render_backend.h @@ -13,7 +13,7 @@ bool gfx_backend_init(renderer* ren); void gfx_backend_shutdown(renderer* ren); -void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model); +void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model, texture* tex); void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, i32 mode); diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index af20999..387ac81 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -7,10 +7,11 @@ // */ // #pragma once -// #include "darray.h" -// #include "maths.h" -// #include "maths_types.h" -// #include "str.h" +#include "animation.h" +#include "darray.h" +#include "maths.h" +#include "maths_types.h" +#include "str.h" // struct GLFWwindow; @@ -40,26 +41,27 @@ // u64 last_time; // } frame_stats; -// typedef struct renderer { -// struct GLFWwindow *window; /** Currently all platforms use GLFW*/ -// void *backend_state; /** Graphics API-specific state */ -// renderer_config config; -// // shaders -// shader blinn_phong; -// } renderer; +typedef struct renderer { + struct GLFWwindow *window; /** Currently all platforms use GLFW*/ + void *backend_state; /** Graphics API-specific state */ + renderer_config config; + // shaders + shader blinn_phong; + shader skinned; +} renderer; // // --- Lighting & Materials -// typedef struct texture { -// u32 texture_id; -// char name[MAX_TEXTURE_NAME_LEN]; -// void* image_data; -// void* backend_data; -// u32 width; -// u32 height; -// u8 channel_count; -// u32 channel_type; -// } texture; +typedef struct texture { + u32 texture_id; + char name[MAX_TEXTURE_NAME_LEN]; + void *image_data; + void *backend_data; + u32 width; + u32 height; + u8 channel_count; + u32 channel_type; +} texture; // typedef struct blinn_phong_material { // char name[MAX_MATERIAL_NAME_LEN]; @@ -80,10 +82,15 @@ // extern material DEFAULT_MATERIAL; // void default_material_init(); -// #ifndef TYPED_MATERIAL_ARRAY -// KITC_DECL_TYPED_ARRAY(material) // creates "material_darray" -// #define TYPED_MATERIAL_ARRAY -// #endif +#ifndef TYPED_MATERIAL_ARRAY +KITC_DECL_TYPED_ARRAY(material) // creates "material_darray" +#define TYPED_MATERIAL_ARRAY +#endif + +#ifndef TYPED_ANIMATION_CLIP_ARRAY +KITC_DECL_TYPED_ARRAY(animation_clip) // creates "material_darray" +#define TYPED_ANIMATION_CLIP_ARRAY +#endif // // lights // typedef struct point_light { @@ -113,34 +120,47 @@ // vec2 uv; // } vertex; -// #ifndef TYPED_VERTEX_ARRAY -// KITC_DECL_TYPED_ARRAY(vertex) // creates "vertex_darray" -// #define TYPED_VERTEX_ARRAY -// #endif - -// typedef struct mesh { -// vertex_darray *vertices; -// u32 vertex_size; /** size in bytes of each vertex including necessary padding */ -// bool has_indices; -// u32 *indices; -// u32 indices_len; -// size_t material_index; -// u32 vbo, vao; /** OpenGL data. TODO: dont leak OpenGL details */ -// } mesh; +typedef struct vertex_bone_data { + vec4u joints; /** @brief 4 indices of joints that influence vectors position */ + vec4 weights; /** @brief weight (0,1) of each joint */ +} vertex_bone_data; + +#include "animation.h" +#ifndef TYPED_VERTEX_ARRAY +KITC_DECL_TYPED_ARRAY(vertex) // creates "vertex_darray" +KITC_DECL_TYPED_ARRAY(vertex_bone_data) // creates "skinned_vertex_darray" +KITC_DECL_TYPED_ARRAY(joint) +#define TYPED_VERTEX_ARRAY +#endif + +typedef struct mesh { + vertex_darray *vertices; + vertex_bone_data_darray *vertex_bone_data; // only used if model needs it + joint_darray *bones; + bool is_skinned; + u32 vertex_size; /** size in bytes of each vertex including necessary padding */ + bool has_indices; + u32 *indices; + u32 indices_len; + size_t material_index; + u32 vbo, vao; /** OpenGL data. TODO: dont leak OpenGL details */ +} mesh; // #ifndef TYPED_MESH_ARRAY // KITC_DECL_TYPED_ARRAY(mesh) // creates "mesh_darray" // #define TYPED_MESH_ARRAY // #endif -// typedef struct model { -// str8 name; -// mesh_darray *meshes; -// aabb_3d bbox; -// material_darray *materials; -// bool is_loaded; -// bool is_uploaded; -// } model; +typedef struct model { + str8 name; + mesh_darray *meshes; + aabb_3d bbox; + material_darray *materials; + animation_clip_darray *animations; + arena animation_data_arena; + bool is_loaded; + bool is_uploaded; +} model; // #ifndef TYPED_MODEL_ARRAY // KITC_DECL_TYPED_ARRAY(model) // creates "model_darray" |