c531f5fb55
Turn's out there rendering should be done clockwise, as it was originally.
295 lines
11 KiB
C
295 lines
11 KiB
C
#include "rse_graphics.h"
|
|
|
|
#include <SDL3/SDL_error.h>
|
|
#include <SDL3/SDL_log.h>
|
|
#include <SDL3/SDL_render.h>
|
|
#include <cglm/util.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <vulkan/vulkan_core.h>
|
|
|
|
#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);
|
|
}
|