polyadvent

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

dae.c (14338B)


      1 
      2 #include "xml.h"
      3 #include "util.h"
      4 #include "animation.h"
      5 #include "debug.h"
      6 #include "dae.h"
      7 
      8 enum dae_state {
      9     PARSING_START,
     10     PARSING_NODE,
     11     PARSING_FLOAT_ARRAY,
     12     PARSING_POSE,
     13     PARSING_JOINT,
     14     PARSING_JOINT_MATRIX,
     15     PARSING_WEIGHTS,
     16     PARSING_POSITIONS,
     17     PARSING_COLORS,
     18     PARSING_COLOR_INDEX,
     19     PARSING_TRIANGLES,
     20     PARSING_INDICES,
     21     PARSING_TEX_COORDS,
     22     PARSING_NORMALS,
     23 };
     24 
     25 enum semantic_type {
     26     SEM_VERTEX,
     27     SEM_NORMAL,
     28     SEM_COLOR,
     29     SEM_TEXCOORD,
     30     N_SEMTYPES
     31 };
     32 
     33 struct dae_data {
     34     int node_level;
     35     int state;
     36     FILE *dae_file;
     37     struct model *model;
     38     struct make_geometry *geom;
     39 
     40     u32 *indices;
     41     float *colors;
     42     float *normals;
     43 
     44     int n_indices;
     45     int prev_tris;
     46     int n_tris;
     47 
     48     enum semantic_type current_sem;
     49     int offsets[N_SEMTYPES];
     50     int semflags; // 1 << semantic_type
     51 
     52     int counter;
     53     char current_name[JOINT_LABEL_SIZE];
     54 };
     55 
     56 static int n_attrs(int semflags)
     57 {
     58     int count = 0;
     59     for (int i = 0; i < N_SEMTYPES; i++)
     60         count += (semflags & (1 << i)) == (1 << i);
     61     return count;
     62 }
     63 
     64 static void parse_joint(const char *t, int id, struct joint *joint)
     65 {
     66     struct node *node = get_node(&joint->node_id);
     67     assert(node);
     68 
     69     float *m = node->mat;
     70     joint->id = id;
     71     /* printf(" parsing joint %d: %s\n", id, t); */
     72 
     73     sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
     74            &m[0],  &m[1],  &m[2],  &m[3],
     75            &m[4],  &m[5],  &m[6],  &m[7],
     76            &m[8],  &m[9],  &m[10], &m[11],
     77            &m[12], &m[13], &m[14], &m[15]
     78            );
     79 }
     80 
     81 
     82 static void dae_tag_start(struct xmlparser *x, const char *t, size_t tl)
     83 {
     84     struct dae_data *data = (struct dae_data*)x->user_data;
     85 
     86     if (streq(t, "node")) {
     87         data->state = PARSING_NODE;
     88         data->node_level++;
     89     }
     90     else if (streq(t, "float_array")) {
     91         data->state = PARSING_FLOAT_ARRAY;
     92     }
     93     else if (streq(t, "triangles")) {
     94         data->state = PARSING_TRIANGLES;
     95     }
     96     else if (data->state == PARSING_TRIANGLES
     97              && streq(t, "p")) {
     98         data->state = PARSING_INDICES;
     99     }
    100     else if (data->state == PARSING_JOINT && streq(t, "matrix"))
    101         data->state = PARSING_JOINT_MATRIX;
    102     else
    103         return;
    104 }
    105 
    106 
    107 static void dae_tag_end(struct xmlparser *x, const char *t, size_t tl, int what)
    108 {
    109     struct dae_data *data = (struct dae_data*)x->user_data;
    110 
    111     if (streq(t, "node"))
    112         data->node_level--;
    113 
    114     if (data->state == PARSING_NODE) {
    115         data->state = PARSING_START;
    116     }
    117 }
    118 
    119 
    120 static void parse_array_with_offset(const char *d, int dl, u8 **elems,
    121                                     const char *fmt, int nelems,
    122                                     int elem_size, int elem_offset)
    123 {
    124     u8 buf[8];
    125     int i;
    126 
    127     assert(elem_size <= 8);
    128     assert(nelems > 0);
    129 
    130     *elems = realloc(*elems, nelems * elem_size);
    131 
    132     const char *p = d;
    133 
    134     for (i = elem_offset; i < nelems; i++) {
    135         sscanf(p, fmt, &buf);
    136         memcpy(*elems + i*elem_size, &buf, elem_size);
    137 
    138         assert(p-d < XML_BUFSIZ);
    139         assert (p < d+dl);
    140         while (p < d+dl) {
    141             if (*(p++) == ' ') {
    142                 break;
    143             }
    144         }
    145     }
    146 
    147     assert(nelems == i);
    148 }
    149 
    150 static void parse_array(const char *d, int dl, u8 **elems,
    151                         const char *fmt, int nelems, int elem_size)
    152 {
    153     assert(*elems == NULL);
    154     parse_array_with_offset(d, dl, elems, fmt, nelems, elem_size, 0);
    155 }
    156 
    157 static void parse_floats(const char *d, int dl, float **floats, int nfloats)
    158 {
    159     parse_array(d, dl, (u8**)floats, "%f", nfloats, sizeof(float));
    160 }
    161 
    162 static void parse_ints_with_offset(const char *d, int dl, u32 **ints,
    163                                    int nints, int offset)
    164 {
    165     parse_array_with_offset(d, dl, (u8**)ints, "%d", nints,
    166                             sizeof(u32), offset);
    167 }
    168 
    169 static void parse_ints(const char *d, int dl, u32 **ints, int nints)
    170 {
    171     parse_ints_with_offset(d, dl, ints, nints, 0);
    172 }
    173 
    174 
    175 static void parse_weights(struct dae_data *data, const char *d, int dl)
    176 {
    177     assert(data->counter != -1);
    178     float *weights = NULL;
    179     parse_floats(d, dl, &weights, data->counter);
    180     struct model *model = data->model;
    181     struct pose *pose = &model->poses[model->nposes];
    182     assert(pose);
    183     pose->nweights = data->counter;
    184     pose->weights = weights;
    185     data->state = PARSING_POSE;
    186     data->counter = -1;
    187 }
    188 
    189 static void parse_joint_matrix(struct dae_data *data, const char *d,
    190                                int dl)
    191 {
    192     assert(data->model->nposes);
    193 
    194     struct model *model = data->model;
    195     struct pose *pose = &model->poses[model->nposes - 1];
    196     assert(pose);
    197 
    198     struct joint *joint = &pose->joints[pose->njoints];
    199     assert(joint);
    200 
    201     struct node *node = new_node(&joint->node_id);
    202     assert(node);
    203     assert((int64_t)joint->node_id.id.uuid != -1);
    204     assert(&joint->node_id == &pose->joints[pose->njoints].node_id);
    205 
    206     parse_joint(d, pose->njoints, joint);
    207     node_set_label(node, data->current_name);
    208     joint->children_ids[0] = data->node_level;
    209     pose->njoints++;
    210     data->state = PARSING_POSE;
    211 }
    212 
    213 static void reset_parse_state(struct dae_data *data)
    214 {
    215     data->state = PARSING_POSE;
    216     data->counter = -1;
    217 }
    218 
    219 static void parse_vertices(struct dae_data *data, const char *d, int dl)
    220 {
    221     assert(data->counter != -1);
    222     parse_floats(d, dl, &data->geom->vertices, data->counter);
    223     data->geom->num_verts = data->counter / 3;
    224     reset_parse_state(data);
    225 }
    226 
    227 static void parse_normals(struct dae_data *data, const char *d, int dl)
    228 {
    229     assert(data->counter != -1);
    230     parse_floats(d, dl, &data->normals, data->counter);
    231     reset_parse_state(data);
    232 }
    233 
    234 static void parse_colors(struct dae_data *data, const char *d, int dl)
    235 {
    236     assert(data->counter != -1);
    237     parse_floats(d, dl, &data->colors, data->counter);
    238     reset_parse_state(data);
    239 }
    240 
    241 static void parse_indices(struct dae_data *data, const char *d, int dl)
    242 {
    243     assert(data->counter != -1);
    244     int nattrs = n_attrs(data->semflags);
    245     // debug("data->counters %d\n", data->counter);
    246     // debug("prev_tris %d n_tris %d counter %d nattrs %d\n",
    247     //       data->prev_tris,
    248     //       data->n_tris,
    249     //       data->counter,
    250     //       nattrs);
    251 
    252     parse_ints_with_offset(d, dl, &data->indices,
    253                            data->n_tris * 3 * nattrs,
    254                            data->prev_tris * 3 * nattrs );
    255     reset_parse_state(data);
    256 }
    257 
    258 static void dae_tagbody(struct xmlparser *x, const char *d, size_t dl)
    259 {
    260     static int count = 0;
    261     struct dae_data *data = (struct dae_data*)x->user_data;
    262 
    263     if (data->state == PARSING_JOINT_MATRIX) {
    264         parse_joint_matrix(data, d, dl);
    265     }
    266     else if (data->geom && data->state == PARSING_POSITIONS) {
    267         parse_vertices(data, d, dl);
    268     }
    269     else if (data->geom && data->state == PARSING_WEIGHTS) {
    270         parse_weights(data, d, dl);
    271     }
    272     else if (data->geom && data->state == PARSING_NORMALS) {
    273         parse_normals(data, d, dl);
    274     }
    275     else if (data->geom && data->state == PARSING_COLORS) {
    276         parse_colors(data, d, dl);
    277     }
    278     else if (data->geom && data->state == PARSING_INDICES) {
    279         parse_indices(data, d, dl);
    280     }
    281     /* else if (data->state == PARSING_TEX_COORDS) { */
    282     /*     parse_tex_coords(data, d, dl); */
    283     /* } */
    284 }
    285 
    286 static int dae_getc(struct xmlparser *x)
    287 {
    288     struct dae_data *data = (struct dae_data*)x->user_data;
    289     return fgetc(data->dae_file);
    290 }
    291 
    292 void dae_attr(struct xmlparser *x, const char *t, size_t tl,
    293               const char *a, size_t al, const char *v, size_t vl)
    294 {
    295     struct dae_data *data = (struct dae_data*)x->user_data;
    296 
    297     if (data->state == PARSING_NODE
    298         && streq(a, "id")
    299         && streq(v, "Armature")) {
    300 
    301         struct model *model = data->model;
    302         struct pose *pose = &model->poses[model->nposes++];
    303         data->state = PARSING_POSE;
    304         init_pose(pose);
    305     }
    306     else if (data->state == PARSING_FLOAT_ARRAY && streq(a, "id")) {
    307         if (contains(v, "skin-weights-array")) {
    308             data->state = PARSING_WEIGHTS;
    309         }
    310         else if (contains(v, "positions-array")) {
    311             data->state = PARSING_POSITIONS;
    312         }
    313         else if (contains(v, "normals-array")) {
    314             data->state = PARSING_NORMALS;
    315         }
    316         else if (contains(v, "mesh-colors")) {
    317             data->state = PARSING_COLORS;
    318         }
    319         else if (contains(v, "mesh-map")) {
    320             data->state = PARSING_TEX_COORDS;
    321         }
    322     }
    323     // this is just for sanity checking the order of things
    324     // if this ever asserts, we need to do proper offset parsing
    325     else if (data->state == PARSING_TRIANGLES && streq(a, "semantic")) {
    326         if (streq(v, "VERTEX"))
    327             data->current_sem = SEM_VERTEX;
    328         else if (streq(v, "NORMAL"))
    329             data->current_sem = SEM_NORMAL;
    330         else if (streq(v, "TEXCOORD"))
    331             data->current_sem = SEM_TEXCOORD;
    332         else if (streq(v, "COLOR"))
    333             data->current_sem = SEM_COLOR;
    334         else
    335             assert(!"unhandled triangle attribute index");
    336     }
    337     else if (data->state == PARSING_TRIANGLES
    338              && streq(a, "offset")) {
    339         int offset = atoi(v);
    340         assert((int)data->current_sem != -1);
    341 
    342         data->semflags |= 1 << data->current_sem;
    343         data->offsets[data->current_sem] = offset;
    344     }
    345     else if (streq(a, "count")) {
    346         data->counter = atoi(v);
    347         if (data->state == PARSING_TRIANGLES) {
    348             data->prev_tris = data->n_tris;
    349             data->n_tris += data->counter;
    350         }
    351     }
    352     else if (data->state == PARSING_NODE
    353              && streq(a, "name")) {
    354         strncpy(data->current_name, v, sizeof(data->current_name)-1);
    355     }
    356     else if (data->state == PARSING_NODE
    357              && streq(a, "type")
    358              && streq(v, "JOINT")) {
    359 
    360         data->state = PARSING_JOINT;
    361     }
    362 }
    363 
    364 static void process_joint_children(struct joint *joints, int njoints)
    365 {
    366     struct joint *joint, *j2;
    367     for (int i = 0; i < njoints; i++) {
    368         joint = &joints[i];
    369 
    370         // node level is stored in here on the first parser pass
    371         int level = joint->children_ids[0];
    372 
    373         for (int j = i+1; j < njoints; j++) {
    374             j2 = &joints[j];
    375             if (j2->children_ids[0] == level + 1) {
    376                 /* printf("%s(%d) assigning child %s(%d)\n", */
    377                 /*        joint->name, level, j2->name, j2->children[0]); */
    378 
    379                 assert(joint->n_children_ids+1 < MAX_JOINT_CHILDREN);
    380                 joint->children_ids[joint->n_children_ids++] = j;
    381             }
    382             else if (j2->children_ids[0] <= level)
    383                 break;
    384         }
    385     }
    386 }
    387 
    388 static void print_indices(struct dae_data *data)
    389 {
    390     int nattrs = n_attrs(data->semflags);
    391     for (int i = 0; i < data->n_tris * 3 * nattrs; i++) {
    392         printf("%d ", data->indices[i]);
    393     }
    394     printf("\n");
    395 }
    396 
    397 static void process_indices(struct dae_data *data)
    398 {
    399     int nattrs = n_attrs(data->semflags);
    400     int num_indices = data->n_tris * 3;
    401     bool has_color = data->semflags & (1 << SEM_COLOR);
    402 
    403     assert(num_indices);
    404 
    405     data->geom->num_indices = num_indices;
    406 
    407     if (has_color) {
    408         assert(data->offsets[SEM_COLOR] != -1);
    409         data->geom->colors = calloc(num_indices, sizeof(float) * 3);
    410     }
    411 
    412     assert(data->semflags & (1 << SEM_NORMAL));
    413     assert(data->semflags & (1 << SEM_VERTEX));
    414 
    415     data->geom->normals = calloc(num_indices, sizeof(float) * 3);
    416     data->geom->indices = calloc(num_indices, sizeof(int));
    417 
    418     // debug("offsets v:%d n:%d c:%d t:%d\n",
    419     //       data->offsets[SEM_VERTEX],
    420     //       data->offsets[SEM_NORMAL],
    421     //       data->offsets[SEM_COLOR],
    422     //       data->offsets[SEM_TEXCOORD]);
    423 
    424     // debug("data->n_indices %d num_indices %d nattrs %d\n",
    425     //       data->n_indices,
    426     //       num_indices,
    427     //       nattrs);
    428 
    429     /* print_indices(data); */
    430 
    431     assert(data->n_indices % nattrs == 0);
    432 
    433     for (int i = 0; i < num_indices; i++) {
    434         int v = i * nattrs;
    435 
    436         int cind = 0;
    437         int vind = data->indices[v + data->offsets[SEM_VERTEX]];
    438         int nind = data->indices[v + data->offsets[SEM_NORMAL]];
    439 
    440         assert(vind < data->geom->num_verts);
    441 
    442         if (has_color) {
    443             cind = data->indices[v + data->offsets[SEM_COLOR]];
    444         }
    445 
    446         assert(cind < 50000);
    447 
    448         data->geom->indices[i] = vind;
    449 
    450         // if (i == 0)
    451         //     printf("first vert %f %f %f\n",
    452         //         (&data->geom->vertices[vind*3])[0],
    453         //         (&data->geom->vertices[vind*3])[1],
    454         //         (&data->geom->vertices[vind*3])[2]);
    455         for (int j = 0; j < 3; j++) {
    456             int ind = (i*3)+j;
    457 
    458             if (has_color) {
    459                 data->geom->colors[ind]  = (&data->colors[cind*3])[j];
    460             }
    461 
    462             data->geom->normals[ind] = (&data->normals[nind*3])[j];
    463         }
    464     }
    465 
    466     assert(data->indices);
    467     if (data->indices)
    468         free(data->indices);
    469 
    470     assert(data->normals);
    471     if (data->normals)
    472         free(data->normals);
    473 
    474     assert(data->colors);
    475     if (data->colors)
    476         free(data->colors);
    477 }
    478 
    479 void load_dae(const char *filename, struct model *model,
    480               struct make_geometry *geom)
    481 {
    482     struct xmlparser x = {0};
    483     struct dae_data data = {
    484       .node_level   = 0,
    485       .state        = PARSING_START,
    486       .model        = model,
    487       .geom         = geom,
    488       .indices      = NULL,
    489       .colors       = NULL,
    490       .normals      = NULL,
    491       .n_indices    = 0,
    492       .n_tris       = 0,
    493       .prev_tris    = 0,
    494       .semflags     = 0,
    495       .current_sem  = -1,
    496       .counter      = -1
    497     };
    498 
    499     for (int i = 0; i < N_SEMTYPES; i++)
    500         data.offsets[i] = -1;
    501 
    502     data.dae_file = fopen(filename, "rb");
    503     if (data.dae_file == NULL)
    504         exit(1);
    505 
    506     x.user_data = &data;
    507     x.xmltagstart = dae_tag_start;
    508     x.xmltagend   = dae_tag_end;
    509     x.xmlattr     = dae_attr;
    510     x.xmldata     = dae_tagbody;
    511     /* x.xmlattrend  = dae_attr_end; */
    512     x.getnext     = dae_getc;
    513 
    514     xml_parse(&x);
    515 
    516     for (int i = 0; i < model->nposes; i++) {
    517         struct pose *pose = &model->poses[i];
    518         process_joint_children(pose->joints, pose->njoints);
    519     }
    520 
    521     if (geom)
    522         process_indices(&data);
    523 
    524     fclose(data.dae_file);
    525 }