From 86d5a546b4eab47b991a0acc4ab444c725feb081 Mon Sep 17 00:00:00 2001 From: quou Date: Sun, 25 Aug 2024 15:38:49 +1000 Subject: GLTF meshes --- convmesh.c | 398 ++++++++++++++++++++++++++++--------------------------------- 1 file changed, 180 insertions(+), 218 deletions(-) (limited to 'convmesh.c') diff --git a/convmesh.c b/convmesh.c index e559824..1c6545d 100644 --- a/convmesh.c +++ b/convmesh.c @@ -1,229 +1,218 @@ #include #include -#include -/* px py pz nx ny nz u v */ -#define elpv 8 - -#define safe_malloc(p, s) \ - p = malloc(s); \ - if (!p) { \ - fprintf( \ - stderr, \ - "Out of memory.\n" \ - ); \ - return 3; \ - } +#define CGLTF_IMPLEMENTATION +#include "cgltf.h" typedef struct { unsigned short p, n, t; -} Vert; +} Vertex; -typedef struct { +struct { int vc, pc, nc, tc; + int* p, * n, * t; + Vertex* verts; +} result = { 0 }; + +struct { + unsigned short* ind; float* p, * n, * t; - Vert* verts; -} Model; + int ic, pc, nc, tc; +} intern = { 0 }; -int line_len(const char* line) { - const char* c; - int r = 0; - for (c = line; *c && *c != '\n'; c++, r++); - return r; +void parse_attrib( + float** d, + int* c, + int ec, + const cgltf_accessor* a +) { + int count, es = ec * 4; + const cgltf_buffer_view* v = a->buffer_view; + if (a->component_type != cgltf_component_type_r_32f) { + fprintf(stderr, "Only float attributes are supported.\n"); + exit(33); + } + if (ec * 4 != a->stride) { + fprintf(stderr, "Attribute stride doesn't match component count.\n"); + exit(34); + } + count = *c + a->count; + *d = realloc(*d, count * es); + memcpy( + &(*d)[*c], + &((char*)v->buffer->data)[v->offset], + a->count * es + ); + *c = count; } -const char* next_line(const char* line) { - const char* c; - for (c = line; *c != '\n'; c++) { - if (!*c) return 0; +void parse_prim_attribs(const cgltf_primitive* p) { + int i; + unsigned m = 0; + for (i = 0; i < p->attributes_count; i++) { + const cgltf_attribute* a = &p->attributes[i]; + switch (a->type) { + case cgltf_attribute_type_position: + parse_attrib(&intern.p, &intern.pc, 3, a->data); + m |= 0x1; + break; + case cgltf_attribute_type_normal: + parse_attrib(&intern.n, &intern.nc, 3, a->data); + m |= 0x2; + break; + case cgltf_attribute_type_texcoord: + parse_attrib(&intern.t, &intern.tc, 2, a->data); + m |= 0x4; + break; + default: break; + } + } + if (m != 0x7) { + fprintf(stderr, "Not all attributes were provided.\n"); + exit(32); } - return c + 1; } -int read_model(Model* m, const char* src) { - const char* line; - int pc = 0, nc = 0, tc = 0, vc = 0; - for (line = src; line; line = next_line(line)) { - if (line_len(line) < 6) continue; - if (!memcmp("vn", line, 2)) - nc++; - else if (!memcmp("vt", line, 2)) - tc++; - else if (!memcmp("v", line, 1)) - pc++; - else if (!memcmp("f", line, 1)) - vc++; +void parse_prim(const cgltf_primitive* p) { + int i, c, s; + const cgltf_accessor* a; + const cgltf_buffer_view* v; + if (p->type != cgltf_primitive_type_triangles) { + fprintf(stderr, "Only triangle meshes are supported.\n"); + exit(30); } - safe_malloc(m->p, pc * 3 * sizeof *m->p); - safe_malloc(m->n, nc * 3 * sizeof *m->n); - safe_malloc(m->t, tc * 2 * sizeof *m->t); - safe_malloc(m->verts, vc * 3 * sizeof *m->verts); - pc = - nc = - tc = 0; - m->vc = 0; - for (line = src; line; line = next_line(line)) { - int idx; - char* end; - if (!memcmp("vn", line, 2)) { - idx = nc++; - m->n[idx * 3 + 0] = (float)strtod(line + 3, &end); - m->n[idx * 3 + 1] = (float)strtod(end, &end); - m->n[idx * 3 + 2] = (float)strtod(end, &end); - } else if (!memcmp("vt", line, 2)) { - idx = tc++; - m->t[idx * 2 + 0] = (float)strtod(line + 3, &end); - m->t[idx * 2 + 1] = (float)strtod(end, &end); - } else if (!memcmp("v", line, 1)) { - idx = pc++; - m->p[idx * 3 + 0] = (float)strtod(line + 2, &end); - m->p[idx * 3 + 1] = (float)strtod(end, &end); - m->p[idx * 3 + 2] = (float)strtod(end, &end); - } else if (!memcmp("f", line, 1)) { - idx = m->vc++; - m->verts[idx].p = (int)strtol(line + 1, &end, 10) - 1; - m->verts[idx].t = (int)strtol(end + 1, &end, 10) - 1; - m->verts[idx].n = (int)strtol(end + 1, &end, 10) - 1; - idx = m->vc++; - m->verts[idx].p = (int)strtol(end + 1, &end, 10) - 1; - m->verts[idx].t = (int)strtol(end + 1, &end, 10) - 1; - m->verts[idx].n = (int)strtol(end + 1, &end, 10) - 1; - idx = m->vc++; - m->verts[idx].p = (int)strtol(end + 1, &end, 10) - 1; - m->verts[idx].t = (int)strtol(end + 1, &end, 10) - 1; - m->verts[idx].n = (int)strtol(end + 1, &end, 10) - 1; - } + a = p->indices; + if (!a) { + fprintf(stderr, "Meshes must be indexed.\n"); + exit(35); } - m->pc = pc; - m->nc = nc; - m->tc = tc; - return 0; -} -/* -int expand_model(Model* m, float** overt, int* ovc) { - int i, c, o; - float* v; - c = m->vc; - safe_malloc(v, c * elpv * sizeof *v); - for (i = o = 0; i < m->vc; i++, o += elpv) { - v[o + 0] = m->p[m->verts[i].p * 3 + 0]; - v[o + 1] = m->p[m->verts[i].p * 3 + 1]; - v[o + 2] = m->p[m->verts[i].p * 3 + 2]; - v[o + 3] = m->n[m->verts[i].n * 3 + 0]; - v[o + 4] = m->n[m->verts[i].n * 3 + 1]; - v[o + 5] = m->n[m->verts[i].n * 3 + 2]; - v[o + 6] = m->t[m->verts[i].t * 2 + 0]; - v[o + 7] = m->t[m->verts[i].t * 2 + 1]; + if (a->stride != 2) { + fprintf(stderr, "Only two byte indices are supported.\n"); + exit(31); } - *overt = v; - *ovc = c; - return 0; + v = a->buffer_view; + c = intern.ic + a->count; + intern.ind = realloc(intern.ind, c * sizeof *intern.ind); + memcpy( + &intern.ind[intern.ic], + &((char*)v->buffer->data)[v->offset], + a->count * sizeof *intern.ind + ); + intern.ic = c; + parse_prim_attribs(p); +} + +void parse_mesh(const cgltf_mesh* m) { + int i; + for (i = 0; i < m->primitives_count; i++) + parse_prim(&m->primitives[i]); } -void vert_cpy(float* dst, const float* src) { +int parse(const char* name) { int i; - for (i = 0; i < elpv; i++) - dst[i] = src[i]; + cgltf_options opt = { 0 }; + cgltf_data* d; + cgltf_result r; + r = cgltf_parse_file(&opt, name, &d); + if (r) return r; + r = cgltf_load_buffers(&opt, d, name); + if (r) return r; + for (i = 0; i < d->meshes_count; i++) + parse_mesh(&d->meshes[i]); + cgltf_free(d); + return 0; +} + +int to_fixed(float v) { + return (int)(v * 512.0f); } -int verts_eq(const float* a, const float* b) { +int attrib_eq(float* a, int* b, int ec) { int i; -#define absf(v) \ - ((v) < 0.0f? -(v): (v)) - for (i = 0; i < elpv; i++) - if (absf(a[i] - b[i]) > 0.0001f) + for (i = 0; i < ec; i++) { + int fpv = to_fixed(a[i]); + if (fpv != b[i]) return 0; + } return 1; -#undef absf } -int index_model( - float* vert, - int vc, - float** overt, - unsigned short** oind, - int* ovc, - int* oic +void convert_attrib( + float* s, + int ec, + unsigned short* di, + int* dc, + int* d ) { - float* ivert; - unsigned short* ind; - int i, ic, ivc; - safe_malloc(ivert, vc * elpv * sizeof *ivert); - safe_malloc(ind, vc * sizeof *ind); - for (i = ic = ivc = 0; i < vc; i++) { - int j, idx; - for (j = 0; j < ivc; j++) { - if (verts_eq(&vert[i * elpv], &ivert[j * elpv])) { - ind[ic++] = (unsigned short)j; - goto cont; - } + int i, idx, c = *dc; + for (i = 0; i < c; i++) { + int ei = i * ec; + if (attrib_eq(s, &d[ei], ec)) { + *di = i; + return; } - idx = ivc++; - vert_cpy(&ivert[idx * elpv], &vert[i * elpv]); - ind[ic++] = (unsigned short)idx; - cont: continue; } - *overt = ivert; - *oind = ind; - *ovc = ivc; - *oic = ic; - return 0; + idx = c++; + *dc = c; + *di = (unsigned short)idx; + for (i = 0; i < ec; i++) { + int iidx = i + idx * ec; + d[iidx] = to_fixed(s[i]); + } } -int write_model( - float* vert, - unsigned short* ind, - int vc, - int ic, - FILE* f -) { - int i, c; -#define write(b, s)\ - if (fwrite(b, 1, s, f) != s) return 42; - write(&vc, 4); - write(&ic, 4); - c = vc * elpv; - for (i = 0; i < c; i++) { - int fv = (int)(vert[i] * 512.0f); - write(&fv, 4); - } - write(ind, ic * sizeof *ind); - return 0; -}*/ +void convert_vert(int i) { + Vertex* d = &result.verts[result.vc++]; + int idx = intern.ind[i]; + convert_attrib( + &intern.p[idx * 3], + 3, + &d->p, + &result.pc, + result.p + ); + convert_attrib( + &intern.n[idx * 3], + 3, + &d->n, + &result.nc, + result.n + ); + convert_attrib( + &intern.t[idx * 2], + 2, + &d->t, + &result.tc, + result.t + ); +} -int write_model( - Model* m, - FILE* f -) { - int i, c, pad[8] = { 0 }; -#define write(b, s)\ - if (fwrite(b, 1, s, f) != s) return 42; - write(&m->vc, 4); - write(&m->pc, 4); - write(&m->nc, 4); - write(&m->tc, 4); - write(pad, 32); - for (i = 0, c = m->pc * 3; i < c; i++) { - int fv = (int)(m->p[i] * 512.0f); - write(&fv, 4); - } - for (i = 0, c = m->nc * 3; i < c; i++) { - int fv = (int)(m->n[i] * 512.0f); - write(&fv, 4); +void convert(void) { + int i; + result.p = malloc(intern.pc * sizeof *result.p * 3); + result.n = malloc(intern.nc * sizeof *result.n * 3); + result.t = malloc(intern.tc * sizeof *result.t * 2); + result.verts = malloc(intern.ic * sizeof *result.verts); + for (i = 0; i < intern.ic; i++) { + convert_vert(i); } - for (i = 0, c = m->tc * 2; i < c; i++) { - int fv = (int)(m->t[i] * 512.0f); - write(&fv, 4); +} + +void dump(const char* name) { + FILE* outfile = fopen(name, "wb"); + if (!outfile) { + fprintf(stderr, "Failed to open %s\n", name); + exit(35); } - write(m->verts, m->vc * sizeof *m->verts); - return 0; + fwrite(&result, 1, sizeof result, outfile); + fwrite(result.p, result.pc, sizeof* result.p * 3, outfile); + fwrite(result.n, result.nc, sizeof* result.n * 3, outfile); + fwrite(result.t, result.tc, sizeof* result.t * 2, outfile); + fwrite(result.verts, result.vc, sizeof* result.verts, outfile); } int main(int argc, const char** argv) { - FILE* infile, * outfile; - char* src; - Model m; - int s, r; + int r; if (argc < 3) { fprintf( stderr, @@ -232,36 +221,9 @@ int main(int argc, const char** argv) { ); return 1; } - infile = fopen(argv[1], "r"); - if (!infile) { - fprintf( - stderr, - "Can't open %s.\n", - argv[1] - ); - return 2; - } - fseek(infile, 0, SEEK_END); - s = ftell(infile); - rewind(infile); - safe_malloc(src, s + 1); - s = fread(src, 1, s, infile); - src[s] = 0; - if ((r = read_model(&m, src))) - return r; - free(src); - outfile = fopen(argv[2], "wb"); - if (!outfile) { - fprintf( - stderr, - "Can't open %s.\n", - argv[2] - ); - return 2; - } - if ((r = write_model(&m, outfile))) - return r; - fclose(infile); - fclose(outfile); + r = parse(argv[1]); + if (r) return r; + convert(); + dump(argv[2]); return 0; } -- cgit v1.2.3-54-g00ecf