#include "rse_graphics.h" #include #include #include #include #include #include #include #include "descriptor_builder.h" #include "font_manager.h" #include "graphics_context.h" #include "mesh_controller.h" #include "pipeline_builder.h" #include "src/renderer.h" #include "src/vulkan_buffers.h" #include "utilities/commons.h" #include "utilities/errors_common.h" #include "utilities/time_utils.h" #include "vulkan_base.h" #include "vulkan_commons.h" #include "vulkan_image.h" #include "window.h" struct rse_graphics_context_t { struct graphics_context_t* context; }; static void model_view_projection_update(struct graphics_context_t* context) { vec3 eye = {0}; vec3 center = {0}; vec3 up = {0}; vec3 rotation_vec = {0.0f, 1.0f, 0.0f}; float fovy; float z_near; float z_far; static float rotation = 0.0; eye[2] = -4.0f; up[1] = 1.0f; fovy = glm_rad(45.0f); z_near = 0.1f; z_far = 20.0f; glm_mat4_identity(context->mvp_data.model); glm_rotate(context->mvp_data.model, rotation, rotation_vec); glm_lookat(eye, center, up, context->mvp_data.view); glm_perspective( fovy, context->swapchain_data.swapchain_extent.width / (float)context->swapchain_data.swapchain_extent.height, z_near, z_far, context->mvp_data.proj); rotation += time_get_dt() * glm_rad(120.0); } static rse_err_t render_static_mesh(struct graphics_context_t* context, uint32_t renderer_id) { VkCommandBuffer command_buffer = context->vulkan_handles.command_buffers[context->current_frame]; VkDeviceSize offsets[] = {0}; uint32_t mvp_offset = 0; uint32_t mvp_size = sizeof(struct mvp_data_t); (void)renderer_id; vkCmdPushConstants(command_buffer, context->pipelines_data.pipeline_layouts[0], VK_SHADER_STAGE_VERTEX_BIT, mvp_offset, mvp_size, &context->mvp_data); model_view_projection_update(context); vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->pipelines_data.pipelines[0]); vkCmdBindIndexBuffer(command_buffer, context->render_targets[RENDER_TARGET_3D].index_buffer.buffer, 0, VK_INDEX_TYPE_UINT16); vkCmdBindVertexBuffers(command_buffer, 0, 1, &context->render_targets[RENDER_TARGET_3D].vertex_buffer.buffer, offsets); /* FIXME: Currently we can only bind one descriptor set */ vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->pipelines_data.pipeline_layouts[0], 0, 1, &context->descriptor_data.descriptor_sets[0], 0, NULL); vkCmdDrawIndexedIndirect(command_buffer, context->render_targets[RENDER_TARGET_3D].draw_indirect_command_buffer.buffer, 0, context->mesh_data.mesh_count, sizeof(VkDrawIndexedIndirectCommand)); return RSE_ERROR_NO_ERROR; } rse_err_t rse_graphics_init(struct graphics_context_t* context) { rse_err_t status = RSE_ERROR_NO_ERROR; STATUS_CHECK(window_init(&context->window_handle, &context->is_framebuffer_resized)); STATUS_CHECK(vulkan_init(context)); return status; } #define TEXTURES_COUNT (3U) rse_err_t rse_graphics_test_function(struct graphics_context_t* context) { rse_err_t status = RSE_ERROR_NO_ERROR; rse_id_t textures[TEXTURES_COUNT] = {0}; struct pipeline_t pipeline; rse_id_t descriptor_set_handle = 0; struct descriptor_set_layout_bindings_t layout_bindings = {0}; struct pipeline_infos_t pipeline_infos = {0}; rse_id_t mesh_id_1 = 0; rse_id_t mesh_id_2 = 0; rse_id_t avocado_id = 0; // rse_id_t font_id = 0; rse_id_t static_mesh_renderer = 0U; rse_id_t vertex_shader_id, fragment_shader_id; STATUS_CHECK(texture_load_from_file(context, "../../test_image.jpg", &textures[0])); STATUS_CHECK(texture_load_from_file(context, "../../test_image_2.jpg", &textures[1])); STATUS_CHECK(texture_load_from_file(context, "../../Avocado_baseColor.png", &textures[2])); // STATUS_CHECK(fonts_init()); // STATUS_CHECK(fonts_load_from_file(context, "../../NotoSansMono-Regular.ttf", &font_id)); // STATUS_CHECK(fonts_set_font_size(context, font_id, 16)); // FIXME: Temporary array of vertices, for testing purposes struct vertex_t vertices[] = { {{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, {{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}, {{0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, {{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, }; struct vertex_t vertices_2[] = { {{-0.7f, -0.7f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, {{-0.7f, 0.7f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}, {{0.1f, 0.7f, 0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, {{0.1f, -0.7f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, }; // FIXME: Temporary array of vertices, for testing purposes uint16_t indices[] = {0, 1, 2, 2, 3, 0, 0, 3, 2, 2, 1, 0}; STATUS_CHECK(mesh_create(context, vertices, indices, 4, 12, &mesh_id_1)); if (RSE_ERROR_NO_ERROR != mesh_create_instance(context, mesh_id_1, (struct instance_data_t){{0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0}, 0.5f, textures[0]})) { exit(1); } if (RSE_ERROR_NO_ERROR != mesh_create_instance( context, mesh_id_1, (struct instance_data_t){{-0.5f, 0.0f, -1.0f}, {0.0f, 0.0f, glm_rad(10.0f)}, 0.5f, textures[1]})) { exit(1); } STATUS_CHECK(mesh_create(context, vertices_2, indices, 4, 6, &mesh_id_2)); if (RSE_ERROR_NO_ERROR != mesh_create_instance( context, mesh_id_2, (struct instance_data_t){{0.5f, 0.0f, 1.0f}, {0.0f, 0.0f, glm_rad(0.0f)}, 0.5f, textures[1]})) { exit(1); } mesh_create_from_file(context, "../../Avocado.glb", &avocado_id); if (RSE_ERROR_NO_ERROR != mesh_create_instance( context, avocado_id, (struct instance_data_t){{0.0f, 0.2f, 0.0f}, {0.0f, 0.0f, glm_rad(180.0f)}, 10.0f, textures[2]})) { exit(1); } STATUS_CHECK(buffers_update(context)); STATUS_CHECK(sampler_create(context, &context->vulkan_handles.sampler)); STATUS_CHECK(descriptor_pool_add_type(context, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1)); STATUS_CHECK(descriptor_pool_add_type(context, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, TEXTURES_COUNT)); STATUS_CHECK(descriptor_pool_initialize(context)); /* Normal rendering */ STATUS_CHECK(descriptor_create_new_set(context, &descriptor_set_handle)); STATUS_CHECK( descriptor_add_layout(&layout_bindings, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT)); STATUS_CHECK(descriptor_add_layout(&layout_bindings, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, TEXTURES_COUNT, VK_SHADER_STAGE_FRAGMENT_BIT)); STATUS_CHECK(descriptor_set_finish(context, &layout_bindings, descriptor_set_handle)); STATUS_CHECK(descriptor_build_sets(context)); STATUS_CHECK(descriptor_attach_buffer(context, descriptor_set_handle, &context->render_targets[RENDER_TARGET_3D].instance_buffer, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)); STATUS_CHECK(descriptor_attach_images(context, descriptor_set_handle, textures, TEXTURES_COUNT, context->vulkan_handles.sampler, 1)); /* Initialize pipeline */ pipeline_builder_init(&pipeline); shader_create_module(context, &vertex_shader_id, "shader.vert.num", VK_SHADER_STAGE_VERTEX_BIT); pipeline_add_shader_stage(context, &pipeline, vertex_shader_id); shader_create_module(context, &fragment_shader_id, "solid_objects.frag.num", VK_SHADER_STAGE_FRAGMENT_BIT); pipeline_add_shader_stage(context, &pipeline, fragment_shader_id); pipeline_add_vertex_input_binding(&pipeline, 0, sizeof(struct vertex_t), VK_VERTEX_INPUT_RATE_VERTEX); pipeline_add_vertex_input_attribute(&pipeline, 0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct vertex_t, pos)); pipeline_add_vertex_input_attribute(&pipeline, 0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct vertex_t, color)); pipeline_add_vertex_input_attribute(&pipeline, 0, 2, VK_FORMAT_R32G32_SFLOAT, offsetof(struct vertex_t, tex_coords)); pipeline_add_dynamic_state(&pipeline, VK_DYNAMIC_STATE_VIEWPORT); pipeline_add_dynamic_state(&pipeline, VK_DYNAMIC_STATE_SCISSOR); pipeline_add_push_constants(&pipeline, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(struct mvp_data_t)); pipeline_add_descriptor_sets(context, &pipeline, descriptor_set_handle); pipeline_add(context, &pipeline, &pipeline_infos); pipelines_build(context, &pipeline_infos); renderer_get_new_id(context, &static_mesh_renderer); renderer_set_render_function(context, static_mesh_renderer, render_static_mesh); return RSE_ERROR_NO_ERROR; } rse_err_t rse_graphics_run(struct graphics_context_t* context) { rse_err_t status = RSE_ERROR_NO_ERROR; STATUS_CHECK(vulkan_run(context)); return status; } rse_err_t rse_graphics_main_loop(struct graphics_context_t* context) { rse_err_t status = RSE_ERROR_NO_ERROR; STATUS_CHECK(vulkan_draw_frame(context)); return status; } // rse_err_t rse_graphics_load_model(struct graphics_context_t* context, const char* model_path, rse_id_t* model_id) // { // rse_err_t status = RSE_ERROR_NO_ERROR; // // return status; // } void rse_graphics_deinit(struct graphics_context_t* context) { vulkan_deinit(context); window_terminate(context->window_handle); rse_free(context->debug_overlay.pixels); }