summaryrefslogtreecommitdiff
path: root/convmesh.c
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2024-08-25 15:38:49 +1000
committerquou <quou@disroot.org>2024-08-25 15:46:21 +1000
commit86d5a546b4eab47b991a0acc4ab444c725feb081 (patch)
tree1a8dae50d6df5f0c008dbe5e024b4496d777c661 /convmesh.c
parent2992af6bbd4e8961e6cb8c15af01d2894d2b1b81 (diff)
GLTF meshes
Diffstat (limited to 'convmesh.c')
-rw-r--r--convmesh.c398
1 files changed, 180 insertions, 218 deletions
diff --git a/convmesh.c b/convmesh.c
index e559824..1c6545d 100644
--- a/convmesh.c
+++ b/convmesh.c
@@ -1,229 +1,218 @@
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-/* 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;
}