]>
Dogcows Code - chaz/rasterize/blob - model.c
3 * CS5600 University of Utah
5 * mcgarvey@eng.utah.edu
15 // create an interface for a vector array
16 DEFINE_ARRAY_TYPE(vec
);
25 const raster_t
* texture
;
31 static int _model_read_raw(model_t
* m
, const char* filename
);
32 static int _model_read_obj(model_t
* m
, const char* filename
);
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
);
38 model_t
* model_alloc(const char* filename
)
41 char* ext
= strrchr(filename
, '.');
47 if (strcmp(ext
, "raw") == 0) {
48 return model_alloc2(filename
, MODEL_TYPE_RAW
);
50 if (strcmp(ext
, "obj") == 0) {
51 return model_alloc2(filename
, MODEL_TYPE_OBJ
);
55 fprintf(stderr
, "Unknown file type: %s", filename
);
59 model_t
* model_alloc2(const char* filename
, int type
)
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);
67 m
->name
= mem_strdup(filename
);
71 m
->count
= _model_try_read_cache(filename
, m
->triangles
);
80 load
= _model_read_raw(m
, filename
);
83 load
= _model_read_obj(m
, filename
);
92 _model_write_cache(filename
, m
->count
, m
->triangles
);
98 void model_destroy(model_t
* m
)
100 array_destroy(m
->triangles
);
102 raster_destroy((raster_t
*)m
->texture
);
109 const array_t
* model_geometry(const model_t
* m
)
114 int model_size(const model_t
* m
)
119 const char* model_name(const model_t
* m
)
124 color_t
model_specular(const model_t
* m
)
129 scal_t
model_shininess(const model_t
* m
)
134 void model_transformation(const model_t
* m
, mat_t
* transform
)
136 *transform
= m
->model
;
139 color_t
model_tcolor(const model_t
* m
, vec_t pt
)
142 return raster_color(m
->texture
, pt
);
147 void* model_tdata(const model_t
* m
, int* width
, int* height
)
150 if (width
) *width
= raster_width(m
->texture
);
151 if (height
) *height
= raster_height(m
->texture
);
152 return raster_data(m
->texture
);
158 void model_transform(model_t
* m
, const mat_t
* transform
)
160 m
->model
= mat_mult(m
->model
, *transform
);
163 void model_material(model_t
* m
, color_t specular
, scal_t shininess
)
165 m
->specular
= specular
;
166 m
->shininess
= shininess
;
169 void model_texture(model_t
* m
, const void* p
)
171 m
->texture
= (const raster_t
*)p
;
178 DEFINE_MAP_TYPE3(vec_t
, list_t
*, vnorm
, vec_compare(*a
, *b
));
182 * Associate a triangle with one of its vertices.
184 static void _find_normals_add_vertex(map_t
* m
, vec_t v
, tri_t
* t
)
186 list_t
** l
= map_vnorm_search(m
, v
);
188 map_vnorm_data_t
* d
= map_vnorm_insert(m
, v
, NULL
);
195 * Associate a triangle with all of its vertices.
197 static void _find_normals_add_triangle(map_t
* m
, tri_t
* t
)
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
);
205 * Calculate an averaged normal from a list of triangles that share a common
208 static void _find_normals_average(const vec_t
* v
, list_t
** l
)
210 // first, compute the average normal
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
));
216 n
= vec_normalize(n
);
218 // set the normal on each triangle's vertex that is shared
220 tri_t
* t
= (tri_t
*)(*l
)->val
;
221 if (vec_isequal(*v
, t
->a
.v
)) {
224 else if (vec_isequal(*v
, t
->b
.v
)) {
227 else if (vec_isequal(*v
, t
->c
.v
)) {
234 #endif // CALC_NORMALS
237 static int _model_read_raw(model_t
* m
, const char* filename
)
239 FILE* file
= fopen(filename
, "r");
241 fprintf(stderr
, "Cannot read %s: %s\n", filename
, strerror(errno
));
245 list_t
* triangles
= NULL
;
248 map_t
* nlookup
= map_vnorm_alloc();
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
)
259 list_push2(&triangles
, t
, mem_free
);
263 _find_normals_add_triangle(nlookup
, t
);
265 vec_t n
= vec_normalize(tri_normal(*t
));
273 map_vnorm_call(nlookup
, _find_normals_average
);
274 rbtree_destroy(nlookup
);
278 if (triangles
== NULL
) {
279 fprintf(stderr
, "No triangles read from %s\n", filename
);
284 array_tri_push(m
->triangles
, *(tri_t
*)triangles
->val
);
285 list_pop(&triangles
);
291 static int _model_read_obj(model_t
* m
, const char* filename
)
293 FILE* file
= fopen(filename
, "r");
295 fprintf(stderr
, "Cannot read %s: %s\n", filename
, strerror(errno
));
299 list_t
* triangles
= NULL
;
302 map_t
* nlookup
= map_vnorm_alloc();
305 array_t
* v
= array_vec_alloc();
306 array_t
* vt
= array_vec_alloc();
307 array_t
* vn
= array_vec_alloc();
309 array_vec_push(v
, VEC_ZERO
);
310 array_vec_push(vt
, VEC_ZERO
);
311 array_vec_push(vn
, VEC_ZERO
);
314 while (fgets(line
, 4096, file
)) {
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
));
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
));
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)));
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
));
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
))
336 list_push2(&triangles
, t
, mem_free
);
340 _find_normals_add_triangle(nlookup
, t
);
342 vec_t n
= vec_normalize(tri_normal(*t
));
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
))
354 list_push2(&triangles
, t
, mem_free
);
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
);
360 _find_normals_add_triangle(nlookup
, t
);
362 vec_t n
= vec_normalize(tri_normal(*t
));
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
))
375 list_push2(&triangles
, t
, mem_free
);
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
);
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
))
388 list_push2(&triangles
, t
, mem_free
);
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
);
404 map_vnorm_call(nlookup
, _find_normals_average
);
405 rbtree_destroy(nlookup
);
409 if (triangles
== NULL
) {
410 fprintf(stderr
, "No triangles read from %s\n", filename
);
415 array_tri_push(m
->triangles
, *(tri_t
*)triangles
->val
);
416 list_pop(&triangles
);
423 #define _DO_OR_DONE(X) if ((X) <= 0) goto done
426 * Try to read the triangle geometry from the cache file.
428 static int _model_try_read_cache(const char* filename
, array_t
* l
)
431 char* cachename
= mem_strcat(".", filename
);
432 FILE* file
= fopen(cachename
, "rb");
437 float x1
, y1
, z1
, x2
, y2
, z2
, x3
, y3
, z3
;
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
));
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
)
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));
489 * Write the triangle data to the cache.
491 static void _model_write_cache(const char* filename
, int count
, const array_t
* l
)
493 char* cachename
= mem_strcat(".", filename
);
494 FILE* file
= fopen(cachename
, "wb");
496 fprintf(stderr
, "Cannot write %s: %s\n", cachename
, strerror(errno
));
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
));
This page took 0.069426 seconds and 4 git commands to generate.