diff --git a/shader_src/texture.frag b/shader_src/texture.frag new file mode 100644 index 0000000..9bbc581 --- /dev/null +++ b/shader_src/texture.frag @@ -0,0 +1,10 @@ +#version 450 + +layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 fragTex; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragTex, 0.0f, 1.0); +} diff --git a/shader_src/texture.vert b/shader_src/texture.vert new file mode 100644 index 0000000..df9d222 --- /dev/null +++ b/shader_src/texture.vert @@ -0,0 +1,19 @@ +#version 450 + +layout(binding = 0) uniform UniformBufferObject { + mat4 view; + mat4 proj; +} ubo; + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inColor; +layout(location = 2) in vec2 inTex; + +layout(location = 0) out vec3 fragColor; +layout(location = 1) out vec2 fragTex; + +void main() { + gl_Position = ubo.proj * ubo.view * vec4(inPosition, 1.0); + fragColor = inColor; + fragTex = inTex; +} diff --git a/src/main.c b/src/main.c index 73c8ee4..ef62c29 100644 --- a/src/main.c +++ b/src/main.c @@ -112,12 +112,20 @@ typedef struct VulkanContextStruct { void** scene_ubo_ptrs; Mesh triangle_mesh; + Mesh triangle_mesh_textured; Material simple_mesh_material; + Material texture_mesh_material; uint32_t current_frame; } VulkanContext; -struct Vertex{ +struct TextureVertex { + vec3 pos; + vec3 color; + vec2 tex; +}; + +struct Vertex { vec3 pos; vec3 color; }; @@ -132,12 +140,17 @@ const struct Vertex vertices[] = { {.pos = { 0.5f, -0.5f, 0.5f}, .color = {0.0f, 1.0f, 0.0f}}, {.pos = { 0.5f, 0.5f, 0.5f}, .color = {0.0f, 0.0f, 1.0f}}, {.pos = {-0.5f, 0.5f, 0.5f}, .color = {1.0f, 1.0f, 1.0f}}, - {.pos = { 0.5f, 0.5f, 1.0f}, .color = {0.0f, 0.0f, 1.0f}}, - {.pos = {-0.5f, 0.5f, 1.0f}, .color = {1.0f, 1.0f, 1.0f}}, +}; + +const struct TextureVertex texture_vertices[] = { + {.pos = {-0.5f, -0.5f, 0.5f}, .color = {1.0f, 0.0f, 0.0f}, .tex = {0.0f, 1.0f}}, + {.pos = { 0.5f, -0.5f, 0.5f}, .color = {0.0f, 1.0f, 0.0f}, .tex = {1.0f, 0.0f}}, + {.pos = { 0.5f, 0.5f, 0.5f}, .color = {0.0f, 0.0f, 1.0f}, .tex = {1.0f, 1.0f}}, + {.pos = {-0.5f, 0.5f, 0.5f}, .color = {1.0f, 1.0f, 1.0f}, .tex = {0.5f, 0.5f}}, }; const uint16_t indices[] = { - 2, 1, 0, 0, 3, 2, 5, 4, 3, + 2, 1, 0, 0, 3, 2, }; const char * validation_layers[] = { @@ -1363,7 +1376,36 @@ VkFence* create_fences(VkDevice device, VkFenceCreateFlags flags, uint32_t count return fences; } -Mesh load_mesh(VkPhysicalDevice physical_device, VkDevice device, struct Vertex* vertices, uint32_t vertex_count, uint16_t* indices, uint32_t index_count, VkCommandPool transfer_pool, VkQueue transfer_queue) { +Mesh load_texture_mesh(VkPhysicalDevice physical_device, VkDevice device, struct TextureVertex* vertices, uint32_t vertex_count, uint16_t* indices, uint32_t index_count, VkCommandPool transfer_pool, VkQueue transfer_queue) { + Mesh mesh = {}; + mesh.vertex_buffer.buffer = VK_NULL_HANDLE; + mesh.vertex_buffer.memory = VK_NULL_HANDLE; + mesh.index_buffer.buffer = VK_NULL_HANDLE; + mesh.index_buffer.memory = VK_NULL_HANDLE; + + AllocatedBuffer vertex_buffer = create_populated_buffer(physical_device, device, (void*)vertices, sizeof(struct TextureVertex) * vertex_count, transfer_pool, transfer_queue, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + if(vertex_buffer.memory == VK_NULL_HANDLE) { + return mesh; + } + + mesh.vertex_buffer = vertex_buffer; + mesh.vertex_count = vertex_count; + + AllocatedBuffer index_buffer = create_populated_buffer(physical_device, device, (void*)indices, sizeof(uint16_t) * index_count, transfer_pool, transfer_queue, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + if(index_buffer.memory == VK_NULL_HANDLE) { + deallocate_buffer(device, vertex_buffer); + AllocatedBuffer tmp = { .memory = VK_NULL_HANDLE, .buffer = VK_NULL_HANDLE}; + mesh.vertex_buffer = tmp; + return mesh; + } + + mesh.index_buffer = index_buffer; + mesh.index_count = index_count; + + return mesh; +} + +Mesh load_simple_mesh(VkPhysicalDevice physical_device, VkDevice device, struct Vertex* vertices, uint32_t vertex_count, uint16_t* indices, uint32_t index_count, VkCommandPool transfer_pool, VkQueue transfer_queue) { Mesh mesh = {}; mesh.vertex_buffer.buffer = VK_NULL_HANDLE; mesh.vertex_buffer.memory = VK_NULL_HANDLE; @@ -1452,6 +1494,100 @@ Material create_material( return material; } +Material create_simple_mesh_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_ubo_layout) { + VkShaderModule vert_shader = load_shader_file(2048, "shader_src/basic.vert.spv", device); + VkShaderModule frag_shader = load_shader_file(2048, "shader_src/basic.frag.spv", device); + VkPipelineShaderStageCreateInfo shader_stages[2] = {}; + shader_stages[0].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT; + shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + shader_stages[0].module = vert_shader; + shader_stages[0].pName = "main"; + + shader_stages[1].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT; + shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shader_stages[1].module = frag_shader; + shader_stages[1].pName = "main"; + + VkVertexInputBindingDescription bindings[1] = { + { + .binding = 0, + .stride = sizeof(struct Vertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }, + }; + + VkVertexInputAttributeDescription attributes[2] = { + { + .binding = 0, + .location = 0, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(struct Vertex, pos), + }, + { + .binding = 0, + .location = 1, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(struct Vertex, color), + }, + }; + + return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, 0, 0, 0, 0, 1, bindings, 2, attributes); +} + +Material create_texture_mesh_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_ubo_layout) { + VkShaderModule vert_shader = load_shader_file(2048, "shader_src/texture.vert.spv", device); + if(vert_shader == VK_NULL_HANDLE) { + Material tmp = {}; + return tmp; + } + VkShaderModule frag_shader = load_shader_file(2048, "shader_src/texture.frag.spv", device); + if(frag_shader == VK_NULL_HANDLE) { + Material tmp = {}; + return tmp; + } + VkPipelineShaderStageCreateInfo shader_stages[2] = {}; + shader_stages[0].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT; + shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + shader_stages[0].module = vert_shader; + shader_stages[0].pName = "main"; + + shader_stages[1].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT; + shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shader_stages[1].module = frag_shader; + shader_stages[1].pName = "main"; + + VkVertexInputBindingDescription bindings[1] = { + { + .binding = 0, + .stride = sizeof(struct TextureVertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }, + }; + + VkVertexInputAttributeDescription attributes[3] = { + { + .binding = 0, + .location = 0, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(struct TextureVertex, pos), + }, + { + .binding = 0, + .location = 1, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(struct TextureVertex, color), + }, + { + .binding = 0, + .location = 2, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = offsetof(struct TextureVertex, tex), + }, + }; + + return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, 0, 0, 0, 0, 1, bindings, 3, attributes); +} + VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { VulkanContext* context = (VulkanContext*)malloc(sizeof(VulkanContext)); @@ -1688,43 +1824,7 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { vkUpdateDescriptorSets(device, 1, &descriptor_write, 0, 0); } - VkShaderModule vert_shader = load_shader_file(2048, "shader_src/basic.vert.spv", device); - VkShaderModule frag_shader = load_shader_file(2048, "shader_src/basic.frag.spv", device); - VkPipelineShaderStageCreateInfo shader_stages[2] = {}; - shader_stages[0].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT; - shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - shader_stages[0].module = vert_shader; - shader_stages[0].pName = "main"; - - shader_stages[1].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT; - shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - shader_stages[1].module = frag_shader; - shader_stages[1].pName = "main"; - - VkVertexInputBindingDescription bindings[1] = { - { - .binding = 0, - .stride = sizeof(struct Vertex), - .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, - }, - }; - - VkVertexInputAttributeDescription attributes[2] = { - { - .binding = 0, - .location = 0, - .format = VK_FORMAT_R32G32B32_SFLOAT, - .offset = offsetof(struct Vertex, pos), - }, - { - .binding = 0, - .location = 1, - .format = VK_FORMAT_R32G32B32_SFLOAT, - .offset = offsetof(struct Vertex, color), - }, - }; - - Material simple_mesh_material = create_material(context->device, context->swapchain_extent, context->render_pass, 2, shader_stages, context->scene_ubo_layout, 0, 0, 0, 0, 1, bindings, 2, attributes); + Material simple_mesh_material = create_simple_mesh_material(context->device, context->swapchain_extent, context->render_pass, context->scene_ubo_layout); if(simple_mesh_material.pipeline == VK_NULL_HANDLE) { fprintf(stderr, "failed to create simple mesh material\n"); return 0; @@ -1732,13 +1832,30 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { context->simple_mesh_material = simple_mesh_material; } - Mesh triangle_mesh = load_mesh(context->physical_device, context->device, (struct Vertex*)vertices, 6, (uint16_t*)indices, 9, context->transfer_command_pool, context->queues.transfer); + Material texture_mesh_material = create_texture_mesh_material(context->device, context->swapchain_extent, context->render_pass, context->scene_ubo_layout); + if(texture_mesh_material.pipeline == VK_NULL_HANDLE) { + fprintf(stderr, "failed to create texture mesh material\n"); + return 0; + } else { + context->texture_mesh_material = texture_mesh_material; + } + + Mesh triangle_mesh = load_simple_mesh(context->physical_device, context->device, (struct Vertex*)vertices, 4, (uint16_t*)indices, 6, context->transfer_command_pool, context->queues.transfer); if(triangle_mesh.vertex_buffer.buffer == VK_NULL_HANDLE) { fprintf(stderr, "failed to load triangle mesh\n"); + return 0; } else { context->triangle_mesh = triangle_mesh; } + Mesh triangle_mesh_textured = load_texture_mesh(context->physical_device, context->device, (struct TextureVertex*)texture_vertices, 4, (uint16_t*)indices, 6, context->transfer_command_pool, context->queues.transfer); + if(triangle_mesh_textured.vertex_buffer.buffer == VK_NULL_HANDLE) { + fprintf(stderr, "failed to load textured triangle mesh\n"); + return 0; + } else { + context->triangle_mesh_textured = triangle_mesh_textured; + } + return context; } @@ -1937,8 +2054,8 @@ VkResult draw_frame(VulkanContext* context) { } uint32_t mesh_counts[] = {1}; - Mesh* meshes[] = {&context->triangle_mesh}; - result = record_command_buffer_scene(1, &context->simple_mesh_material, (uint32_t*)&mesh_counts, (Mesh**)meshes, context->scene_ubo_descriptors[context->current_frame], context->swapchain_command_buffers[context->current_frame], context->render_pass, context->swapchain_framebuffers[image_index], context->swapchain_extent); + Mesh* meshes[] = {&context->triangle_mesh_textured}; + result = record_command_buffer_scene(1, &context->texture_mesh_material, (uint32_t*)&mesh_counts, (Mesh**)meshes, context->scene_ubo_descriptors[context->current_frame], context->swapchain_command_buffers[context->current_frame], context->render_pass, context->swapchain_framebuffers[image_index], context->swapchain_extent); if(result != VK_SUCCESS) { return result; }