summaryrefslogtreecommitdiff
path: root/src/renderer
diff options
context:
space:
mode:
authoromnisci3nce <omniscient.oce@gmail.com>2024-04-27 13:08:03 +1000
committeromnisci3nce <omniscient.oce@gmail.com>2024-04-27 13:08:03 +1000
commit4cbc38b92edaa331fd0f6a077bbe7d7aebdb9ecf (patch)
tree753d23b07b09e3494e4cce594bd4b0f4710566f8 /src/renderer
parentd6837defc03e431517f6616ec8e49a8eb3643011 (diff)
parentc7c33cd18e057bc826a0d31e1860b0ac396a00b6 (diff)
Merge remote-tracking branch 'origin/cel-67-load-animation-data-from-gltf' into ral
Diffstat (limited to 'src/renderer')
-rw-r--r--src/renderer/backends/backend_opengl.c4
-rw-r--r--src/renderer/backends/backend_vulkan.c133
-rw-r--r--src/renderer/render.c181
-rw-r--r--src/renderer/render.h4
-rw-r--r--src/renderer/render_backend.h2
-rw-r--r--src/renderer/render_types.h114
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"