summaryrefslogtreecommitdiff
path: root/src/obj.c
diff options
context:
space:
mode:
authorConnor Thomson <blumatrikz@gmail.com>2026-09-10 17:07:15 -0700
committerConnor Thomson <blumatrikz@gmail.com>2026-09-10 17:07:15 -0700
commite9d4cbaa3c44337115d672d2038a7b73745181c8 (patch)
treeacc15d887e370117f80cc94512af612002ebdbd9 /src/obj.c
parentda1891aa0a053297e1b17bc34c23c362f9ac0c6b (diff)
Update teapot model, add phong shading, & more
Diffstat (limited to 'src/obj.c')
-rw-r--r--src/obj.c139
1 files changed, 79 insertions, 60 deletions
diff --git a/src/obj.c b/src/obj.c
index 7f3442c..4887d52 100644
--- a/src/obj.c
+++ b/src/obj.c
@@ -28,9 +28,9 @@ typedef struct ta_obj_position {
float value[3];
} ta_obj_position;
-typedef struct ta_obj_normal {
- float value[3];
-} ta_obj_normal;
+typedef struct ta_obj_face {
+ int position_indices[3];
+} ta_obj_face;
static bool ta_obj_push_vertex(ta_obj_mesh *mesh, size_t *capacity, const ta_obj_vertex *vertex) {
if (mesh->vertex_count == *capacity) {
@@ -48,11 +48,12 @@ static bool ta_obj_push_vertex(ta_obj_mesh *mesh, size_t *capacity, const ta_obj
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;
+ ta_obj_face *faces = NULL;
+ float *normal_accum = NULL;
size_t position_count = 0;
- size_t normal_count = 0;
+ size_t face_count = 0;
size_t position_capacity = 0;
- size_t normal_capacity = 0;
+ size_t face_capacity = 0;
size_t vertex_capacity = 0;
bool success = false;
@@ -86,84 +87,102 @@ bool ta_obj_parse(const unsigned char *data, size_t size, ta_obj_mesh *mesh) {
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];
+ ta_obj_face face;
+ int discarded_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;
+ &face.position_indices[0], &discarded_normal_indices[0],
+ &face.position_indices[1], &discarded_normal_indices[1],
+ &face.position_indices[2], &discarded_normal_indices[2]) == 6;
if (!has_normals && sscanf(line + 2, "%d %d %d",
- &position_indices[0], &position_indices[1], &position_indices[2]) != 3) {
+ &face.position_indices[0], &face.position_indices[1], &face.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))) {
+ if (face.position_indices[index] <= 0 || (size_t)face.position_indices[index] > position_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)) {
+ if (face_count == face_capacity) {
+ size_t next_capacity = face_capacity == 0 ? 1024 : face_capacity * 2;
+ ta_obj_face *grown = realloc(faces, next_capacity * sizeof(*grown));
+ if (!grown) {
goto done;
}
+ faces = grown;
+ face_capacity = next_capacity;
}
+ faces[face_count++] = face;
}
-
+
if (!next_line) {
break;
}
line = next_line + 1;
}
+ if (position_count == 0 || face_count == 0) {
+ goto done;
+ }
+
+ normal_accum = calloc(position_count * 3, sizeof(*normal_accum));
+ if (!normal_accum) {
+ goto done;
+ }
+
+ for (size_t index = 0; index < face_count; index++) {
+ const float *first = positions[faces[index].position_indices[0] - 1].value;
+ const float *second = positions[faces[index].position_indices[1] - 1].value;
+ const float *third = positions[faces[index].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]};
+ float face_normal[3] = {
+ 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++) {
+ size_t position_index = (size_t)(faces[index].position_indices[corner] - 1);
+ 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];
+ }
+ }
+
+ 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]);
+ if (length > 0.0f) {
+ normal[0] /= length;
+ normal[1] /= length;
+ normal[2] /= length;
+ } else {
+ normal[0] = 0.0f;
+ normal[1] = 0.0f;
+ normal[2] = 1.0f;
+ }
+ }
+
+ for (size_t index = 0; index < face_count; index++) {
+ for (int corner = 0; corner < 3; corner++) {
+ size_t position_index = (size_t)(faces[index].position_indices[corner] - 1);
+ ta_obj_vertex vertex;
+ memcpy(vertex.position, positions[position_index].value, sizeof(vertex.position));
+ memcpy(vertex.normal, &normal_accum[position_index * 3], sizeof(vertex.normal));
+ if (!ta_obj_push_vertex(mesh, &vertex_capacity, &vertex)) {
+ goto done;
+ }
+ }
+ }
+
success = mesh->vertex_count > 0;
done:
if (!success) {
ta_obj_free(mesh);
}
free(positions);
- free(normals);
+ free(faces);
+ free(normal_accum);
free(text);
return success;
}
@@ -172,4 +191,4 @@ void ta_obj_free(ta_obj_mesh *mesh) {
free(mesh->vertices);
mesh->vertices = NULL;
mesh->vertex_count = 0;
-} \ No newline at end of file
+}