]> Dogcows Code - chaz/rasterize/blob - model.c
add opengl support
[chaz/rasterize] / model.c
1
2 /*
3 * CS5600 University of Utah
4 * Charles McGarvey
5 * mcgarvey@eng.utah.edu
6 */
7
8 #include <errno.h>
9
10 #include "list.h"
11 #include "model.h"
12 #include "raster.h"
13
14
15 // create an interface for a vector array
16 DEFINE_ARRAY_TYPE(vec);
17
18
19 struct model
20 {
21 array_t* triangles;
22 mat_t model;
23 color_t specular;
24 scal_t shininess;
25 const raster_t* texture;
26 char* name;
27 int count;
28 };
29
30
31 static int _model_read_raw(model_t* m, const char* filename);
32 static int _model_read_obj(model_t* m, const char* filename);
33
34 static int _model_try_read_cache(const char* filename, array_t* l);
35 static void _model_write_cache(const char* filename, int count, const array_t* l);
36
37
38 model_t* model_alloc(const char* filename)
39 {
40 int type = 0;
41 char* ext = strrchr(filename, '.');
42 if (ext == NULL) {
43 goto fail;
44 }
45 ++ext;
46
47 if (strcmp(ext, "raw") == 0) {
48 return model_alloc2(filename, MODEL_TYPE_RAW);
49 }
50 if (strcmp(ext, "obj") == 0) {
51 return model_alloc2(filename, MODEL_TYPE_OBJ);
52 }
53
54 fail:
55 fprintf(stderr, "Unknown file type: %s", filename);
56 return NULL;
57 }
58
59 model_t* model_alloc2(const char* filename, int type)
60 {
61 model_t* m = (model_t*)mem_alloc(sizeof(model_t));
62 m->triangles = array_tri_alloc();
63 m->model = MAT_IDENTITY;
64 m->specular = COLOR_BLACK;
65 m->shininess = S(64.0);
66 m->texture = NULL;
67 m->name = mem_strdup(filename);
68 m->count = 0;
69
70 #if CACHE_GEOMETRY
71 m->count = _model_try_read_cache(filename, m->triangles);
72 if (0 < m->count) {
73 return m;
74 }
75 #endif
76
77 int load;
78 switch (type) {
79 case MODEL_TYPE_RAW:
80 load = _model_read_raw(m, filename);
81 break;
82 case MODEL_TYPE_OBJ:
83 load = _model_read_obj(m, filename);
84 break;
85 }
86 if (load != 0) {
87 model_destroy(m);
88 return NULL;
89 }
90
91 #if CACHE_GEOMETRY
92 _model_write_cache(filename, m->count, m->triangles);
93 #endif
94
95 return m;
96 }
97
98 void model_destroy(model_t* m)
99 {
100 array_destroy(m->triangles);
101 if (m->texture) {
102 raster_destroy((raster_t*)m->texture);
103 }
104 mem_free(m->name);
105 mem_free(m);
106 }
107
108
109 const array_t* model_geometry(const model_t* m)
110 {
111 return m->triangles;
112 }
113
114 int model_size(const model_t* m)
115 {
116 return m->count;
117 }
118
119 const char* model_name(const model_t* m)
120 {
121 return m->name;
122 }
123
124 color_t model_specular(const model_t* m)
125 {
126 return m->specular;
127 }
128
129 scal_t model_shininess(const model_t* m)
130 {
131 return m->shininess;
132 }
133
134 void model_transformation(const model_t* m, mat_t* transform)
135 {
136 *transform = m->model;
137 }
138
139 color_t model_tcolor(const model_t* m, vec_t pt)
140 {
141 if (m->texture) {
142 return raster_color(m->texture, pt);
143 }
144 return COLOR_WHITE;
145 }
146
147 void* model_tdata(const model_t* m, int* width, int* height)
148 {
149 if (m->texture) {
150 if (width) *width = raster_width(m->texture);
151 if (height) *height = raster_height(m->texture);
152 return raster_data(m->texture);
153 }
154 return NULL;
155 }
156
157
158 void model_transform(model_t* m, const mat_t* transform)
159 {
160 m->model = mat_mult(m->model, *transform);
161 }
162
163 void model_material(model_t* m, color_t specular, scal_t shininess)
164 {
165 m->specular = specular;
166 m->shininess = shininess;
167 }
168
169 void model_texture(model_t* m, const void* p)
170 {
171 m->texture = (const raster_t*)p;
172 }
173
174
175 #if CALC_NORMALS
176
177 #include "map.h"
178 DEFINE_MAP_TYPE3(vec_t, list_t*, vnorm, vec_compare(*a, *b));
179
180
181 /*
182 * Associate a triangle with one of its vertices.
183 */
184 static void _find_normals_add_vertex(map_t* m, vec_t v, tri_t* t)
185 {
186 list_t** l = map_vnorm_search(m, v);
187 if (l == NULL) {
188 map_vnorm_data_t* d = map_vnorm_insert(m, v, NULL);
189 l = &d->val;
190 }
191 list_push(l, t);
192 }
193
194 /*
195 * Associate a triangle with all of its vertices.
196 */
197 static void _find_normals_add_triangle(map_t* m, tri_t* t)
198 {
199 _find_normals_add_vertex(m, t->a.v, t);
200 _find_normals_add_vertex(m, t->b.v, t);
201 _find_normals_add_vertex(m, t->c.v, t);
202 }
203
204 /*
205 * Calculate an averaged normal from a list of triangles that share a common
206 * vertex.
207 */
208 static void _find_normals_average(const vec_t* v, list_t** l)
209 {
210 // first, compute the average normal
211 vec_t n = VEC_ZERO;
212 for (list_t* i = *l; i; i = i->link) {
213 tri_t* t = (tri_t*)i->val;
214 n = vec_add(n, tri_normal(*t));
215 }
216 n = vec_normalize(n);
217
218 // set the normal on each triangle's vertex that is shared
219 while (*l) {
220 tri_t* t = (tri_t*)(*l)->val;
221 if (vec_isequal(*v, t->a.v)) {
222 t->a.n = n;
223 }
224 else if (vec_isequal(*v, t->b.v)) {
225 t->b.n = n;
226 }
227 else if (vec_isequal(*v, t->c.v)) {
228 t->c.n = n;
229 }
230 list_pop(l);
231 }
232 }
233
234 #endif // CALC_NORMALS
235
236
237 static int _model_read_raw(model_t* m, const char* filename)
238 {
239 FILE* file = fopen(filename, "r");
240 if (file == NULL) {
241 fprintf(stderr, "Cannot read %s: %s\n", filename, strerror(errno));
242 return -1;
243 }
244
245 list_t* triangles = NULL;
246
247 #if CALC_NORMALS
248 map_t* nlookup = map_vnorm_alloc();
249 #endif
250
251 double x1, y1, z1, x2, y2, z2, x3, y3, z3;
252 while (fscanf(file, " %lf %lf %lf %lf %lf %lf %lf %lf %lf",
253 &x1, &y1, &z1, &x2, &y2, &z2, &x3, &y3, &z3) == 9) {
254 tri_t* t = tri_alloc(
255 vert_new2((scal_t)x1, (scal_t)y1, (scal_t)z1),
256 vert_new2((scal_t)x2, (scal_t)y2, (scal_t)z2),
257 vert_new2((scal_t)x3, (scal_t)y3, (scal_t)z3)
258 );
259 list_push2(&triangles, t, mem_free);
260 ++m->count;
261
262 #if CALC_NORMALS
263 _find_normals_add_triangle(nlookup, t);
264 #else
265 vec_t n = vec_normalize(tri_normal(*t));
266 t->a.n = n;
267 t->b.n = n;
268 t->c.n = n;
269 #endif
270 }
271
272 #if CALC_NORMALS
273 map_vnorm_call(nlookup, _find_normals_average);
274 rbtree_destroy(nlookup);
275 #endif
276
277 fclose(file);
278 if (triangles == NULL) {
279 fprintf(stderr, "No triangles read from %s\n", filename);
280 return -1;
281 }
282
283 while (triangles) {
284 array_tri_push(m->triangles, *(tri_t*)triangles->val);
285 list_pop(&triangles);
286 }
287
288 return 0;
289 }
290
291 static int _model_read_obj(model_t* m, const char* filename)
292 {
293 FILE* file = fopen(filename, "r");
294 if (file == NULL) {
295 fprintf(stderr, "Cannot read %s: %s\n", filename, strerror(errno));
296 return -1;
297 }
298
299 list_t* triangles = NULL;
300
301 #if CALC_NORMALS
302 map_t* nlookup = map_vnorm_alloc();
303 #endif
304
305 array_t* v = array_vec_alloc();
306 array_t* vt = array_vec_alloc();
307 array_t* vn = array_vec_alloc();
308
309 array_vec_push(v, VEC_ZERO);
310 array_vec_push(vt, VEC_ZERO);
311 array_vec_push(vn, VEC_ZERO);
312
313 char line[4096];
314 while (fgets(line, 4096, file)) {
315 char name[4096];
316 double f1, f2, f3, f4;
317 int i1, i2, i3, i4, i5, i6, i7, i8, i9;
318 if (sscanf(line, "v %lf %lf %lf %lf ", &f1, &f2, &f3, &f4) == 4) {
319 array_vec_push(v, vec_new2((scal_t)f1, (scal_t)f2, (scal_t)f3, (scal_t)f4));
320 }
321 else if (sscanf(line, "v %lf %lf %lf ", &f1, &f2, &f3) == 3) {
322 array_vec_push(v, vec_new((scal_t)f1, (scal_t)f2, (scal_t)f3));
323 }
324 else if (sscanf(line, "vt %lf %lf ", &f1, &f2) == 2) {
325 array_vec_push(vt, vec_new((scal_t)f1, (scal_t)f2, S(0.0)));
326 }
327 else if (sscanf(line, "vn %lf %lf %lf ", &f1, &f2, &f3) == 3) {
328 array_vec_push(vn, vec_new((scal_t)f1, (scal_t)f2, (scal_t)f3));
329 }
330 else if (sscanf(line, "f %d %d %d ", &i1, &i2, &i3) == 3) {
331 tri_t* t = tri_alloc(
332 vert_new(*array_vec_index(v, i1)),
333 vert_new(*array_vec_index(v, i2)),
334 vert_new(*array_vec_index(v, i3))
335 );
336 list_push2(&triangles, t, mem_free);
337 ++m->count;
338
339 #if CALC_NORMALS
340 _find_normals_add_triangle(nlookup, t);
341 #else
342 vec_t n = vec_normalize(tri_normal(*t));
343 t->a.n = n;
344 t->b.n = n;
345 t->c.n = n;
346 #endif
347 }
348 else if (sscanf(line, "f %d/%d %d/%d %d/%d ", &i1, &i2, &i3, &i4, &i5, &i6) == 6) {
349 tri_t* t = tri_alloc(
350 vert_new(*array_vec_index(v, i1)),
351 vert_new(*array_vec_index(v, i3)),
352 vert_new(*array_vec_index(v, i5))
353 );
354 list_push2(&triangles, t, mem_free);
355 ++m->count;
356 t->a.t = *array_vec_index(vt, i2);
357 t->b.t = *array_vec_index(vt, i4);
358 t->c.t = *array_vec_index(vt, i6);
359 #if CALC_NORMALS
360 _find_normals_add_triangle(nlookup, t);
361 #else
362 vec_t n = vec_normalize(tri_normal(*t));
363 t->a.n = n;
364 t->b.n = n;
365 t->c.n = n;
366 #endif
367 }
368 else if (sscanf(line, "f %d//%d %d//%d %d//%d ",
369 &i1, &i2, &i3, &i4, &i5, &i6) == 6) {
370 tri_t* t = tri_alloc(
371 vert_new(*array_vec_index(v, i1)),
372 vert_new(*array_vec_index(v, i3)),
373 vert_new(*array_vec_index(v, i5))
374 );
375 list_push2(&triangles, t, mem_free);
376 ++m->count;
377 t->a.n = *array_vec_index(vn, i2);
378 t->b.n = *array_vec_index(vn, i4);
379 t->c.n = *array_vec_index(vn, i6);
380 }
381 else if (sscanf(line, "f %d/%d/%d %d/%d/%d %d/%d/%d ",
382 &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8, &i9) == 9) {
383 tri_t* t = tri_alloc(
384 vert_new(*array_vec_index(v, i1)),
385 vert_new(*array_vec_index(v, i4)),
386 vert_new(*array_vec_index(v, i7))
387 );
388 list_push2(&triangles, t, mem_free);
389 ++m->count;
390 t->a.t = *array_vec_index(vt, i2);
391 t->b.t = *array_vec_index(vt, i5);
392 t->c.t = *array_vec_index(vt, i8);
393 t->a.n = *array_vec_index(vn, i3);
394 t->b.n = *array_vec_index(vn, i6);
395 t->c.n = *array_vec_index(vn, i9);
396 }
397 }
398
399 array_destroy(v);
400 array_destroy(vt);
401 array_destroy(vn);
402
403 #if CALC_NORMALS
404 map_vnorm_call(nlookup, _find_normals_average);
405 rbtree_destroy(nlookup);
406 #endif
407
408 fclose(file);
409 if (triangles == NULL) {
410 fprintf(stderr, "No triangles read from %s\n", filename);
411 return -1;
412 }
413
414 while (triangles) {
415 array_tri_push(m->triangles, *(tri_t*)triangles->val);
416 list_pop(&triangles);
417 }
418
419 return 0;
420 }
421
422
423 #define _DO_OR_DONE(X) if ((X) <= 0) goto done
424
425 /*
426 * Try to read the triangle geometry from the cache file.
427 */
428 static int _model_try_read_cache(const char* filename, array_t* l)
429 {
430 int count = 0;
431 char* cachename = mem_strcat(".", filename);
432 FILE* file = fopen(cachename, "rb");
433 if (file == NULL) {
434 goto done;
435 }
436
437 float x1, y1, z1, x2, y2, z2, x3, y3, z3;
438 while (1) {
439 _DO_OR_DONE(fread(&x1, sizeof(float), 1, file));
440 _DO_OR_DONE(fread(&y1, sizeof(float), 1, file));
441 _DO_OR_DONE(fread(&z1, sizeof(float), 1, file));
442 _DO_OR_DONE(fread(&x2, sizeof(float), 1, file));
443 _DO_OR_DONE(fread(&y2, sizeof(float), 1, file));
444 _DO_OR_DONE(fread(&z2, sizeof(float), 1, file));
445 _DO_OR_DONE(fread(&x3, sizeof(float), 1, file));
446 _DO_OR_DONE(fread(&y3, sizeof(float), 1, file));
447 _DO_OR_DONE(fread(&z3, sizeof(float), 1, file));
448 tri_t t = tri_new(
449 vert_new2((scal_t)x1, (scal_t)y1, (scal_t)z1),
450 vert_new2((scal_t)x2, (scal_t)y2, (scal_t)z2),
451 vert_new2((scal_t)x3, (scal_t)y3, (scal_t)z3)
452 );
453 ++count;
454 array_tri_push(l, t);
455 tri_t* tp = array_tri_back(l);
456 _DO_OR_DONE(fread(&x1, sizeof(float), 1, file));
457 _DO_OR_DONE(fread(&y1, sizeof(float), 1, file));
458 _DO_OR_DONE(fread(&z1, sizeof(float), 1, file));
459 _DO_OR_DONE(fread(&x2, sizeof(float), 1, file));
460 _DO_OR_DONE(fread(&y2, sizeof(float), 1, file));
461 _DO_OR_DONE(fread(&z2, sizeof(float), 1, file));
462 _DO_OR_DONE(fread(&x3, sizeof(float), 1, file));
463 _DO_OR_DONE(fread(&y3, sizeof(float), 1, file));
464 _DO_OR_DONE(fread(&z3, sizeof(float), 1, file));
465 tp->a.n = vec_new((scal_t)x1, (scal_t)y1, (scal_t)z1);
466 tp->b.n = vec_new((scal_t)x2, (scal_t)y2, (scal_t)z2);
467 tp->c.n = vec_new((scal_t)x3, (scal_t)y3, (scal_t)z3);
468 _DO_OR_DONE(fread(&x1, sizeof(float), 1, file));
469 _DO_OR_DONE(fread(&y1, sizeof(float), 1, file));
470 _DO_OR_DONE(fread(&x2, sizeof(float), 1, file));
471 _DO_OR_DONE(fread(&y2, sizeof(float), 1, file));
472 _DO_OR_DONE(fread(&x3, sizeof(float), 1, file));
473 _DO_OR_DONE(fread(&y3, sizeof(float), 1, file));
474 tp->a.t = vec_new((scal_t)x1, (scal_t)y1, S(0.0));
475 tp->b.t = vec_new((scal_t)x2, (scal_t)y2, S(0.0));
476 tp->c.t = vec_new((scal_t)x3, (scal_t)y3, S(0.0));
477 }
478
479 done:
480 mem_free(cachename);
481 if (file != NULL) {
482 fclose(file);
483 }
484
485 return count;
486 }
487
488 /*
489 * Write the triangle data to the cache.
490 */
491 static void _model_write_cache(const char* filename, int count, const array_t* l)
492 {
493 char* cachename = mem_strcat(".", filename);
494 FILE* file = fopen(cachename, "wb");
495 if (file == NULL) {
496 fprintf(stderr, "Cannot write %s: %s\n", cachename, strerror(errno));
497 goto done;
498 }
499
500 float x1, y1, z1, x2, y2, z2, x3, y3, z3;
501 array_it_t it = array_begin(l);
502 for (tri_t* t; t = array_it_tri_next(&it);) {
503 x1 = (float)t->a.v.x; y1 = (float)t->a.v.y; z1 = (float)t->a.v.z;
504 x2 = (float)t->b.v.x; y2 = (float)t->b.v.y; z2 = (float)t->b.v.z;
505 x3 = (float)t->c.v.x; y3 = (float)t->c.v.y; z3 = (float)t->c.v.z;
506 _DO_OR_DONE(fwrite(&x1, sizeof(float), 1, file));
507 _DO_OR_DONE(fwrite(&y1, sizeof(float), 1, file));
508 _DO_OR_DONE(fwrite(&z1, sizeof(float), 1, file));
509 _DO_OR_DONE(fwrite(&x2, sizeof(float), 1, file));
510 _DO_OR_DONE(fwrite(&y2, sizeof(float), 1, file));
511 _DO_OR_DONE(fwrite(&z2, sizeof(float), 1, file));
512 _DO_OR_DONE(fwrite(&x3, sizeof(float), 1, file));
513 _DO_OR_DONE(fwrite(&y3, sizeof(float), 1, file));
514 _DO_OR_DONE(fwrite(&z3, sizeof(float), 1, file));
515 x1 = (float)t->a.n.x; y1 = (float)t->a.n.y; z1 = (float)t->a.n.z;
516 x2 = (float)t->b.n.x; y2 = (float)t->b.n.y; z2 = (float)t->b.n.z;
517 x3 = (float)t->c.n.x; y3 = (float)t->c.n.y; z3 = (float)t->c.n.z;
518 _DO_OR_DONE(fwrite(&x1, sizeof(float), 1, file));
519 _DO_OR_DONE(fwrite(&y1, sizeof(float), 1, file));
520 _DO_OR_DONE(fwrite(&z1, sizeof(float), 1, file));
521 _DO_OR_DONE(fwrite(&x2, sizeof(float), 1, file));
522 _DO_OR_DONE(fwrite(&y2, sizeof(float), 1, file));
523 _DO_OR_DONE(fwrite(&z2, sizeof(float), 1, file));
524 _DO_OR_DONE(fwrite(&x3, sizeof(float), 1, file));
525 _DO_OR_DONE(fwrite(&y3, sizeof(float), 1, file));
526 _DO_OR_DONE(fwrite(&z3, sizeof(float), 1, file));
527 x1 = (float)t->a.t.x; y1 = (float)t->a.t.y;
528 x2 = (float)t->b.t.x; y2 = (float)t->b.t.y;
529 x3 = (float)t->c.t.x; y3 = (float)t->c.t.y;
530 _DO_OR_DONE(fwrite(&x1, sizeof(float), 1, file));
531 _DO_OR_DONE(fwrite(&y1, sizeof(float), 1, file));
532 _DO_OR_DONE(fwrite(&x2, sizeof(float), 1, file));
533 _DO_OR_DONE(fwrite(&y2, sizeof(float), 1, file));
534 _DO_OR_DONE(fwrite(&x3, sizeof(float), 1, file));
535 _DO_OR_DONE(fwrite(&y3, sizeof(float), 1, file));
536 }
537
538 done:
539 mem_free(cachename);
540 if (file != NULL) {
541 fclose(file);
542 }
543 }
544
545 #undef _DO_OR_DIE
546
This page took 0.095838 seconds and 4 git commands to generate.