From 9419ddf6e42ccf6127c2dde7d8791c19e4511844 Mon Sep 17 00:00:00 2001 From: Connor Thomson Date: Thu, 10 Sep 2026 19:30:13 -0700 Subject: Make model.c and model.h a little better --- include/model.h | 14 +++-- src/model.c | 192 ++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 140 insertions(+), 66 deletions(-) diff --git a/include/model.h b/include/model.h index 5d19307..01aa288 100644 --- a/include/model.h +++ b/include/model.h @@ -24,9 +24,11 @@ #include #include "ta_sdl.h" +#define TA_MODEL_DIMENSION 3 + typedef struct ta_model_vertex { - float position[3]; - float normal[3]; + float position[TA_MODEL_DIMENSION]; + float normal[TA_MODEL_DIMENSION]; } ta_model_vertex; typedef struct ta_model_mesh { @@ -40,13 +42,13 @@ typedef struct ta_model { ta_model_mesh mesh; Uint32 vertex_count; bool uploaded; - float position[3]; - float rotation[3]; + float position[TA_MODEL_DIMENSION]; + float rotation[TA_MODEL_DIMENSION]; } ta_model; -bool ta_model_build(const float positions[][3], size_t position_count, const unsigned int faces[][3], size_t face_count, ta_model_mesh *mesh); +bool ta_model_build(const float positions[][TA_MODEL_DIMENSION], size_t position_count, const unsigned int faces[][TA_MODEL_DIMENSION], size_t face_count, ta_model_mesh *mesh); void ta_model_free(ta_model_mesh *mesh); -bool ta_model_init(ta_model *model, SDL_GPUDevice *device, const float positions[][3], size_t position_count, const unsigned int faces[][3], size_t face_count, SDL_GPUTextureFormat color_format, SDL_GPUTextureFormat depth_format, SDL_GPUSampleCount sample_count); +bool ta_model_init(ta_model *model, SDL_GPUDevice *device, const float positions[][3], size_t position_count, const unsigned int faces[][TA_MODEL_DIMENSION], size_t face_count, SDL_GPUTextureFormat color_format, SDL_GPUTextureFormat depth_format, SDL_GPUSampleCount sample_count); void ta_model_upload(ta_model *model, SDL_GPUCommandBuffer *command_buffer, SDL_GPUDevice *device); void ta_model_render(const ta_model *model, SDL_GPUCommandBuffer *command_buffer, SDL_GPURenderPass *render_pass, int window_width, int window_height); void ta_model_destroy(ta_model *model, SDL_GPUDevice *device); diff --git a/src/model.c b/src/model.c index b256f42..b8c0efe 100644 --- a/src/model.c +++ b/src/model.c @@ -38,9 +38,7 @@ static bool ta_model_push_vertex(ta_model_mesh *mesh, size_t *capacity, const ta return true; } -bool ta_model_build(const float positions[][3], size_t position_count, - const unsigned int faces[][3], size_t face_count, - ta_model_mesh *mesh) { +bool ta_model_build(const float positions[][TA_MODEL_DIMENSION], size_t position_count, const unsigned int faces[][TA_MODEL_DIMENSION], size_t face_count, ta_model_mesh *mesh) { float *normal_accum = NULL; size_t vertex_capacity = 0; bool success = false; @@ -51,40 +49,48 @@ bool ta_model_build(const float positions[][3], size_t position_count, } for (size_t index = 0; index < face_count; index++) { - for (int corner = 0; corner < 3; corner++) { + for (int corner = 0; corner < TA_MODEL_DIMENSION; corner++) { if (faces[index][corner] >= position_count) { return false; } } } - normal_accum = calloc(position_count * 3, sizeof(*normal_accum)); + normal_accum = calloc(position_count * TA_MODEL_DIMENSION, sizeof(*normal_accum)); if (!normal_accum) { goto done; } for (size_t index = 0; index < face_count; index++) { - const float *first = positions[faces[index][0]]; + const float *first = positions[faces[index][0]]; const float *second = positions[faces[index][1]]; - const float *third = positions[faces[index][2]]; - float edge_a[3] = {second[0] - first[0], second[1] - first[1], second[2] - first[2]}; - float edge_b[3] = {third[0] - first[0], third[1] - first[1], third[2] - first[2]}; - float face_normal[3] = { + const float *third = positions[faces[index][2]]; + float edge_a[TA_MODEL_DIMENSION] = { + second[0] - first[0], + second[1] - first[1], + second[2] - first[2] + }; + float edge_b[TA_MODEL_DIMENSION] = { + third[0] - first[0], + third[1] - first[1], + third[2] - first[2] + }; + float face_normal[TA_MODEL_DIMENSION] = { edge_a[1] * edge_b[2] - edge_a[2] * edge_b[1], edge_a[2] * edge_b[0] - edge_a[0] * edge_b[2], edge_a[0] * edge_b[1] - edge_a[1] * edge_b[0], }; - for (int corner = 0; corner < 3; corner++) { + for (int corner = 0; corner < TA_MODEL_DIMENSION; corner++) { size_t position_index = faces[index][corner]; - normal_accum[position_index * 3 + 0] += face_normal[0]; - normal_accum[position_index * 3 + 1] += face_normal[1]; - normal_accum[position_index * 3 + 2] += face_normal[2]; + normal_accum[position_index * TA_MODEL_DIMENSION + 0] += face_normal[0]; + normal_accum[position_index * TA_MODEL_DIMENSION + 1] += face_normal[1]; + normal_accum[position_index * TA_MODEL_DIMENSION + 2] += face_normal[2]; } } for (size_t index = 0; index < position_count; index++) { - float *normal = &normal_accum[index * 3]; - float length = sqrtf(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]); + float *normal = &normal_accum[index * TA_MODEL_DIMENSION]; + float length = sqrtf(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]); if (length > 0.0f) { normal[0] /= length; normal[1] /= length; @@ -97,11 +103,11 @@ bool ta_model_build(const float positions[][3], size_t position_count, } for (size_t index = 0; index < face_count; index++) { - for (int corner = 0; corner < 3; corner++) { + for (int corner = 0; corner < TA_MODEL_DIMENSION; corner++) { size_t position_index = faces[index][corner]; ta_model_vertex vertex; memcpy(vertex.position, positions[position_index], sizeof(vertex.position)); - memcpy(vertex.normal, &normal_accum[position_index * 3], sizeof(vertex.normal)); + memcpy(vertex.normal, &normal_accum[position_index * TA_MODEL_DIMENSION], sizeof(vertex.normal)); if (!ta_model_push_vertex(mesh, &vertex_capacity, &vertex)) { goto done; } @@ -119,62 +125,84 @@ done: void ta_model_free(ta_model_mesh *mesh) { free(mesh->vertices); - mesh->vertices = NULL; + mesh->vertices = NULL; mesh->vertex_count = 0; } typedef struct ta_model_uniforms { - float mvp[16]; - float model[16]; - float camera_position[3]; + float mvp[16]; // TODO: Use dynamic buffer + float model[16]; // TODO: Use dynamic buffer + float camera_position[TA_MODEL_DIMENSION]; float padding; } ta_model_uniforms; static SDL_GPUShader *ta_model_shader(SDL_GPUDevice *device, const void *code, size_t size, SDL_GPUShaderStage stage) { SDL_GPUShaderCreateInfo info = { - .code = code, - .code_size = size, - .entrypoint = "main", - .format = SDL_GPU_SHADERFORMAT_SPIRV, - .stage = stage, + .code = code, + .code_size = size, + .entrypoint = "main", + .format = SDL_GPU_SHADERFORMAT_SPIRV, + .stage = stage, .num_uniform_buffers = stage == SDL_GPU_SHADERSTAGE_VERTEX ? 1 : 0, }; return ta_sdl_create_gpu_shader(device, &info); } static void ta_model_identity(float *matrix) { - for (int index = 0; index < 16; index++) matrix[index] = index % 5 == 0 ? 1.0f : 0.0f; + for (int index = 0; index < 16; index++) { + matrix[index] = index % 5 == 0 ? 1.0f : 0.0f; + } } static void ta_model_multiply(float *result, const float *left, const float *right) { float product[16]; for (int column = 0; column < 4; column++) for (int row = 0; row < 4; row++) { product[column * 4 + row] = 0.0f; - for (int inner = 0; inner < 4; inner++) product[column * 4 + row] += left[inner * 4 + row] * right[column * 4 + inner]; + for (int inner = 0; inner < 4; inner++) { + product[column * 4 + row] += left[inner * 4 + row] * right[column * 4 + inner]; + } } memcpy(result, product, sizeof(product)); } -bool ta_model_init(ta_model *model, SDL_GPUDevice *device, - const float positions[][3], size_t position_count, - const unsigned int faces[][3], size_t face_count, - SDL_GPUTextureFormat color_format, SDL_GPUTextureFormat depth_format, SDL_GPUSampleCount sample_count) { +bool ta_model_init(ta_model *model, SDL_GPUDevice *device, const float positions[][TA_MODEL_DIMENSION], size_t position_count, const unsigned int faces[][TA_MODEL_DIMENSION], size_t face_count, SDL_GPUTextureFormat color_format, SDL_GPUTextureFormat depth_format, SDL_GPUSampleCount sample_count) { memset(model, 0, sizeof(*model)); - if (!ta_model_build(positions, position_count, faces, face_count, &model->mesh) || model->mesh.vertex_count == 0) return false; - float minimum[3]; - float maximum[3]; + if (!ta_model_build(positions, position_count, faces, face_count, &model->mesh) || model->mesh.vertex_count == 0) { + return false; + } + float minimum[TA_MODEL_DIMENSION]; + float maximum[TA_MODEL_DIMENSION]; memcpy(minimum, model->mesh.vertices[0].position, sizeof(minimum)); memcpy(maximum, minimum, sizeof(maximum)); - for (size_t index = 1; index < model->mesh.vertex_count; index++) for (int axis = 0; axis < 3; axis++) { - if (model->mesh.vertices[index].position[axis] < minimum[axis]) minimum[axis] = model->mesh.vertices[index].position[axis]; - if (model->mesh.vertices[index].position[axis] > maximum[axis]) maximum[axis] = model->mesh.vertices[index].position[axis]; + for (size_t index = 1; index < model->mesh.vertex_count; index++) for (int axis = 0; axis < TA_MODEL_DIMENSION; axis++) { + if (model->mesh.vertices[index].position[axis] < minimum[axis]) { + minimum[axis] = model->mesh.vertices[index].position[axis]; + } + if (model->mesh.vertices[index].position[axis] > maximum[axis]) { + maximum[axis] = model->mesh.vertices[index].position[axis]; + } } - float center[3] = {(minimum[0] + maximum[0]) * 0.5f, (minimum[1] + maximum[1]) * 0.5f, (minimum[2] + maximum[2]) * 0.5f}; + float center[TA_MODEL_DIMENSION] = { + (minimum[0] + maximum[0]) * 0.5f, + (minimum[1] + maximum[1]) * 0.5f, + (minimum[2] + maximum[2]) * 0.5f + }; float extent = maximum[0] - minimum[0]; - for (int axis = 1; axis < 3; axis++) if (maximum[axis] - minimum[axis] > extent) extent = maximum[axis] - minimum[axis]; - for (size_t index = 0; index < model->mesh.vertex_count; index++) for (int axis = 0; axis < 3; axis++) model->mesh.vertices[index].position[axis] = (model->mesh.vertices[index].position[axis] - center[axis]) * (2.2f / extent); + for (int axis = 1; axis < TA_MODEL_DIMENSION; axis++) { + if (maximum[axis] - minimum[axis] > extent) { + extent = maximum[axis] - minimum[axis]; + } + } + for (size_t index = 0; index < model->mesh.vertex_count; index++) { + for (int axis = 0; axis < TA_MODEL_DIMENSION; axis++) { + model->mesh.vertices[index].position[axis] = (model->mesh.vertices[index].position[axis] - center[axis]) * (2.2f / extent); + } + } - SDL_GPUBufferCreateInfo buffer_info = {.usage = SDL_GPU_BUFFERUSAGE_VERTEX, .size = (Uint32)(model->mesh.vertex_count * sizeof(*model->mesh.vertices))}; + SDL_GPUBufferCreateInfo buffer_info = { + .usage = SDL_GPU_BUFFERUSAGE_VERTEX, + .size = (Uint32)(model->mesh.vertex_count * sizeof(*model->mesh.vertices)) + }; model->vertex_buffer = SDL_CreateGPUBuffer(device, &buffer_info); if (!model->vertex_buffer) { ta_model_free(&model->mesh); @@ -185,19 +213,49 @@ bool ta_model_init(ta_model *model, SDL_GPUDevice *device, SDL_GPUShader *fragment_shader = ta_model_shader(device, file_obj_frag_slang_spv_start, file_obj_frag_slang_spv_size, SDL_GPU_SHADERSTAGE_FRAGMENT); SDL_GPUVertexBufferDescription vertex_buffer = {.slot = 0, .pitch = sizeof(ta_model_vertex), .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX}; SDL_GPUVertexAttribute attributes[2] = { - {.location = 0, .buffer_slot = 0, .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, .offset = 0}, - {.location = 1, .buffer_slot = 0, .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, .offset = sizeof(float) * 3}, + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = 0 + }, + { + .location = 1, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = sizeof(float) * TA_MODEL_DIMENSION + }, + }; + SDL_GPUColorTargetDescription color_target = { + .format = color_format }; - SDL_GPUColorTargetDescription color_target = {.format = color_format}; SDL_GPUGraphicsPipelineCreateInfo pipeline_info = { - .vertex_shader = vertex_shader, - .fragment_shader = fragment_shader, - .vertex_input_state = {.vertex_buffer_descriptions = &vertex_buffer, .num_vertex_buffers = 1, .vertex_attributes = attributes, .num_vertex_attributes = 2}, - .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, - .rasterizer_state = {.cull_mode = SDL_GPU_CULLMODE_NONE}, - .depth_stencil_state = {.compare_op = SDL_GPU_COMPAREOP_LESS, .enable_depth_test = true, .enable_depth_write = true}, - .multisample_state = {.sample_count = sample_count}, - .target_info = {.num_color_targets = 1, .color_target_descriptions = &color_target, .depth_stencil_format = depth_format, .has_depth_stencil_target = true}, + .vertex_shader = vertex_shader, + .fragment_shader = fragment_shader, + .vertex_input_state = { + .vertex_buffer_descriptions = &vertex_buffer, + .num_vertex_buffers = 1, + .vertex_attributes = attributes, + .num_vertex_attributes = 2 + }, + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + .rasterizer_state = { + .cull_mode = SDL_GPU_CULLMODE_NONE + }, + .depth_stencil_state = { + .compare_op = SDL_GPU_COMPAREOP_LESS, + .enable_depth_test = true, + .enable_depth_write = true + }, + .multisample_state = { + .sample_count = sample_count + }, + .target_info = { + .num_color_targets = 1, + .color_target_descriptions = &color_target, + .depth_stencil_format = depth_format, + .has_depth_stencil_target = true + }, }; model->pipeline = ta_sdl_create_gpu_graphics_pipeline(device, &pipeline_info); SDL_ReleaseGPUShader(device, vertex_shader); @@ -206,16 +264,26 @@ bool ta_model_init(ta_model *model, SDL_GPUDevice *device, } void ta_model_upload(ta_model *model, SDL_GPUCommandBuffer *command_buffer, SDL_GPUDevice *device) { - if (model->uploaded || !model->vertex_buffer) return; + if (model->uploaded || !model->vertex_buffer) { + return; + } Uint32 size = (Uint32)(model->mesh.vertex_count * sizeof(*model->mesh.vertices)); - SDL_GPUTransferBufferCreateInfo transfer_info = {.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, .size = size}; + SDL_GPUTransferBufferCreateInfo transfer_info = { + .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, + .size = size + }; SDL_GPUTransferBuffer *transfer_buffer = ta_sdl_create_gpu_transfer_buffer(device, &transfer_info); void *mapped = ta_sdl_map_gpu_transfer_buffer(device, transfer_buffer, false); memcpy(mapped, model->mesh.vertices, size); SDL_UnmapGPUTransferBuffer(device, transfer_buffer); SDL_GPUCopyPass *copy_pass = ta_sdl_begin_gpu_copy_pass(command_buffer); - SDL_GPUTransferBufferLocation source = {.transfer_buffer = transfer_buffer}; - SDL_GPUBufferRegion destination = {.buffer = model->vertex_buffer, .size = size}; + SDL_GPUTransferBufferLocation source = { + .transfer_buffer = transfer_buffer + }; + SDL_GPUBufferRegion destination = { + .buffer = model->vertex_buffer, + .size = size + }; SDL_UploadToGPUBuffer(copy_pass, &source, &destination, false); SDL_EndGPUCopyPass(copy_pass); SDL_ReleaseGPUTransferBuffer(device, transfer_buffer); @@ -224,7 +292,9 @@ void ta_model_upload(ta_model *model, SDL_GPUCommandBuffer *command_buffer, SDL_ } void ta_model_render(const ta_model *model, SDL_GPUCommandBuffer *command_buffer, SDL_GPURenderPass *render_pass, int window_width, int window_height) { - if (!model->pipeline || !model->vertex_buffer || !model->uploaded) return; + if (!model->pipeline || !model->vertex_buffer || !model->uploaded) { + return; + } ta_model_uniforms uniforms; float view[16]; float projection[16] = {0}; @@ -277,7 +347,9 @@ void ta_model_render(const ta_model *model, SDL_GPUCommandBuffer *command_buffer uniforms.padding = 0.0f; SDL_PushGPUVertexUniformData(command_buffer, 0, &uniforms, sizeof(uniforms)); SDL_BindGPUGraphicsPipeline(render_pass, model->pipeline); - SDL_GPUBufferBinding binding = {.buffer = model->vertex_buffer}; + SDL_GPUBufferBinding binding = { + .buffer = model->vertex_buffer + }; SDL_BindGPUVertexBuffers(render_pass, 0, &binding, 1); SDL_DrawGPUPrimitives(render_pass, model->vertex_count, 1, 0, 0); } -- cgit v1.2.3