From fb3e055ff500e530e9ec46317441688bf4d07e13 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Mon, 1 Apr 2024 01:57:11 +1100 Subject: image / textures ! --- src/renderer/backends/backend_opengl.c | 2 +- src/renderer/backends/backend_vulkan.c | 191 +++++++++++++++++++++++---------- 2 files changed, 135 insertions(+), 58 deletions(-) (limited to 'src/renderer/backends') diff --git a/src/renderer/backends/backend_opengl.c b/src/renderer/backends/backend_opengl.c index a9f7482..e3a4fb6 100644 --- a/src/renderer/backends/backend_opengl.c +++ b/src/renderer/backends/backend_opengl.c @@ -60,7 +60,7 @@ void clear_screen(vec3 colour) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -void texture_data_upload(texture* tex) { +void texture_data_upload(texture *tex) { printf("Texture name %s\n", tex->name); TRACE("Upload texture data"); u32 texture_id; diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 9d0ef51..e0b0e4e 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); @@ -867,15 +919,10 @@ void vulkan_image_view_create(vulkan_context* context, VkFormat format, vulkan_i &image->view); } -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}; +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; @@ -892,12 +939,16 @@ void vulkan_image_transition_layout( VkPipelineStageFlags source_stage; VkPipelineStageFlags dest_stage; - if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && + 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; - } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + 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; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; @@ -907,25 +958,30 @@ void vulkan_image_transition_layout( return; } - vkCmdPipelineBarrier(command_buffer->handle, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, &barrier); + vkCmdPipelineBarrier(command_buffer->handle, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, + &barrier); } -void vulkan_image_copy_from_buffer( - vulkan_image* image, - VkBuffer buffer, - vulkan_command_buffer* command_buffer -) { +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; - vkCmdCopyBufferToImage(command_buffer->handle, buffer, image->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + vkCmdCopyBufferToImage(command_buffer->handle, buffer, image->handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); } void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 width, u32 height, @@ -942,7 +998,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; @@ -951,8 +1007,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); @@ -1649,12 +1705,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; @@ -1677,14 +1734,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"); @@ -1750,32 +1809,46 @@ 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); - VkFormat image_format = VK_FORMAT_R8G8B8A8_SNORM; + TRACE("Creating buffer of size %ld", image_size); + + 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; + 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, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT - , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_COLOR_BIT, &data->image); + vulkan_image_create( + &context, VK_IMAGE_TYPE_2D, tex->width, tex->height, image_format, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_COLOR_BIT, &data->image); vulkan_command_buffer temp_buffer; - vulkan_command_buffer_allocate_and_begin_oneshot(&context, context.device.gfx_command_pool, &temp_buffer); + vulkan_command_buffer_allocate_and_begin_oneshot(&context, context.device.gfx_command_pool, + &temp_buffer); - vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); vulkan_image_copy_from_buffer(&data->image, staging.handle, &temp_buffer); - vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - vulkan_command_buffer_end_oneshot(&context, context.device.gfx_command_pool, &temp_buffer, context.device.graphics_queue); + vulkan_command_buffer_end_oneshot(&context, context.device.gfx_command_pool, &temp_buffer, + context.device.graphics_queue); - VkSamplerCreateInfo sampler_info = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + VkSamplerCreateInfo sampler_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; sampler_info.magFilter = VK_FILTER_LINEAR; sampler_info.minFilter = VK_FILTER_LINEAR; sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; @@ -1792,12 +1865,14 @@ void texture_data_upload(texture* tex) { sampler_info.minLod = 0.0; sampler_info.maxLod = 0.0; - VkResult res = vkCreateSampler(context.device.logical_device, &sampler_info, context.allocator, &data->sampler); + VkResult res = vkCreateSampler(context.device.logical_device, &sampler_info, context.allocator, + &data->sampler); if (res != VK_SUCCESS) { ERROR("Error creating texture sampler for image %s", tex->name); return; } - + + tex->image_data = (void*)data; } // TODO: destroy texture @@ -1840,7 +1915,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; @@ -1848,7 +1923,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); -- cgit v1.2.3-70-g09d2 From af97c4330a27a92d2362e30b70990e3aa5c9954a Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Thu, 4 Apr 2024 20:54:45 +1100 Subject: add AnimatedCube --- assets/models/gltf/AnimatedCube/LICENSE.md | 15 ++ assets/models/gltf/AnimatedCube/README.body.md | 3 + assets/models/gltf/AnimatedCube/README.md | 27 +++ .../models/gltf/AnimatedCube/glTF/AnimatedCube.bin | Bin 0 -> 1860 bytes .../gltf/AnimatedCube/glTF/AnimatedCube.gltf | 262 +++++++++++++++++++++ .../AnimatedCube/glTF/AnimatedCube_BaseColor.png | Bin 0 -> 891995 bytes .../glTF/AnimatedCube_MetallicRoughness.png | Bin 0 -> 319 bytes assets/models/gltf/AnimatedCube/metadata.json | 25 ++ .../gltf/AnimatedCube/screenshot/screenshot.gif | Bin 0 -> 517169 bytes .../property_animation/ex_property_animation.c | 103 ++++++++ src/defines.h | 4 +- src/renderer/backends/backend_opengl.c | 6 + src/resources/gltf.c | 3 +- 13 files changed, 445 insertions(+), 3 deletions(-) create mode 100644 assets/models/gltf/AnimatedCube/LICENSE.md create mode 100644 assets/models/gltf/AnimatedCube/README.body.md create mode 100644 assets/models/gltf/AnimatedCube/README.md create mode 100644 assets/models/gltf/AnimatedCube/glTF/AnimatedCube.bin create mode 100644 assets/models/gltf/AnimatedCube/glTF/AnimatedCube.gltf create mode 100644 assets/models/gltf/AnimatedCube/glTF/AnimatedCube_BaseColor.png create mode 100644 assets/models/gltf/AnimatedCube/glTF/AnimatedCube_MetallicRoughness.png create mode 100644 assets/models/gltf/AnimatedCube/metadata.json create mode 100644 assets/models/gltf/AnimatedCube/screenshot/screenshot.gif (limited to 'src/renderer/backends') diff --git a/assets/models/gltf/AnimatedCube/LICENSE.md b/assets/models/gltf/AnimatedCube/LICENSE.md new file mode 100644 index 0000000..c001f8f --- /dev/null +++ b/assets/models/gltf/AnimatedCube/LICENSE.md @@ -0,0 +1,15 @@ +# LICENSE file for the model: Animated Cube + +All files in this directory tree are licensed as indicated below. + +* All files directly associated with the model including all text, image and binary files: + + * [CC0 1.0 Universal]("https://creativecommons.org/publicdomain/zero/1.0/legalcode") [SPDX license identifier: "CC0-1.0"] + +* This file and all other metadocumentation files including "metadata.json": + + * [Creative Commons Attribtution 4.0 International]("https://creativecommons.org/licenses/by/4.0/legalcode") [SPDX license identifier: "CC-BY-4.0"] + +Full license text of these licenses are available at the links above + +#### Generated by modelmetadata \ No newline at end of file diff --git a/assets/models/gltf/AnimatedCube/README.body.md b/assets/models/gltf/AnimatedCube/README.body.md new file mode 100644 index 0000000..1efdf8c --- /dev/null +++ b/assets/models/gltf/AnimatedCube/README.body.md @@ -0,0 +1,3 @@ +## Screenshot + +![screenshot](screenshot/screenshot.gif) diff --git a/assets/models/gltf/AnimatedCube/README.md b/assets/models/gltf/AnimatedCube/README.md new file mode 100644 index 0000000..d5cf0a3 --- /dev/null +++ b/assets/models/gltf/AnimatedCube/README.md @@ -0,0 +1,27 @@ +# Animated Cube + +## Tags + +[core](../../Models-core.md), [testing](../../Models-testing.md) + +## Summary + +Same as 'Cube', but having a linear rotation animation. + +## Operations + +* [Display](https://github.khronos.org/glTF-Sample-Viewer-Release/?model=https://raw.GithubUserContent.com/KhronosGroup/glTF-Sample-Assets/main/./Models/AnimatedCube/glTF/AnimatedCube.gltf) in SampleViewer +* [Model Directory](./) + +## Screenshot + +![screenshot](screenshot/screenshot.gif) + + +## Legal + +© 2017, UX3D. [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/legalcode) + + - Norbert Nopper for Everything + +#### Assembled by modelmetadata \ No newline at end of file diff --git a/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.bin b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.bin new file mode 100644 index 0000000..72f7d2d Binary files /dev/null and b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.bin differ diff --git a/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.gltf b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.gltf new file mode 100644 index 0000000..ff117b0 --- /dev/null +++ b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube.gltf @@ -0,0 +1,262 @@ +{ + "accessors" : [ + { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 3, + "max" : [ + 2.000000 + ], + "min" : [ + 0.000000 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 3, + "max" : [ + 0.000000, + 1.000000, + 0.000000, + 1.000000 + ], + "min" : [ + 0.000000, + -8.742278e-008, + 0.000000, + -1.000000 + ], + "type" : "VEC4" + }, + { + "bufferView" : 2, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 36, + "max" : [ + 35 + ], + "min" : [ + 0 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 3, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000001 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 4, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 5, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + -0.000000, + -0.000000, + 1.000000 + ], + "min" : [ + 0.000000, + -0.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC4" + }, + { + "bufferView" : 6, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000 + ], + "type" : "VEC2" + } + ], + "animations" : [ + { + "channels" : [ + { + "sampler" : 0, + "target" : { + "node" : 0, + "path" : "rotation" + } + } + ], + "name" : "animation_AnimatedCube", + "samplers" : [ + { + "input" : 0, + "interpolation" : "LINEAR", + "output" : 1 + } + ] + } + ], + "asset" : { + "generator" : "VKTS glTF 2.0 exporter", + "version" : "2.0" + }, + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 12, + "byteOffset" : 0 + }, + { + "buffer" : 0, + "byteLength" : 48, + "byteOffset" : 12 + }, + { + "buffer" : 0, + "byteLength" : 72, + "byteOffset" : 60, + "target" : 34963 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 132, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 564, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 576, + "byteOffset" : 996, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 288, + "byteOffset" : 1572, + "target" : 34962 + } + ], + "buffers" : [ + { + "byteLength" : 1860, + "uri" : "AnimatedCube.bin" + } + ], + "images" : [ + { + "uri" : "AnimatedCube_BaseColor.png" + }, + { + "uri" : "AnimatedCube_MetallicRoughness.png" + } + ], + "materials" : [ + { + "name" : "AnimatedCube", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicRoughnessTexture" : { + "index" : 1 + } + } + } + ], + "meshes" : [ + { + "name" : "AnimatedCube", + "primitives" : [ + { + "attributes" : { + "NORMAL" : 4, + "POSITION" : 3, + "TANGENT" : 5, + "TEXCOORD_0" : 6 + }, + "indices" : 2, + "material" : 0, + "mode" : 4 + } + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "AnimatedCube", + "rotation" : [ + 0.000000, + -1.000000, + 0.000000, + 0.000000 + ] + } + ], + "samplers" : [ + {} + ], + "scene" : 0, + "scenes" : [ + { + "nodes" : [ + 0 + ] + } + ], + "textures" : [ + { + "sampler" : 0, + "source" : 0 + }, + { + "sampler" : 0, + "source" : 1 + } + ] +} \ No newline at end of file diff --git a/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_BaseColor.png b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_BaseColor.png new file mode 100644 index 0000000..5e5cb20 Binary files /dev/null and b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_BaseColor.png differ diff --git a/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_MetallicRoughness.png b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_MetallicRoughness.png new file mode 100644 index 0000000..efd2026 Binary files /dev/null and b/assets/models/gltf/AnimatedCube/glTF/AnimatedCube_MetallicRoughness.png differ diff --git a/assets/models/gltf/AnimatedCube/metadata.json b/assets/models/gltf/AnimatedCube/metadata.json new file mode 100644 index 0000000..3af6fdb --- /dev/null +++ b/assets/models/gltf/AnimatedCube/metadata.json @@ -0,0 +1,25 @@ +{ + "version": 2, + "legal": [ + { + "license": "CC0", + "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/legalcode", + "artist": "Norbert Nopper", + "year": "2017", + "owner": "UX3D", + "what": "Everything", + "text": "CC0 1.0 Universal", + "spdx": "CC0-1.0", + "icon": "https://licensebuttons.net/p/zero/1.0/88x31.png" + } + ], + "tags": [ + "core", + "testing" + ], + "screenshot": "screenshot/screenshot.gif", + "name": "Animated Cube", + "path": "./Models/AnimatedCube", + "summary": "Same as 'Cube', but having a linear rotation animation.", + "createReadme": true +} \ No newline at end of file diff --git a/assets/models/gltf/AnimatedCube/screenshot/screenshot.gif b/assets/models/gltf/AnimatedCube/screenshot/screenshot.gif new file mode 100644 index 0000000..eea74ee Binary files /dev/null and b/assets/models/gltf/AnimatedCube/screenshot/screenshot.gif differ diff --git a/examples/property_animation/ex_property_animation.c b/examples/property_animation/ex_property_animation.c index e69de29..38bafd5 100644 --- a/examples/property_animation/ex_property_animation.c +++ b/examples/property_animation/ex_property_animation.c @@ -0,0 +1,103 @@ +#include + +#include "camera.h" +#include "core.h" +#include "input.h" +#include "keys.h" +#include "maths.h" +#include "maths_types.h" +#include "primitives.h" +#include "render.h" +#include "render_backend.h" +#include "render_types.h" + +const vec3 pointlight_positions[4] = { + { 0.7, 0.2, 2.0 }, + { 2.3, -3.3, -4.0 }, + { -4.0, 2.0, -12.0 }, + { 0.0, 0.0, -3.0 }, +}; +point_light point_lights[4]; + +typedef struct game_state { + camera camera; + vec3 camera_euler; + bool first_mouse_update; // so the camera doesnt lurch when you run the first + // process_camera_rotation +} game_state; + +void update_camera_rotation(input_state* input, game_state* game, camera* cam); + +int main() { + core* core = core_bringup(); + + model_handle animated_cube_handle = + model_load_gltf(core, "assets/models/gltf/AnimatedCube/glTF/AnimatedCube.gltf", false); + model* cube = &core->models->data[animated_cube_handle.raw]; + model_upload_meshes(&core->renderer, cube); + + directional_light dir_light = { .direction = (vec3){ -0.2, -1.0, -0.3 }, + .ambient = (vec3){ 0.2, 0.2, 0.2 }, + .diffuse = (vec3){ 0.5, 0.5, 0.5 }, + .specular = (vec3){ 1.0, 1.0, 1.0 } }; + + for (int i = 0; i < 4; i++) { + point_lights[i].position = pointlight_positions[i]; + point_lights[i].ambient = (vec3){ 0.05, 0.05, 0.05 }; + point_lights[i].diffuse = (vec3){ 0.8, 0.8, 0.8 }; + point_lights[i].specular = (vec3){ 1.0, 1.0, 1.0 }; + point_lights[i].constant = 1.0; + point_lights[i].linear = 0.09; + point_lights[i].quadratic = 0.032; + } + scene our_scene = { .dir_light = dir_light, .n_point_lights = 4 }; + memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4])); + + vec3 cam_pos = vec3_create(5, 5, 5); + game_state game = { + .camera = camera_create(cam_pos, vec3_negate(cam_pos), VEC3_Y, deg_to_rad(45.0)), + .camera_euler = vec3_create(90, 0, 0), + .first_mouse_update = true, + }; + + print_vec3(game.camera.front); + + // Main loop + const f32 camera_lateral_speed = 0.2; + const f32 camera_zoom_speed = 0.15; + + while (!should_exit(core)) { + input_update(&core->input); + + vec3 translation = VEC3_ZERO; + if (key_is_pressed(KEYCODE_W) || key_is_pressed(KEYCODE_KEY_UP)) { + translation = vec3_mult(game.camera.front, camera_zoom_speed); + } else if (key_is_pressed(KEYCODE_S) || key_is_pressed(KEYCODE_KEY_DOWN)) { + translation = vec3_mult(game.camera.front, -camera_zoom_speed); + } else if (key_is_pressed(KEYCODE_A) || key_is_pressed(KEYCODE_KEY_LEFT)) { + vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up)); + translation = vec3_mult(lateral, -camera_lateral_speed); + } else if (key_is_pressed(KEYCODE_D) || key_is_pressed(KEYCODE_KEY_RIGHT)) { + vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up)); + translation = vec3_mult(lateral, camera_lateral_speed); + } + game.camera.position = vec3_add(game.camera.position, translation); + + // UNUSED: threadpool_process_results(&core->threadpool, 1); + + render_frame_begin(&core->renderer); + + mat4 model = mat4_translation(VEC3_ZERO); + transform tf = transform_create(VEC3_ZERO, quat_ident(), 1.0); + + draw_model(&core->renderer, &game.camera, cube, tf, &our_scene); + + // gfx_backend_draw_frame(&core->renderer, &game.camera, model, NULL); + + render_frame_end(&core->renderer); + } + + core_shutdown(core); + + return 0; +} diff --git a/src/defines.h b/src/defines.h index 4459e1a..52aa7b0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -66,8 +66,8 @@ Renderer backend defines: // Platform will inform renderer backend (unless user overrides) #if defined(CEL_PLATFORM_LINUX) || defined(CEL_PLATFORM_WINDOWS) -// #define CEL_REND_BACKEND_OPENGL 1 -#define CEL_REND_BACKEND_VULKAN 1 +#define CEL_REND_BACKEND_OPENGL 1 +// #define CEL_REND_BACKEND_VULKAN 1 #endif #if defined(CEL_PLATFORM_MAC) diff --git a/src/renderer/backends/backend_opengl.c b/src/renderer/backends/backend_opengl.c index e3a4fb6..8df0933 100644 --- a/src/renderer/backends/backend_opengl.c +++ b/src/renderer/backends/backend_opengl.c @@ -1,4 +1,5 @@ #include +#include "camera.h" #define CEL_PLATFORM_LINUX #include "defines.h" @@ -40,6 +41,11 @@ 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/resources/gltf.c b/src/resources/gltf.c index b269fcd..261c96f 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -211,7 +211,8 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel if (primitive.material != NULL) { for (int i = 0; i < material_darray_len(out_model->materials); i++) { - if (strcmp(primitive.material->name, out_model->materials->data[i].name)) { + printf("%s vs %s \n", primitive.material->name, out_model->materials->data[i].name); + if (strcmp(primitive.material->name, out_model->materials->data[i].name) == 0) { TRACE("Found material"); mesh.material_index = i; break; -- cgit v1.2.3-70-g09d2 From 9baff5661f2ba8b57e1b0794e490e239b7ef80ca Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Thu, 4 Apr 2024 22:53:13 +1100 Subject: loading animation data - step 1 --- .../property_animation/ex_property_animation.c | 4 ++ src/animation.c | 0 src/animation.h | 53 ++++++++++++++ src/maths/primitives.h | 82 +++++++++++++--------- src/renderer/backends/backend_opengl.c | 4 +- src/renderer/render.c | 16 +++++ src/renderer/render.h | 2 + src/renderer/render_types.h | 12 +++- src/resources/gltf.c | 59 ++++++++++++++++ 9 files changed, 194 insertions(+), 38 deletions(-) create mode 100644 src/animation.c create mode 100644 src/animation.h (limited to 'src/renderer/backends') diff --git a/examples/property_animation/ex_property_animation.c b/examples/property_animation/ex_property_animation.c index 38bafd5..e175b31 100644 --- a/examples/property_animation/ex_property_animation.c +++ b/examples/property_animation/ex_property_animation.c @@ -4,6 +4,7 @@ #include "core.h" #include "input.h" #include "keys.h" +#include "log.h" #include "maths.h" #include "maths_types.h" #include "primitives.h" @@ -97,6 +98,9 @@ int main() { render_frame_end(&core->renderer); } + INFO("Shutting down"); + model_destroy(cube); + core_shutdown(core); return 0; diff --git a/src/animation.c b/src/animation.c new file mode 100644 index 0000000..e69de29 diff --git a/src/animation.h b/src/animation.h new file mode 100644 index 0000000..b7c8ca4 --- /dev/null +++ b/src/animation.h @@ -0,0 +1,53 @@ +#pragma once + +#include "darray.h" +#include "defines.h" +#include "maths_types.h" + +KITC_DECL_TYPED_ARRAY(f32) + +typedef enum interpolation { INTERPOLATION_LINEAR, INTERPOLATION_COUNT } interpolation; + +typedef enum keyframe_kind { + KEYFRAME_ROTATION, + KEYFRAME_TRANSLATION, + KEYFRAME_SCALE, + KEYFRAME_WEIGHTS, +} keyframe_kind; + +typedef union keyframe { + quat rotation; + vec3 translation; + vec3 scale; + float* weights; +} keyframe; + +typedef struct keyframes { + keyframe_kind kind; + keyframe* values; + size_t count; +} keyframes; + +typedef struct animation_spline { + f32_darray timestamps; + keyframes values; + interpolation interpolation; +} animation_spline; + +typedef struct animation_sampler { + int current_index; + animation_spline animation; +} animation_sampler; + +/** @brief Sample an animation at a given time `t` */ +keyframe animation_sample(animation_sampler sampler, f32 t); + +typedef struct animation_clip { + // A clip contains one or more animation curves + // for now I think we can just enumerate all of the properties (assuming *only* one per type is in + // a clip) NULL = this property is not animated in this clip + animation_sampler* rotation; + animation_sampler* translation; + animation_sampler* scale; + animation_sampler* weights; +} animation_clip; \ No newline at end of file diff --git a/src/maths/primitives.h b/src/maths/primitives.h index b7fefa0..ed52c8c 100644 --- a/src/maths/primitives.h +++ b/src/maths/primitives.h @@ -34,38 +34,48 @@ static mesh prim_cube_mesh_create() { (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); vertex_darray_push( cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1,1 } }); + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 1 } }); vertex_darray_push( cube.vertices, (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); // front faces - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1} }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0} }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); // top faces vertex_darray_push(cube.vertices, (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); vertex_darray_push(cube.vertices, (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } }); // bottom faces vertex_darray_push( @@ -88,18 +98,24 @@ static mesh prim_cube_mesh_create() { (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); // right faces - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1,1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } }); // left faces vertex_darray_push( diff --git a/src/renderer/backends/backend_opengl.c b/src/renderer/backends/backend_opengl.c index 8df0933..b769002 100644 --- a/src/renderer/backends/backend_opengl.c +++ b/src/renderer/backends/backend_opengl.c @@ -42,9 +42,7 @@ bool gfx_backend_init(renderer *ren) { return true; } -void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model, texture* tex) { - -} +void gfx_backend_draw_frame(renderer *ren, camera *cam, mat4 model, texture *tex) {} void gfx_backend_shutdown(renderer *ren) {} diff --git a/src/renderer/render.c b/src/renderer/render.c index 2993225..2f5e553 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -1,3 +1,4 @@ +#include "mem.h" #define STB_IMAGE_IMPLEMENTATION #include @@ -88,6 +89,21 @@ void default_material_init() { texture_data_upload(&DEFAULT_MATERIAL.specular_texture); } +void model_destroy(model* model) { + 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); + } + } +} + void draw_model(renderer* ren, camera* camera, model* model, transform tf, scene* scene) { // TRACE("Drawing model: %s", model->name); mat4 view; diff --git a/src/renderer/render.h b/src/renderer/render.h index b6dad00..f0118b6 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -35,5 +35,7 @@ void model_upload_meshes(renderer* ren, model* model); void draw_model(renderer* ren, camera* camera, model* model, transform tf, scene* scene); void draw_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* view, mat4* proj); +void model_destroy(model* model); + // --- texture texture_data_load(const char* path, bool invert_y); // #frontend diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 80e1372..8d12183 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -7,6 +7,7 @@ */ #pragma once +#include "animation.h" #include "darray.h" #include "maths.h" #include "maths_types.h" @@ -52,8 +53,8 @@ typedef struct renderer { typedef struct texture { u32 texture_id; char name[MAX_TEXTURE_NAME_LEN]; - void* image_data; - void* backend_data; + void *image_data; + void *backend_data; u32 width; u32 height; u8 channel_count; @@ -84,6 +85,11 @@ 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 { vec3 position; @@ -137,6 +143,8 @@ typedef struct model { mesh_darray *meshes; aabb_3d bbox; material_darray *materials; + animation_clip_darray *animations; + arena animation_data_arena; bool is_loaded; bool is_uploaded; } model; diff --git a/src/resources/gltf.c b/src/resources/gltf.c index 261c96f..b6e100f 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -1,11 +1,13 @@ #include #include #include +#include "animation.h" #include "core.h" #include "defines.h" #include "file.h" #include "loaders.h" #include "log.h" +#include "mem.h" #include "path.h" #include "render.h" #include "render_types.h" @@ -228,6 +230,63 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel printf("Mesh %d Mat index %d Mat name %s\n", i, mat_idx, out_model->materials->data[mat_idx].name); } + + // Animations + TRACE("Num animations %d", data->animations_count); + size_t num_animations = data->animations_count; + if (num_animations > 0) { +// Create an arena for all animation related data +#define ANIMATION_STORAGE_ARENA_SIZE (1024 * 1024) + char *animation_backing_storage = malloc(ANIMATION_STORAGE_ARENA_SIZE); + // We'll store data on this arena so we can easily free it all at once later + arena anim_arena = arena_create(animation_backing_storage, ANIMATION_STORAGE_ARENA_SIZE); + + if (!out_model->animations) { + out_model->animations = animation_clip_darray_new(num_animations); + } + + for (int anim_idx = 0; anim_idx < data->animations_count; anim_idx++) { + cgltf_animation animation = data->animations[anim_idx]; + animation_clip clip = { 0 }; + + for (size_t c = 0; c < animation.channels_count; c++) { + cgltf_animation_channel channel = animation.channels[c]; + + animation_sampler *sampler = arena_alloc(&anim_arena, sizeof(animation_sampler)); + + animation_sampler **target_property; + keyframe_kind data_type; + + switch (channel.target_path) { + case cgltf_animation_path_type_rotation: + target_property = &clip.rotation; + data_type = KEYFRAME_ROTATION; + break; + default: + WARN("unsupported animation type"); + return false; + } + *target_property = sampler; + + sampler->current_index = 0; + sampler->animation.interpolation = INTERPOLATION_LINEAR; + + // keyframe times + size_t n_frames = channel.sampler->input->count; + assert(channel.sampler->input->component_type == cgltf_component_type_r_32f); + // FIXME: CASSERT_MSG function "Expected animation sampler input component to be type f32 (keyframe times)"); + + sampler, + + // keyframe values + size_t n_values = channel.sampler->output->count; + assert(n_frames == n_values); + + sampler->animation.timestamps + } + } + } + return true; } -- cgit v1.2.3-70-g09d2