gltf import fixes

This commit is contained in:
luboslenco
2025-11-21 16:06:48 +01:00
parent 19f215457e
commit 36a9dc04bc
+91 -106
View File
@@ -1,103 +1,71 @@
#define CGLTF_IMPLEMENTATION #define CGLTF_IMPLEMENTATION
#include "cgltf.h" #include "cgltf.h"
#include <math.h>
#include "iron_array.h" #include "iron_array.h"
#include "iron_obj.h" #include "iron_obj.h"
#include <math.h>
static bool has_next = false; static bool has_next = false;
static int current_node = 0; static int current_node = 0;
static float scale_pos = 1.0; static float scale_pos = 1.0;
uint32_t *io_gltf_read_u8_array(cgltf_accessor *a) {
cgltf_buffer_view *v = a->buffer_view;
uint8_t *ar = (uint8_t *) (v->buffer->data + v->offset);
uint32_t *res = malloc(sizeof(uint32_t) * v->size);
for (int i = 0; i < v->size; ++i) {
res[i] = ar[i];
}
return res;
}
uint32_t *io_gltf_read_u16_array(cgltf_accessor *a) {
cgltf_buffer_view *v = a->buffer_view;
uint16_t *ar = (uint16_t *) (v->buffer->data + v->offset);
uint32_t *res = malloc(sizeof(unsigned int) * v->size);
for (int i = 0; i < a->count; ++i) {
res[i] = ar[i];
}
return res;
}
uint32_t *io_gltf_read_u32_array(cgltf_accessor *a) {
cgltf_buffer_view *v = a->buffer_view;
uint32_t *ar = (uint32_t *) (v->buffer->data + v->offset);
return ar;
}
float *io_gltf_read_f32_array(cgltf_accessor *a) {
cgltf_buffer_view *v = a->buffer_view;
float *ar = (float *) (v->buffer->data + v->offset);
return ar;
}
void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, float *scale) { void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, float *scale) {
cgltf_primitive *prim = NULL; cgltf_primitive *prim = NULL;
uint32_t *inda = NULL; uint32_t *inda = NULL;
for (int i = 0; i < mesh->primitives_count; ++i) { for (int i = 0; i < mesh->primitives_count; ++i) {
prim = &mesh->primitives[0]; // TODO: handle all primitives
prim = &mesh->primitives[i];
cgltf_accessor *a = prim->indices; cgltf_accessor *a = prim->indices;
int elem_size = a->buffer_view->size / a->count; inda = malloc(sizeof(uint32_t) * a->count);
for (cgltf_size i = 0; i < a->count; ++i) {
inda = elem_size == 1 ? io_gltf_read_u8_array(a) inda[i] = cgltf_accessor_read_index(a, i);
: elem_size == 2 ? io_gltf_read_u16_array(a)
: elem_size == 4 ? io_gltf_read_u32_array(a) : NULL;
if (inda) {
break;
} }
} }
if (!inda) { if (inda == NULL) {
// All of the primitives in the mesh don't have data
return; return;
} }
int index_count = prim->indices->count; int index_count = prim->indices->count;
int vertex_count = -1;
int vertex_count = -1; float *posa32 = NULL;
float *posa32 = NULL; float *nora32 = NULL;
float *nora32 = NULL; float *texa32 = NULL;
float *texa32 = NULL;
for (int i = 0; i < prim->attributes_count; ++i) { for (int i = 0; i < prim->attributes_count; ++i) {
cgltf_attribute* attrib = &prim->attributes[i]; cgltf_attribute *attrib = &prim->attributes[i];
if (attrib->type == cgltf_attribute_type_position) { if (attrib->type == cgltf_attribute_type_position) {
vertex_count = attrib->data->count; vertex_count = attrib->data->count;
posa32 = io_gltf_read_f32_array(attrib->data); posa32 = malloc(sizeof(float) * attrib->data->count * 3);
for (cgltf_size i = 0; i < attrib->data->count; ++i) {
cgltf_accessor_read_float(attrib->data, i, posa32 + i * 3, 3);
}
} }
else if (attrib->type == cgltf_attribute_type_normal) { else if (attrib->type == cgltf_attribute_type_normal) {
nora32 = io_gltf_read_f32_array(attrib->data); nora32 = malloc(sizeof(float) * attrib->data->count * 3);
for (cgltf_size i = 0; i < attrib->data->count; ++i) {
cgltf_accessor_read_float(attrib->data, i, nora32 + i * 3, 3);
}
} }
else if (attrib->type == cgltf_attribute_type_texcoord) { else if (attrib->type == cgltf_attribute_type_texcoord) {
texa32 = io_gltf_read_f32_array(attrib->data); texa32 = malloc(sizeof(float) * attrib->data->count * 2);
for (cgltf_size i = 0; i < attrib->data->count; ++i) {
cgltf_accessor_read_float(attrib->data, i, texa32 + i * 2, 2);
}
} }
} }
if (vertex_count == -1) { if (vertex_count == -1) {
// No vertex data position attributes found in primitive
return; return;
} }
float *m = to_world; float *m = to_world;
for (int i = 0; i < vertex_count; ++i) { for (int i = 0; i < vertex_count; ++i) {
float x = posa32[i * 3 + 0]; float x = posa32[i * 3 + 0];
float y = posa32[i * 3 + 1]; float y = posa32[i * 3 + 1];
float z = posa32[i * 3 + 2]; float z = posa32[i * 3 + 2];
posa32[i * 3 + 0] = m[0] * x + m[4] * y + m[8] * z + m[12]; posa32[i * 3 + 0] = m[0] * x + m[4] * y + m[8] * z + m[12];
posa32[i * 3 + 1] = m[1] * x + m[5] * y + m[9] * z + m[13]; posa32[i * 3 + 1] = m[1] * x + m[5] * y + m[9] * z + m[13];
posa32[i * 3 + 2] = m[2] * x + m[6] * y + m[10] * z + m[14]; posa32[i * 3 + 2] = m[2] * x + m[6] * y + m[10] * z + m[14];
@@ -105,12 +73,21 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa
if (nora32 != NULL) { if (nora32 != NULL) {
for (int i = 0; i < vertex_count; ++i) { for (int i = 0; i < vertex_count; ++i) {
float x = nora32[i * 3 + 0] / scale[0]; float x = nora32[i * 3 + 0] / scale[0];
float y = nora32[i * 3 + 1] / scale[1]; float y = nora32[i * 3 + 1] / scale[1];
float z = nora32[i * 3 + 2] / scale[2]; float z = nora32[i * 3 + 2] / scale[2];
nora32[i * 3 + 0] = m[0] * x + m[4] * y + m[8] * z; float tx = m[0] * x + m[4] * y + m[8] * z;
nora32[i * 3 + 1] = m[1] * x + m[5] * y + m[9] * z; float ty = m[1] * x + m[5] * y + m[9] * z;
nora32[i * 3 + 2] = m[2] * x + m[6] * y + m[10] * z; float tz = m[2] * x + m[6] * y + m[10] * z;
float len = sqrtf(tx * tx + ty * ty + tz * tz);
if (len > 1e-6f) {
tx /= len;
ty /= len;
tz /= len;
}
nora32[i * 3 + 0] = tx;
nora32[i * 3 + 1] = ty;
nora32[i * 3 + 2] = tz;
} }
} }
@@ -120,21 +97,25 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa
float hz = 0.0; float hz = 0.0;
for (int i = 0; i < vertex_count; ++i) { for (int i = 0; i < vertex_count; ++i) {
float f = fabsf(posa32[i * 3]); float f = fabsf(posa32[i * 3]);
if (hx < f) hx = f; if (hx < f)
hx = f;
f = fabsf(posa32[i * 3 + 1]); f = fabsf(posa32[i * 3 + 1]);
if (hy < f) hy = f; if (hy < f)
hy = f;
f = fabsf(posa32[i * 3 + 2]); f = fabsf(posa32[i * 3 + 2]);
if (hz < f) hz = f; if (hz < f)
hz = f;
} }
float _scale_pos = fmax(hx, fmax(hy, hz)); float _scale_pos = fmax(hx, fmax(hy, hz));
if (_scale_pos > scale_pos) scale_pos = _scale_pos; if (_scale_pos > scale_pos)
scale_pos = _scale_pos;
float inv = 1 / scale_pos; float inv = 1 / scale_pos;
// Pack into 16bit // Pack into 16bit
short *posa = malloc(sizeof(short) * vertex_count * 4); short *posa = malloc(sizeof(short) * vertex_count * 4);
for (int i = 0; i < vertex_count; ++i) { for (int i = 0; i < vertex_count; ++i) {
posa[i * 4 ] = posa32[i * 3 ] * 32767 * inv; posa[i * 4] = posa32[i * 3] * 32767 * inv;
posa[i * 4 + 1] = posa32[i * 3 + 1] * 32767 * inv; posa[i * 4 + 1] = posa32[i * 3 + 1] * 32767 * inv;
posa[i * 4 + 2] = posa32[i * 3 + 2] * 32767 * inv; posa[i * 4 + 2] = posa32[i * 3 + 2] * 32767 * inv;
} }
@@ -142,7 +123,7 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa
short *nora = malloc(sizeof(short) * vertex_count * 2); short *nora = malloc(sizeof(short) * vertex_count * 2);
if (nora32 != NULL) { if (nora32 != NULL) {
for (int i = 0; i < vertex_count; ++i) { for (int i = 0; i < vertex_count; ++i) {
nora[i * 2 ] = nora32[i * 3 ] * 32767; nora[i * 2] = nora32[i * 3] * 32767;
nora[i * 2 + 1] = nora32[i * 3 + 1] * 32767; nora[i * 2 + 1] = nora32[i * 3 + 1] * 32767;
posa[i * 4 + 3] = nora32[i * 3 + 2] * 32767; posa[i * 4 + 3] = nora32[i * 3 + 2] * 32767;
} }
@@ -150,18 +131,28 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa
else { else {
// Calc normals // Calc normals
for (int i = 0; i < index_count / 3; ++i) { for (int i = 0; i < index_count / 3; ++i) {
int i1 = inda[i * 3 ]; int i1 = inda[i * 3];
int i2 = inda[i * 3 + 1]; int i2 = inda[i * 3 + 1];
int i3 = inda[i * 3 + 2]; int i3 = inda[i * 3 + 2];
float vax = posa32[i1 * 3]; float vay = posa32[i1 * 3 + 1]; float vaz = posa32[i1 * 3 + 2]; float vax = posa32[i1 * 3];
float vbx = posa32[i2 * 3]; float vby = posa32[i2 * 3 + 1]; float vbz = posa32[i2 * 3 + 2]; float vay = posa32[i1 * 3 + 1];
float vcx = posa32[i3 * 3]; float vcy = posa32[i3 * 3 + 1]; float vcz = posa32[i3 * 3 + 2]; float vaz = posa32[i1 * 3 + 2];
float cbx = vcx - vbx; float cby = vcy - vby; float cbz = vcz - vbz; float vbx = posa32[i2 * 3];
float abx = vax - vbx; float aby = vay - vby; float abz = vaz - vbz; float vby = posa32[i2 * 3 + 1];
float vbz = posa32[i2 * 3 + 2];
float vcx = posa32[i3 * 3];
float vcy = posa32[i3 * 3 + 1];
float vcz = posa32[i3 * 3 + 2];
float cbx = vcx - vbx;
float cby = vcy - vby;
float cbz = vcz - vbz;
float abx = vax - vbx;
float aby = vay - vby;
float abz = vaz - vbz;
float x = cbx, y = cby, z = cbz; float x = cbx, y = cby, z = cbz;
cbx = y * abz - z * aby; cbx = y * abz - z * aby;
cby = z * abx - x * abz; cby = z * abx - x * abz;
cbz = x * aby - y * abx; cbz = x * aby - y * abx;
float n = sqrt(cbx * cbx + cby * cby + cbz * cbz); float n = sqrt(cbx * cbx + cby * cby + cbz * cbz);
if (n > 0.0) { if (n > 0.0) {
float inv_n = 1.0 / n; float inv_n = 1.0 / n;
@@ -169,13 +160,13 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa
cby *= inv_n; cby *= inv_n;
cbz *= inv_n; cbz *= inv_n;
} }
nora[i1 * 2 ] = (int)(cbx * 32767); nora[i1 * 2] = (int)(cbx * 32767);
nora[i1 * 2 + 1] = (int)(cby * 32767); nora[i1 * 2 + 1] = (int)(cby * 32767);
posa[i1 * 4 + 3] = (int)(cbz * 32767); posa[i1 * 4 + 3] = (int)(cbz * 32767);
nora[i2 * 2 ] = (int)(cbx * 32767); nora[i2 * 2] = (int)(cbx * 32767);
nora[i2 * 2 + 1] = (int)(cby * 32767); nora[i2 * 2 + 1] = (int)(cby * 32767);
posa[i2 * 4 + 3] = (int)(cbz * 32767); posa[i2 * 4 + 3] = (int)(cbz * 32767);
nora[i3 * 2 ] = (int)(cbx * 32767); nora[i3 * 2] = (int)(cbx * 32767);
nora[i3 * 2 + 1] = (int)(cby * 32767); nora[i3 * 2 + 1] = (int)(cby * 32767);
posa[i3 * 4 + 3] = (int)(cbz * 32767); posa[i3 * 4 + 3] = (int)(cbz * 32767);
} }
@@ -185,29 +176,26 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa
if (texa32 != NULL) { if (texa32 != NULL) {
texa = malloc(sizeof(short) * vertex_count * 2); texa = malloc(sizeof(short) * vertex_count * 2);
for (int i = 0; i < vertex_count; ++i) { for (int i = 0; i < vertex_count; ++i) {
texa[i * 2 ] = texa32[i * 2 ] * 32767; texa[i * 2] = texa32[i * 2] * 32767;
texa[i * 2 + 1] = texa32[i * 2 + 1] * 32767; texa[i * 2 + 1] = texa32[i * 2 + 1] * 32767;
} }
} }
raw->posa = (i16_array_t *)malloc(sizeof(i16_array_t)); raw->posa = (i16_array_t *)malloc(sizeof(i16_array_t));
raw->posa->buffer = posa; raw->posa->buffer = posa;
raw->posa->length = raw->posa->capacity = vertex_count * 4; raw->posa->length = raw->posa->capacity = vertex_count * 4;
raw->nora = (i16_array_t *)malloc(sizeof(i16_array_t)); raw->nora = (i16_array_t *)malloc(sizeof(i16_array_t));
raw->nora->buffer = nora; raw->nora->buffer = nora;
raw->nora->length = raw->nora->capacity = vertex_count * 2; raw->nora->length = raw->nora->capacity = vertex_count * 2;
if (texa != NULL) { if (texa != NULL) {
raw->texa = (i16_array_t *)malloc(sizeof(i16_array_t)); raw->texa = (i16_array_t *)malloc(sizeof(i16_array_t));
raw->texa->buffer = texa; raw->texa->buffer = texa;
raw->texa->length = raw->texa->capacity = vertex_count * 2; raw->texa->length = raw->texa->capacity = vertex_count * 2;
} }
else {
raw->texa = NULL;
}
raw->inda = (u32_array_t *)malloc(sizeof(u32_array_t)); raw->inda = (u32_array_t *)malloc(sizeof(u32_array_t));
raw->inda->buffer = inda; raw->inda->buffer = inda;
raw->inda->length = raw->inda->capacity = index_count; raw->inda->length = raw->inda->capacity = index_count;
@@ -217,8 +205,8 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa
void *io_gltf_parse(char *buf, size_t size, const char *path) { void *io_gltf_parse(char *buf, size_t size, const char *path) {
cgltf_options options = {0}; cgltf_options options = {0};
cgltf_data *data = NULL; cgltf_data *data = NULL;
cgltf_result result = cgltf_parse(&options, buf, size, &data); cgltf_result result = cgltf_parse(&options, buf, size, &data);
if (result != cgltf_result_success) { if (result != cgltf_result_success) {
return NULL; return NULL;
} }
@@ -232,17 +220,14 @@ void *io_gltf_parse(char *buf, size_t size, const char *path) {
raw->name = malloc(strlen(n->name) + 1); raw->name = malloc(strlen(n->name) + 1);
strcpy(raw->name, n->name); strcpy(raw->name, n->name);
float m[16]; float m[16];
cgltf_node_transform_world(n, &m); cgltf_node_transform_world(n, m);
float scale[3]; float scale[3] = {1.0f, 1.0f, 1.0f};
scale[0] = 1;
scale[1] = 1;
scale[2] = 1;
if (n->has_scale) { if (n->has_scale) {
scale[0] = n->scale[0]; scale[0] = n->scale[0];
scale[1] = n->scale[1]; scale[1] = n->scale[1];
scale[2] = n->scale[2]; scale[2] = n->scale[2];
} }
io_gltf_parse_mesh(raw, n->mesh, &m, &scale); io_gltf_parse_mesh(raw, n->mesh, m, scale);
break; break;
} }
} }