188 lines
6.5 KiB
C
188 lines
6.5 KiB
C
/**
|
|
* @file mesh_controller.h
|
|
* @author Piotr Krygier (piotrkrygier@everyonencancode.xyz)
|
|
* @brief Graphics context for Red Scarf Engine
|
|
* @version 0.1
|
|
* @date 2025-09-23
|
|
*
|
|
* @copyright Copyright (c) 2025
|
|
*
|
|
*/
|
|
#include <SDL3/SDL_log.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include "src/graphics_context.h"
|
|
#include "src/vulkan_commons.h"
|
|
#include "utilities/cgltf.h"
|
|
#include "utilities/commons.h"
|
|
#include "utilities/entity.h"
|
|
#include "utilities/errors_common.h"
|
|
#include "utilities/file_utils.h"
|
|
#include "vulkan_buffers.h"
|
|
|
|
rse_err_t mesh_create(struct graphics_context_t* context,
|
|
struct vertex_t* vertices,
|
|
uint16_t* indices,
|
|
size_t vertices_count,
|
|
size_t indices_count,
|
|
rse_id_t* mesh_id)
|
|
{
|
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
|
|
|
if (mesh_id == NULL) {
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Provided mesh id handle is NULL");
|
|
return RSE_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
*mesh_id = context->mesh_data.mesh_count;
|
|
|
|
if (context->mesh_data.mesh_count > MAX_MESH_NUMBER) {
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Could not allocate new mesh, reached maximum.");
|
|
return RSE_ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
STATUS_CHECK(add_vertices(context, *mesh_id, vertices_count, vertices, indices_count, indices));
|
|
context->mesh_data.mesh_count++;
|
|
|
|
return status;
|
|
}
|
|
|
|
rse_err_t mesh_create_from_file(struct graphics_context_t* context, const char* file_name, rse_id_t* mesh_id)
|
|
{
|
|
struct vertex_t* vertices = NULL;
|
|
uint16_t* indices = NULL;
|
|
size_t indices_count = 0U;
|
|
size_t mesh_index = 0U;
|
|
size_t primitive_index = 0U;
|
|
size_t attribute_index = 0U;
|
|
cgltf_mesh* mesh = NULL;
|
|
cgltf_primitive* primitive = NULL;
|
|
cgltf_attribute* attribute = NULL;
|
|
size_t* position_data_offset = NULL;
|
|
size_t* color_data_offset = NULL;
|
|
size_t* texture_coord_data_offset = NULL;
|
|
size_t* indices_data_offset = 0U;
|
|
size_t data_count = 0U;
|
|
size_t data_index = 0U;
|
|
size_t tmp_offset = 0U;
|
|
uint8_t* bin = NULL;
|
|
|
|
(void)context;
|
|
(void)mesh_id;
|
|
|
|
cgltf_data* data = NULL;
|
|
rse_err_t status = RSE_ERROR_NO_ERROR;
|
|
|
|
STATUS_CHECK(file_load_gltf(file_name, &data));
|
|
|
|
for (mesh_index = 0U; mesh_index < data->meshes_count; ++mesh_index) {
|
|
mesh = &data->meshes[mesh_index];
|
|
|
|
for (primitive_index = 0U; primitive_index < mesh->primitives_count; ++primitive_index) {
|
|
primitive = &mesh->primitives[primitive_index];
|
|
|
|
if (primitive->indices == NULL) {
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU,
|
|
"No indices for mesh found. Currently only indexed drawing is supported");
|
|
return RSE_ERROR_INVALID_PARAM;
|
|
} else {
|
|
rse_malloc(indices_data_offset, sizeof(size_t));
|
|
*indices_data_offset = primitive->indices->buffer_view->offset;
|
|
indices_count = primitive->indices->count;
|
|
rse_malloc(indices, (sizeof(uint16_t) * indices_count));
|
|
}
|
|
|
|
for (attribute_index = 0; attribute_index < primitive->attributes_count; ++attribute_index) {
|
|
attribute = &primitive->attributes[attribute_index];
|
|
|
|
tmp_offset = attribute->data->buffer_view->offset;
|
|
|
|
switch (attribute->type) {
|
|
case cgltf_attribute_type_position:
|
|
rse_malloc(position_data_offset, sizeof(size_t));
|
|
*position_data_offset = tmp_offset;
|
|
data_count = attribute->data->count;
|
|
break;
|
|
case cgltf_attribute_type_color:
|
|
rse_malloc(color_data_offset, sizeof(size_t));
|
|
*color_data_offset = tmp_offset;
|
|
break;
|
|
case cgltf_attribute_type_texcoord:
|
|
rse_malloc(texture_coord_data_offset, sizeof(size_t));
|
|
*texture_coord_data_offset = tmp_offset;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (position_data_offset == NULL) {
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to retrieve position data for mesh %s", file_name);
|
|
status = RSE_ERROR_INVALID_PARAM;
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (data_count == 0) {
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failure: data count for mesh is 0");
|
|
status = RSE_ERROR_INVALID_PARAM;
|
|
|
|
goto exit;
|
|
}
|
|
|
|
rse_malloc(vertices, sizeof(struct vertex_t) * data_count);
|
|
bin = (uint8_t*)data->bin;
|
|
|
|
for (data_index = 0U; data_index < data_count; ++data_index) {
|
|
rse_memcpy(vertices[data_index].pos,
|
|
(bin + *position_data_offset + (sizeof(vec3) * data_index)),
|
|
sizeof(vec3));
|
|
if (color_data_offset != NULL) {
|
|
rse_memcpy(vertices[data_index].color,
|
|
(bin + *color_data_offset + (sizeof(vec3) * data_index)),
|
|
sizeof(vec3));
|
|
} else {
|
|
vertices[data_index].color[0] = 1.0;
|
|
vertices[data_index].color[1] = 1.0;
|
|
vertices[data_index].color[2] = 1.0;
|
|
}
|
|
|
|
if (texture_coord_data_offset != NULL) {
|
|
rse_memcpy(vertices[data_index].tex_coords,
|
|
(bin + *texture_coord_data_offset + (sizeof(vec2) * data_index)),
|
|
sizeof(vec2));
|
|
}
|
|
}
|
|
|
|
rse_memcpy(indices, (bin + *indices_data_offset), (sizeof(uint16_t) * indices_count));
|
|
|
|
STATUS_CHECK(mesh_create(context, vertices, indices, data_count, indices_count, mesh_id));
|
|
}
|
|
|
|
exit:
|
|
rse_free(position_data_offset);
|
|
rse_free(color_data_offset);
|
|
rse_free(texture_coord_data_offset);
|
|
rse_free(indices_data_offset);
|
|
rse_free(vertices);
|
|
rse_free(indices);
|
|
cgltf_free(data);
|
|
|
|
return status;
|
|
}
|
|
|
|
rse_err_t mesh_create_instance(struct graphics_context_t* context,
|
|
entity_t entity,
|
|
struct instance_data_t instance_data)
|
|
{
|
|
if (context->mesh_data.mesh_bucket[entity].instances_count >= MAX_INSTANCE_NUMBER) {
|
|
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Could not allocate new mesh, reached maximum.");
|
|
return RSE_ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
return mesh_add_instance(context, entity, &instance_data);
|
|
}
|