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 }