/* * Copyright (C) 2018 Tomasz Kramkowski * SPDX-License-Identifier: MIT */ #include #include #include #include "eprintf.h" #include "fmd.h" #include "ieee754.h" #include "nelem.h" static const char *MAGIC = "FMD002\r\n"; // checkmagic: check the fmd magic number static void checkmagic(FILE *f) { for (size_t i = 0; i < strlen(MAGIC); i++) assert(fgetc(f) == MAGIC[i]); } // betoul: read big endian 32 bit unsigned integer static inline unsigned long betoul(FILE *src) { unsigned long ret = 0; assert(src != NULL); for (int i = 0; i < 4; i++) { int c = fgetc(src); assert(c != EOF); ret += (unsigned long)(c & 0xff) << (3 - i) * 8; } return ret; } // readfloats: read ieee754 32 bit floating point numbers void readfloats(float *dest, int count, FILE *src) { assert(dest != NULL); assert(src != NULL); for (int i = 0; i < count; i++) dest[i] = ieee754f(betoul(src)); } // fmd_load: read a FMD file void fmd_load(struct fmd *fmd, FILE *f) { assert(fmd != NULL); assert(f != NULL); checkmagic(f); fmd->nverts = betoul(f); if (fmd->nverts > 0) fmd->verts = emalloc(fmd->nverts * sizeof *fmd->verts); else fmd->verts = NULL; for (int i = 0; i < fmd->nverts; i++) { struct vertex *v = &fmd->verts[i]; readfloats(v->pos, 3, f); readfloats(v->norm, 3, f); readfloats(v->uv, 2, f); } fmd->ntris = betoul(f); if (fmd->ntris > 0) fmd->tris = emalloc(fmd->ntris * sizeof *fmd->tris); else fmd->tris = NULL; for (int i = 0; i < fmd->ntris; i++) for (size_t j = 0; j < NELEM(fmd->tris[j]); j++) fmd->tris[i][j] = betoul(f); fmd->nmtls = betoul(f); if (fmd->nmtls > 0) fmd->mtls = emalloc(fmd->nmtls * sizeof *fmd->mtls); else fmd->mtls = NULL; for (int i = 0; i < fmd->nmtls; i++) { unsigned long len = betoul(f); char **m = &fmd->mtls[i]; size_t ret; *m = emalloc(len + 1); ret = fread(*m, len, 1, f); assert(ret == 1); (*m)[len] = '\0'; } fmd->nmeshes = betoul(f); if (fmd->nmeshes > 0) fmd->meshes = emalloc(fmd->nmeshes * sizeof *fmd->meshes); else fmd->meshes = NULL; for (int i = 0; i < fmd->nmeshes; i++) { struct fmd_mesh *m = &fmd->meshes[i]; unsigned long midx; midx = betoul(f); m->midx = midx == 0xffffffff ? -1 : (int)midx; m->tidx = betoul(f); m->tcnt = betoul(f); } } // fmd_free: free a previously loaded FMD file void fmd_free(struct fmd *fmd) { assert(fmd); free(fmd->verts); free(fmd->tris); for (int i = 0; i < fmd->nmtls; i++) free(fmd->mtls[i]); free(fmd->mtls); free(fmd->meshes); }