polyadvent

A game engine from scratch in C
git clone git://jb55.com/polyadvent
Log | Files | Refs | README

mdl.c (7086B)


      1 
      2 #include "mdl.h"
      3 #include "debug.h"
      4 #include "vec3.h"
      5 #include <assert.h>
      6 
      7 
      8 static inline void write_tag(enum mdl_tag tag, FILE *out)
      9 {
     10     fwrite(&tag, 1, 1, out);
     11 }
     12 
     13 // little endian is assumed...
     14 static inline void write_int(int val, FILE *out)
     15 {
     16     assert(val != 0);
     17     fwrite(&val, sizeof(val), 1, out);
     18 }
     19 
     20 static inline void write_nfloats(float *floats, int num_floats, FILE *out)
     21 {
     22     fwrite(floats, sizeof(*floats), num_floats, out);
     23 }
     24 
     25 static inline void write_floats(float *floats, int num_floats, FILE *out)
     26 {
     27     write_int(num_floats, out);
     28     write_nfloats(floats, num_floats, out);
     29 }
     30 
     31 static inline void write_ints(u32 *ints, int num_ints, FILE *out)
     32 {
     33     write_int(num_ints, out);
     34     fwrite(ints, sizeof(*ints), num_ints, out);
     35 }
     36 
     37 void init_mdl_geometry(struct mdl_geometry *lgeom)
     38 {
     39     init_make_geometry(&lgeom->mkgeom);
     40     vec3_set(V3(0,0,0), lgeom->min);
     41     vec3_set(V3(0,0,0), lgeom->max);
     42 }
     43 
     44 void save_mdl_fd(FILE *out, struct model *model, struct mdl_geometry *lgeom)
     45 {
     46     struct make_geometry *mkgeom = &lgeom->mkgeom;
     47     assert(mkgeom->vertices);
     48     assert(mkgeom->normals);
     49     assert(mkgeom->indices);
     50 
     51     for (int i = 0; i < N_MDL_TAGS; i++) {
     52         switch ((enum mdl_tag)i) {
     53         case MDL_POSITION:
     54             write_tag(MDL_POSITION, out);
     55             write_floats(mkgeom->vertices, mkgeom->num_verts * 3, out);
     56             break;
     57 
     58         case MDL_NORMAL:
     59             write_tag(MDL_NORMAL, out);
     60             write_floats(mkgeom->normals, mkgeom->num_verts * 3, out);
     61             break;
     62 
     63         case MDL_COLOR:
     64             if (mkgeom->colors) {
     65                 write_tag(MDL_COLOR, out);
     66                 write_floats(mkgeom->colors, mkgeom->num_verts * 3, out);
     67             }
     68             break;
     69 
     70         case MDL_INDEX:
     71             write_tag(MDL_INDEX, out);
     72             write_ints(mkgeom->indices, mkgeom->num_indices , out);
     73             /* debug("writing out %d indices\n", mkgeom->num_indices); */
     74             break;
     75 
     76         case MDL_JOINT_IDS:
     77             if (mkgeom->joint_ids) {
     78                 write_tag(MDL_JOINT_IDS, out);
     79                 write_ints(mkgeom->joint_ids, mkgeom->num_joint_ids, out);
     80             }
     81             break;
     82 
     83         case MDL_JOINT_WEIGHTS:
     84             if (mkgeom->joint_weights) {
     85                 write_tag(MDL_JOINT_WEIGHTS, out);
     86                 write_floats(mkgeom->joint_weights,
     87                              mkgeom->num_verts * 3, out);
     88             }
     89             break;
     90 
     91         case MDL_TEX_COORD:
     92             if (mkgeom->tex_coords) {
     93                 write_tag(MDL_TEX_COORD, out);
     94                 assert(mkgeom->num_uv_components == 2);
     95                 write_floats(mkgeom->tex_coords,
     96                              mkgeom->num_verts * mkgeom->num_uv_components,
     97                              out);
     98             }
     99             break;
    100 
    101         case MDL_MAX:
    102             write_tag(MDL_MAX, out);
    103             write_nfloats(lgeom->max, 3, out);
    104             /* debug("write max: %f %f %f\n", */
    105             /*       lgeom->max[0], lgeom->max[1], lgeom->max[2]); */
    106             break;
    107 
    108         case MDL_MIN:
    109             write_tag(MDL_MIN, out);
    110             write_nfloats(lgeom->min, 3, out);
    111 
    112             /* debug("write min: %f %f %f\n", */
    113             /*       lgeom->min[0], lgeom->min[1], lgeom->min[2]); */
    114             break;
    115 
    116         case N_MDL_TAGS:
    117             assert(!"this shouldn't happend"); break;
    118         }
    119     }
    120 
    121 }
    122 
    123 static inline enum mdl_tag read_tag(FILE *stream)
    124 {
    125     enum mdl_tag tag = 0;
    126     int read = fread(&tag, 1, 1, stream);
    127     /* debug("read_tag %d\n", tag); */
    128     assert(read == 1 || feof(stream));
    129     assert(tag != 0 || feof(stream));
    130     return tag;
    131 }
    132 
    133 static inline int read_int(FILE *stream)
    134 {
    135     int val = 0;
    136     int read = fread(&val, sizeof(val), 1, stream);
    137     /* debug("val %d ftell %zu\n", val, ftell(stream)-4); */
    138     assert(read == 1);
    139     assert(val != 0);
    140     return val;
    141 }
    142 
    143 #define MAX_MDL_ARRAY 128000 // only enforced at dev time for sanity
    144 
    145 static inline int read_nfloats(FILE *stream, int n, float *floats)
    146 {
    147     return fread(floats, sizeof(float), n, stream);
    148 }
    149 
    150 static int read_floats(FILE *stream, float **floats)
    151 {
    152     int nfloats = read_int(stream);
    153     assert(nfloats != 0);
    154     assert(nfloats < MAX_MDL_ARRAY); // it's a low poly game...
    155     *floats = malloc(nfloats*sizeof(float));
    156     int nread = read_nfloats(stream, nfloats, *floats);
    157     assert(nread == nfloats);
    158     return nread;
    159 }
    160 
    161 static int read_ints(FILE *stream, u32 **ints)
    162 {
    163     int nints = read_int(stream);
    164     assert(nints != 0);
    165     assert(nints < MAX_MDL_ARRAY); // it's a low poly game...
    166     *ints = malloc(nints*sizeof(u32));
    167     int nread = fread(*ints, sizeof(u32), nints, stream);
    168     assert(nread == nints);
    169     return nread;
    170 }
    171 
    172 void load_mdl_fd(FILE *in, struct model *model, struct mdl_geometry *lgeom)
    173 {
    174     struct make_geometry *mkgeom = &lgeom->mkgeom;
    175     int num;
    176     (void)num;
    177 
    178     while (1) {
    179         enum mdl_tag tag = read_tag(in);
    180         if (feof(in))
    181             break;
    182         assert(tag < N_MDL_TAGS);
    183 
    184         switch (tag) {
    185         case MDL_POSITION:
    186             mkgeom->num_verts = read_floats(in, &mkgeom->vertices) / 3;
    187             break;
    188 
    189         case MDL_NORMAL:
    190             num = read_floats(in, &mkgeom->normals);
    191             assert(num == mkgeom->num_verts * 3);
    192             break;
    193 
    194         case MDL_COLOR:
    195             num = read_floats(in, &mkgeom->colors);
    196             assert(num == mkgeom->num_verts * 3);
    197             break;
    198 
    199         case MDL_INDEX:
    200             mkgeom->num_indices = read_ints(in, &mkgeom->indices);
    201             /* debug("reading in %d indices\n", mkgeom->num_indices); */
    202             break;
    203 
    204         case MDL_TEX_COORD:
    205             num = read_floats(in, &mkgeom->tex_coords);
    206             assert(num == mkgeom->num_verts * 2);
    207             break;
    208 
    209         case MDL_JOINT_IDS:
    210             mkgeom->num_joint_ids = read_ints(in, &mkgeom->joint_ids);
    211             break;
    212 
    213         case MDL_JOINT_WEIGHTS:
    214             // TODO: multiple poses
    215             debug("loading joint weights\n");
    216             model->nposes = 1;
    217             num = read_floats(in, &mkgeom->joint_weights);
    218             assert(num == mkgeom->num_verts * 3);
    219             break;
    220 
    221         case MDL_MIN:
    222             read_nfloats(in, 3, lgeom->min);
    223             /* debug("read min: %f %f %f\n", */
    224             /*       lgeom->min[0], lgeom->min[1], lgeom->min[2]); */
    225             break;
    226 
    227         case MDL_MAX:
    228             read_nfloats(in, 3, lgeom->max);
    229             /* debug("read max: %f %f %f\n", */
    230             /*       lgeom->max[0], lgeom->max[1], lgeom->max[2]); */
    231             break;
    232 
    233         case N_MDL_TAGS: assert(!"this shouldn't happend"); break;
    234         }
    235     }
    236 }
    237 
    238 void save_mdl(const char *filename, struct model *model, struct mdl_geometry *lgeom)
    239 {
    240     FILE *out = fopen(filename, "wb");
    241     assert(out);
    242     save_mdl_fd(out, model, lgeom);
    243     fclose(out);
    244 }
    245 
    246 void load_mdl(const char *file, struct model *model, struct mdl_geometry *lgeom)
    247 {
    248     FILE *in = fopen(file, "rb");
    249     assert(in);
    250     load_mdl_fd(in, model, lgeom);
    251     fclose(in);
    252 }