diff options
| author | Connor Thomson <blumatrikz@gmail.com> | 2026-09-10 17:07:15 -0700 |
|---|---|---|
| committer | Connor Thomson <blumatrikz@gmail.com> | 2026-09-10 17:07:15 -0700 |
| commit | e9d4cbaa3c44337115d672d2038a7b73745181c8 (patch) | |
| tree | acc15d887e370117f80cc94512af612002ebdbd9 /src/obj.c | |
| parent | da1891aa0a053297e1b17bc34c23c362f9ac0c6b (diff) | |
Update teapot model, add phong shading, & more
Diffstat (limited to 'src/obj.c')
| -rw-r--r-- | src/obj.c | 139 |
1 files changed, 79 insertions, 60 deletions
@@ -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 +} |