polyadvent

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

ply.c (6140B)


      1 
      2 #include <assert.h>
      3 #include <stdio.h>
      4 #include <string.h>
      5 #include <stdlib.h>
      6 #include "file.h"
      7 #include "mdl.h"
      8 #include "common.h"
      9 #include "ply.h"
     10 #include "vec3.h"
     11 
     12 /* void parse_vertex( */
     13 
     14 
     15 enum ply_state {
     16     PLY_MAGIC,
     17     PLY_HEADER,
     18     PLY_VERTICES,
     19     PLY_INDICES
     20 };
     21 
     22 static void next_line(const char **cursor) {
     23     while (*((*cursor)++) != '\n')
     24         ;
     25 }
     26 
     27 static int consume_string(const char **cursor, const char *str) {
     28     int len = strlen(str);
     29 
     30     if (memcmp(*cursor, str, len) == 0)
     31         *cursor += len;
     32     else
     33         return 0;
     34 
     35     return 1;
     36 }
     37 
     38 static int parse_element(const char **cursor, const char *element, int *nverts) {
     39     int ok;
     40     static char buffer[32];
     41 
     42     snprintf(buffer, sizeof(buffer), "element %s ", element);
     43 
     44     ok = consume_string(cursor, buffer);
     45 
     46     if (!ok)
     47         return 0;
     48 
     49     *nverts = atoi(*cursor);
     50 
     51     return *nverts != 0;
     52 }
     53 
     54 
     55 static inline int parse_vertex(const char **cursor, float *v, float *n, u8 *c) {
     56     static float st[2];
     57 
     58     int matched =
     59         sscanf(*cursor, "%f %f %f %f %f %f %f %f %hhu %hhu %hhu",
     60             &v[0], &v[1], &v[2],
     61             &n[0], &n[1], &n[2],
     62             &st[0], &st[1],
     63             &c[0], &c[1], &c[2]);
     64 
     65     if (matched == 11)
     66         return 1;
     67 
     68     matched =
     69         sscanf(*cursor, "%f %f %f %f %f %f %hhu %hhu %hhu",
     70                &v[0], &v[1], &v[2],
     71                &n[0], &n[1], &n[2],
     72                &c[0], &c[1], &c[2]);
     73 
     74     if (matched == 9)
     75         return 1;
     76 
     77     return 0;
     78 }
     79 
     80 
     81 static int parse_indices(const char **cursor, int *inds) {
     82     // NOTE: only support tris inds for now
     83     int matched =
     84         sscanf(*cursor, "3 %d %d %d", &inds[0], &inds[1], &inds[2]);
     85 
     86     return matched == 3;
     87 }
     88 
     89 static int parse_header(const char **cursor, int *nverts, int *ninds) {
     90     int ok = 0;
     91     ok = parse_element(cursor, "vertex", nverts);
     92     if (ok) return 1;
     93 
     94     ok = parse_element(cursor, "face", ninds);
     95     if (ok) return 1;
     96 
     97     return 0;
     98 }
     99 
    100 static int parse_magic(const char **cursor) {
    101     return consume_string(cursor, "ply");
    102 }
    103 
    104 
    105 /*
    106 int parse_ply(const char *filename, struct geometry *geom)
    107 {
    108     struct mdl_geometry mdlgeom;
    109     init_mdl_geometry(&mdlgeom);
    110     struct make_geometry *mkgeom = &mdlgeom.mkgeom;
    111 
    112     int ok = parse_ply_with_mkgeom(filename, &mdlgeom);
    113 
    114     make_buffer_geometry(mkgeom, geom);
    115     free_make_geometry(mkgeom);
    116 
    117     return ok;
    118 }
    119 */
    120 
    121 int parse_ply_with_mkgeom(const char *filename, struct mdl_geometry *mdlgeom)
    122 {
    123     size_t len;
    124     int success = 0;
    125     int nverts = 0;
    126     int ninds = 0;
    127     int done = 0;
    128     int res = 0;
    129     int cvert = 0;
    130     int cind = 0;
    131 
    132     struct make_geometry *mkgeom = &mdlgeom->mkgeom;
    133     enum ply_state state = PLY_MAGIC;
    134     const char *data = (const char*)file_contents(filename, &len);
    135     const char *p = data;
    136 
    137     float vert[3], norm[3], min[3]={0}, max[3]={0};
    138     int inds[3];
    139     u8 color[3];
    140 
    141     while(!done) {
    142         switch (state) {
    143         case PLY_MAGIC:
    144             res = parse_magic(&p);
    145             if (!res) {
    146                 printf("failed to parse ply magic header\n");
    147                 done = 1;
    148                 break;
    149             }
    150             state = PLY_HEADER;
    151             break;
    152         case PLY_HEADER:
    153             res = parse_header(&p, &nverts, &ninds);
    154             if (consume_string(&p, "end_header")) {
    155                 if (ninds == 0 || nverts == 0)  {
    156                     printf("ply parsing failed, could not determine number "
    157                            " of vertices or faces\n");
    158                     done = 1;
    159                     break;
    160                 }
    161 
    162                 mkgeom->vertices = calloc(nverts * 3, sizeof(*mkgeom->vertices));
    163                 mkgeom->normals  = calloc(nverts * 3, sizeof(*mkgeom->normals));
    164                 mkgeom->colors   = calloc(nverts * 3, sizeof(*mkgeom->colors));
    165                 mkgeom->indices  = calloc(ninds * 3, sizeof(*mkgeom->indices));
    166 
    167                 state = PLY_VERTICES;
    168             }
    169             break;
    170         case PLY_VERTICES:
    171             res = parse_vertex(&p, vert, norm, color);
    172             if (!res) {
    173                 printf("failed parsing verts\n");
    174                 done = 1;
    175                 break;
    176             }
    177 
    178             // compute bounding box as we go
    179             if (cvert == 0) {
    180                 vec3_copy(vert, min);
    181                 vec3_copy(vert, max);
    182             }
    183             else {
    184                 vec3_min(vert, min, min);
    185                 vec3_max(vert, max, max);
    186             }
    187 
    188             mkgeom->vertices[cvert * 3]     = vert[0];
    189             mkgeom->vertices[cvert * 3 + 1] = vert[1];
    190             mkgeom->vertices[cvert * 3 + 2] = vert[2];
    191 
    192             mkgeom->normals[cvert * 3]     = norm[0];
    193             mkgeom->normals[cvert * 3 + 1] = norm[1];
    194             mkgeom->normals[cvert * 3 + 2] = norm[2];
    195 
    196             mkgeom->colors[cvert * 3]     = color[0] / 255.0;
    197             mkgeom->colors[cvert * 3 + 1] = color[1] / 255.0;
    198             mkgeom->colors[cvert * 3 + 2] = color[2] / 255.0;
    199 
    200             cvert++;
    201 
    202             if (cvert == nverts)
    203                 state = PLY_INDICES;
    204 
    205             break;
    206         case PLY_INDICES:
    207             res = parse_indices(&p, inds);
    208             if (!res) {
    209                 printf("failed parsing indices\n");
    210                 done = 1;
    211                 break;
    212             }
    213 
    214             mkgeom->indices[cind * 3]     = inds[0];
    215             mkgeom->indices[cind * 3 + 1] = inds[1];
    216             mkgeom->indices[cind * 3 + 2] = inds[2];
    217 
    218             cind++;
    219 
    220             if (cind == ninds) {
    221                 success = 1;
    222                 done = 1;
    223             }
    224 
    225             break;
    226         }
    227 
    228         // next line
    229         if (p >= data + len) {
    230             /* printf("got here, state %d cind %d ninds %d over %ld\n", */
    231             /*        state, cind, ninds, p - (data + len)); */
    232             done = 1;
    233         }
    234 
    235         if (!done)
    236             next_line(&p);
    237     }
    238 
    239     free((void*)data);
    240 
    241     if (success) {
    242         mkgeom->num_indices = ninds * 3;
    243         mkgeom->num_verts = nverts;
    244 
    245         vec3_copy(min, mdlgeom->min);
    246         vec3_copy(max, mdlgeom->max);
    247     }
    248 
    249     return success;
    250 }