diff options
| author | Connor Thomson <blumatrikz@gmail.com> | 2026-09-08 18:27:39 -0700 |
|---|---|---|
| committer | Connor Thomson <blumatrikz@gmail.com> | 2026-09-08 18:27:39 -0700 |
| commit | f1ddc12b68b4e4c8087962de25260470e6df2bea (patch) | |
| tree | 7d0440a6402a9b0ef75ded23fa64b68534255bba /src/obj.c | |
| parent | 6025860a61386bf767b29c3ec5fd0d31285f1056 (diff) | |
Add tuxanci2 files
Diffstat (limited to 'src/obj.c')
| -rw-r--r-- | src/obj.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/src/obj.c b/src/obj.c new file mode 100644 index 0000000..7f3442c --- /dev/null +++ b/src/obj.c @@ -0,0 +1,175 @@ +/* + * Tuxánci 2 - A first person shooter + * Copyright (C) 2007-2011 Tuxánci Development Team + * Copyright (C) 2025-2026 Connor Thomson + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdbool.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "obj.h" + +typedef struct ta_obj_position { + float value[3]; +} ta_obj_position; + +typedef struct ta_obj_normal { + float value[3]; +} ta_obj_normal; + +static bool ta_obj_push_vertex(ta_obj_mesh *mesh, size_t *capacity, const ta_obj_vertex *vertex) { + if (mesh->vertex_count == *capacity) { + size_t next_capacity = *capacity == 0 ? 1024 : *capacity * 2; + ta_obj_vertex *vertices = realloc(mesh->vertices, next_capacity * sizeof(*vertices)); + if (!vertices) { + return false; + } + mesh->vertices = vertices; + *capacity = next_capacity; + } + mesh->vertices[mesh->vertex_count++] = *vertex; + return true; +} + +bool ta_obj_parse(const unsigned char *data, size_t size, ta_obj_mesh *mesh) { + ta_obj_position *positions = NULL; + ta_obj_normal *normals = NULL; + size_t position_count = 0; + size_t normal_count = 0; + size_t position_capacity = 0; + size_t normal_capacity = 0; + size_t vertex_capacity = 0; + bool success = false; + + memset(mesh, 0, sizeof(*mesh)); + char *text = malloc(size + 1); + if (!text) { + return false; + } + memcpy(text, data, size); + text[size] = '\0'; + + char *line = text; + while (line && *line) { + char *next_line = strchr(line, '\n'); + if (next_line) { + *next_line = '\0'; + } + + if (line[0] == 'v' && line[1] == ' ') { + ta_obj_position position; + if (sscanf(line + 2, "%f %f %f", &position.value[0], &position.value[1], &position.value[2]) != 3) { + goto done; + } + if (position_count == position_capacity) { + size_t next_capacity = position_capacity == 0 ? 1024 : position_capacity * 2; + ta_obj_position *grown = realloc(positions, next_capacity * sizeof(*grown)); + if (!grown) { + goto done; + } + positions = grown; + position_capacity = next_capacity; + } + positions[position_count++] = position; + } else if (line[0] == 'v' && line[1] == 'n' && line[2] == ' ') { + ta_obj_normal normal; + if (sscanf(line + 3, "%f %f %f", &normal.value[0], &normal.value[1], &normal.value[2]) != 3) { + goto done; + } + if (normal_count == normal_capacity) { + size_t next_capacity = normal_capacity == 0 ? 1024 : normal_capacity * 2; + ta_obj_normal *grown = realloc(normals, next_capacity * sizeof(*grown)); + if (!grown) { + goto done; + } + normals = grown; + normal_capacity = next_capacity; + } + normals[normal_count++] = normal; + } else if (line[0] == 'f' && line[1] == ' ') { + int position_indices[3]; + int normal_indices[3]; + bool has_normals = sscanf(line + 2, "%d//%d %d//%d %d//%d", + &position_indices[0], &normal_indices[0], + &position_indices[1], &normal_indices[1], + &position_indices[2], &normal_indices[2]) == 6; + if (!has_normals && sscanf(line + 2, "%d %d %d", + &position_indices[0], &position_indices[1], &position_indices[2]) != 3) { + goto done; + } + for (int index = 0; index < 3; index++) { + if (position_indices[index] <= 0 || + (size_t)position_indices[index] > position_count || + (has_normals && (normal_indices[index] <= 0 || + (size_t)normal_indices[index] > normal_count))) { + goto done; + } + } + float face_normal[3] = {0.0f, 0.0f, 1.0f}; + if (!has_normals) { + const float *first = positions[position_indices[0] - 1].value; + const float *second = positions[position_indices[1] - 1].value; + const float *third = positions[position_indices[2] - 1].value; + 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]}; + face_normal[0] = edge_a[1] * edge_b[2] - edge_a[2] * edge_b[1]; + face_normal[1] = edge_a[2] * edge_b[0] - edge_a[0] * edge_b[2]; + face_normal[2] = edge_a[0] * edge_b[1] - edge_a[1] * edge_b[0]; + float length = sqrtf(face_normal[0] * face_normal[0] + face_normal[1] * face_normal[1] + face_normal[2] * face_normal[2]); + if (length > 0.0f) { + face_normal[0] /= length; + face_normal[1] /= length; + face_normal[2] /= length; + } + } + for (int index = 0; index < 3; index++) { + ta_obj_vertex vertex; + memcpy(vertex.position, positions[position_indices[index] - 1].value, sizeof(vertex.position)); + if (has_normals) { + memcpy(vertex.normal, normals[normal_indices[index] - 1].value, sizeof(vertex.normal)); + } else { + memcpy(vertex.normal, face_normal, sizeof(vertex.normal)); + } + if (!ta_obj_push_vertex(mesh, &vertex_capacity, &vertex)) { + goto done; + } + } + } + + if (!next_line) { + break; + } + line = next_line + 1; + } + + success = mesh->vertex_count > 0; +done: + if (!success) { + ta_obj_free(mesh); + } + free(positions); + free(normals); + free(text); + return success; +} + +void ta_obj_free(ta_obj_mesh *mesh) { + free(mesh->vertices); + mesh->vertices = NULL; + mesh->vertex_count = 0; +}
\ No newline at end of file |