]>
Dogcows Code - chaz/rasterize/blob - model.c
3 * CS5600 University of Utah
5 * mcgarvey@eng.utah.edu
16 // create an interface for a vector array
17 DEFINE_ARRAY_TYPE(vec
);
26 const raster_t
* texture
;
32 static int _model_read_raw(model_t
* m
, const char* filename
);
33 static int _model_read_obj(model_t
* m
, const char* filename
);
35 static int _model_try_read_cache(const char* filename
, list_t
** l
);
36 static void _model_write_cache(const char* filename
, int count
, list_t
* l
);
39 model_t
* model_alloc(const char* filename
)
42 char* ext
= strrchr(filename
, '.');
48 if (strcmp(ext
, "raw") == 0) {
49 return model_alloc2(filename
, MODEL_TYPE_RAW
);
51 if (strcmp(ext
, "obj") == 0) {
52 return model_alloc2(filename
, MODEL_TYPE_OBJ
);
56 fprintf(stderr
, "Unknown file type: %s", filename
);
60 model_t
* model_alloc2(const char* filename
, int type
)
62 model_t
* m
= (model_t
*)mem_alloc(sizeof(model_t
));
64 m
->model
= MAT_IDENTITY
;
65 m
->specular
= COLOR_BLACK
;
66 m
->shininess
= S(64.0);
68 m
->name
= mem_strdup(filename
);
72 m
->count
= _model_try_read_cache(filename
, &m
->triangles
);
81 load
= _model_read_raw(m
, filename
);
84 load
= _model_read_obj(m
, filename
);
93 _model_write_cache(filename
, m
->count
, m
->triangles
);
99 void model_destroy(model_t
* m
)
101 list_destroy(&m
->triangles
);
103 raster_destroy((raster_t
*)m
->texture
);
110 const list_t
* model_geometry(const model_t
* m
)
115 int model_size(const model_t
* m
)
120 const char* model_name(const model_t
* m
)
125 color_t
model_specular(const model_t
* m
)
130 scal_t
model_shininess(const model_t
* m
)
135 void model_transformation(const model_t
* m
, mat_t
* transform
)
137 *transform
= m
->model
;
140 color_t
model_tcolor(const model_t
* m
, vec_t pt
)
143 return raster_color(m
->texture
, pt
);
149 void model_transform(model_t
* m
, const mat_t
* transform
)
151 m
->model
= mat_mult(m
->model
, *transform
);
154 void model_material(model_t
* m
, color_t specular
, scal_t shininess
)
156 m
->specular
= specular
;
157 m
->shininess
= shininess
;
160 void model_texture(model_t
* m
, const void* p
)
162 m
->texture
= (const raster_t
*)p
;
169 DEFINE_MAP_TYPE3(vec_t
, list_t
*, vnorm
, vec_compare(*a
, *b
));
173 * Associate a triangle with one of its vertices.
175 static void _find_normals_add_vertex(map_t
* m
, vec_t v
, tri_t
* t
)
177 list_t
** l
= map_vnorm_search(m
, v
);
179 map_vnorm_data_t
* d
= map_vnorm_insert(m
, v
, NULL
);
186 * Associate a triangle with all of its vertices.
188 static void _find_normals_add_triangle(map_t
* m
, tri_t
* t
)
190 _find_normals_add_vertex(m
, t
->a
.v
, t
);
191 _find_normals_add_vertex(m
, t
->b
.v
, t
);
192 _find_normals_add_vertex(m
, t
->c
.v
, t
);
196 * Calculate an averaged normal from a list of triangles that share a common
199 static void _find_normals_average(const vec_t
* v
, list_t
** l
)
201 // first, compute the average normal
203 for (list_t
* i
= *l
; i
; i
= i
->link
) {
204 tri_t
* t
= (tri_t
*)i
->val
;
205 n
= vec_add(n
, tri_normal(*t
));
207 n
= vec_normalize(n
);
209 // set the normal on each triangle's vertex that is shared
211 tri_t
* t
= (tri_t
*)(*l
)->val
;
212 if (vec_isequal(*v
, t
->a
.v
)) {
215 else if (vec_isequal(*v
, t
->b
.v
)) {
218 else if (vec_isequal(*v
, t
->c
.v
)) {
225 #endif // CALC_NORMALS
228 static int _model_read_raw(model_t
* m
, const char* filename
)
230 FILE* file
= fopen(filename
, "r");
232 fprintf(stderr
, "Cannot read %s: %s\n", filename
, strerror(errno
));
237 map_t
* nlookup
= map_vnorm_alloc();
240 double x1
, y1
, z1
, x2
, y2
, z2
, x3
, y3
, z3
;
241 while (fscanf(file
, " %lf %lf %lf %lf %lf %lf %lf %lf %lf",
242 &x1
, &y1
, &z1
, &x2
, &y2
, &z2
, &x3
, &y3
, &z3
) == 9) {
243 tri_t
* t
= tri_alloc(
244 vert_new2((scal_t
)x1
, (scal_t
)y1
, (scal_t
)z1
),
245 vert_new2((scal_t
)x2
, (scal_t
)y2
, (scal_t
)z2
),
246 vert_new2((scal_t
)x3
, (scal_t
)y3
, (scal_t
)z3
)
248 list_push2(&m
->triangles
, t
, mem_free
);
252 _find_normals_add_triangle(nlookup
, t
);
254 vec_t n
= vec_normalize(tri_normal(*t
));
262 map_vnorm_call(nlookup
, _find_normals_average
);
263 rbtree_destroy(nlookup
);
267 if (m
->triangles
== NULL
) {
268 fprintf(stderr
, "No triangles read from %s\n", filename
);
274 static int _model_read_obj(model_t
* m
, const char* filename
)
276 FILE* file
= fopen(filename
, "r");
278 fprintf(stderr
, "Cannot read %s: %s\n", filename
, strerror(errno
));
283 map_t
* nlookup
= map_vnorm_alloc();
286 array_t
* v
= array_vec_alloc();
287 array_t
* vt
= array_vec_alloc();
288 array_t
* vn
= array_vec_alloc();
290 array_vec_push(v
, VEC_ZERO
);
291 array_vec_push(vt
, VEC_ZERO
);
292 array_vec_push(vn
, VEC_ZERO
);
295 while (fgets(line
, 4096, file
)) {
297 double f1
, f2
, f3
, f4
;
298 int i1
, i2
, i3
, i4
, i5
, i6
, i7
, i8
, i9
;
299 if (sscanf(line
, "v %lf %lf %lf %lf ", &f1
, &f2
, &f3
, &f4
) == 4) {
300 array_vec_push(v
, vec_new2((scal_t
)f1
, (scal_t
)f2
, (scal_t
)f3
, (scal_t
)f4
));
302 else if (sscanf(line
, "v %lf %lf %lf ", &f1
, &f2
, &f3
) == 3) {
303 array_vec_push(v
, vec_new((scal_t
)f1
, (scal_t
)f2
, (scal_t
)f3
));
305 else if (sscanf(line
, "vt %lf %lf ", &f1
, &f2
) == 2) {
306 array_vec_push(vt
, vec_new((scal_t
)f1
, (scal_t
)f2
, S(0.0)));
308 else if (sscanf(line
, "vn %lf %lf %lf ", &f1
, &f2
, &f3
) == 3) {
309 array_vec_push(vn
, vec_new((scal_t
)f1
, (scal_t
)f2
, (scal_t
)f3
));
311 else if (sscanf(line
, "f %d %d %d ", &i1
, &i2
, &i3
) == 3) {
312 tri_t
* t
= tri_alloc(
313 vert_new(*array_vec_index(v
, i1
)),
314 vert_new(*array_vec_index(v
, i2
)),
315 vert_new(*array_vec_index(v
, i3
))
317 list_push2(&m
->triangles
, t
, mem_free
);
321 _find_normals_add_triangle(nlookup
, t
);
323 vec_t n
= vec_normalize(tri_normal(*t
));
329 else if (sscanf(line
, "f %d/%d %d/%d %d/%d ", &i1
, &i2
, &i3
, &i4
, &i5
, &i6
) == 6) {
330 tri_t
* t
= tri_alloc(
331 vert_new(*array_vec_index(v
, i1
)),
332 vert_new(*array_vec_index(v
, i3
)),
333 vert_new(*array_vec_index(v
, i5
))
335 list_push2(&m
->triangles
, t
, mem_free
);
337 t
->a
.t
= *array_vec_index(vt
, i2
);
338 t
->b
.t
= *array_vec_index(vt
, i4
);
339 t
->c
.t
= *array_vec_index(vt
, i6
);
341 _find_normals_add_triangle(nlookup
, t
);
343 vec_t n
= vec_normalize(tri_normal(*t
));
349 else if (sscanf(line
, "f %d//%d %d//%d %d//%d ",
350 &i1
, &i2
, &i3
, &i4
, &i5
, &i6
) == 6) {
351 tri_t
* t
= tri_alloc(
352 vert_new(*array_vec_index(v
, i1
)),
353 vert_new(*array_vec_index(v
, i3
)),
354 vert_new(*array_vec_index(v
, i5
))
356 list_push2(&m
->triangles
, t
, mem_free
);
358 t
->a
.n
= *array_vec_index(vn
, i2
);
359 t
->b
.n
= *array_vec_index(vn
, i4
);
360 t
->c
.n
= *array_vec_index(vn
, i6
);
362 else if (sscanf(line
, "f %d/%d/%d %d/%d/%d %d/%d/%d ",
363 &i1
, &i2
, &i3
, &i4
, &i5
, &i6
, &i7
, &i8
, &i9
) == 9) {
364 tri_t
* t
= tri_alloc(
365 vert_new(*array_vec_index(v
, i1
)),
366 vert_new(*array_vec_index(v
, i4
)),
367 vert_new(*array_vec_index(v
, i7
))
369 list_push2(&m
->triangles
, t
, mem_free
);
371 t
->a
.t
= *array_vec_index(vt
, i2
);
372 t
->b
.t
= *array_vec_index(vt
, i5
);
373 t
->c
.t
= *array_vec_index(vt
, i8
);
374 t
->a
.n
= *array_vec_index(vn
, i3
);
375 t
->b
.n
= *array_vec_index(vn
, i6
);
376 t
->c
.n
= *array_vec_index(vn
, i9
);
385 map_vnorm_call(nlookup
, _find_normals_average
);
386 rbtree_destroy(nlookup
);
390 if (m
->triangles
== NULL
) {
391 fprintf(stderr
, "No triangles read from %s\n", filename
);
398 #define _DO_OR_DONE(X) if ((X) <= 0) goto done
401 * Try to read the triangle geometry from the cache file.
403 static int _model_try_read_cache(const char* filename
, list_t
** l
)
406 char* cachename
= mem_strcat(".", filename
);
407 FILE* file
= fopen(cachename
, "rb");
412 float x1
, y1
, z1
, x2
, y2
, z2
, x3
, y3
, z3
;
414 _DO_OR_DONE(fread(&x1
, sizeof(float), 1, file
));
415 _DO_OR_DONE(fread(&y1
, sizeof(float), 1, file
));
416 _DO_OR_DONE(fread(&z1
, sizeof(float), 1, file
));
417 _DO_OR_DONE(fread(&x2
, sizeof(float), 1, file
));
418 _DO_OR_DONE(fread(&y2
, sizeof(float), 1, file
));
419 _DO_OR_DONE(fread(&z2
, sizeof(float), 1, file
));
420 _DO_OR_DONE(fread(&x3
, sizeof(float), 1, file
));
421 _DO_OR_DONE(fread(&y3
, sizeof(float), 1, file
));
422 _DO_OR_DONE(fread(&z3
, sizeof(float), 1, file
));
423 tri_t
* t
= tri_alloc(
424 vert_new2((scal_t
)x1
, (scal_t
)y1
, (scal_t
)z1
),
425 vert_new2((scal_t
)x2
, (scal_t
)y2
, (scal_t
)z2
),
426 vert_new2((scal_t
)x3
, (scal_t
)y3
, (scal_t
)z3
)
429 list_push2(l
, t
, mem_free
);
430 _DO_OR_DONE(fread(&x1
, sizeof(float), 1, file
));
431 _DO_OR_DONE(fread(&y1
, sizeof(float), 1, file
));
432 _DO_OR_DONE(fread(&z1
, sizeof(float), 1, file
));
433 _DO_OR_DONE(fread(&x2
, sizeof(float), 1, file
));
434 _DO_OR_DONE(fread(&y2
, sizeof(float), 1, file
));
435 _DO_OR_DONE(fread(&z2
, sizeof(float), 1, file
));
436 _DO_OR_DONE(fread(&x3
, sizeof(float), 1, file
));
437 _DO_OR_DONE(fread(&y3
, sizeof(float), 1, file
));
438 _DO_OR_DONE(fread(&z3
, sizeof(float), 1, file
));
439 t
->a
.n
= vec_new((scal_t
)x1
, (scal_t
)y1
, (scal_t
)z1
);
440 t
->b
.n
= vec_new((scal_t
)x2
, (scal_t
)y2
, (scal_t
)z2
);
441 t
->c
.n
= vec_new((scal_t
)x3
, (scal_t
)y3
, (scal_t
)z3
);
442 _DO_OR_DONE(fread(&x1
, sizeof(float), 1, file
));
443 _DO_OR_DONE(fread(&y1
, sizeof(float), 1, file
));
444 _DO_OR_DONE(fread(&x2
, sizeof(float), 1, file
));
445 _DO_OR_DONE(fread(&y2
, sizeof(float), 1, file
));
446 _DO_OR_DONE(fread(&x3
, sizeof(float), 1, file
));
447 _DO_OR_DONE(fread(&y3
, sizeof(float), 1, file
));
448 t
->a
.t
= vec_new((scal_t
)x1
, (scal_t
)y1
, S(0.0));
449 t
->b
.t
= vec_new((scal_t
)x2
, (scal_t
)y2
, S(0.0));
450 t
->c
.t
= vec_new((scal_t
)x3
, (scal_t
)y3
, S(0.0));
463 * Write the triangle data to the cache.
465 static void _model_write_cache(const char* filename
, int count
, list_t
* l
)
467 char* cachename
= mem_strcat(".", filename
);
468 FILE* file
= fopen(cachename
, "wb");
470 fprintf(stderr
, "Cannot write %s: %s\n", cachename
, strerror(errno
));
474 float x1
, y1
, z1
, x2
, y2
, z2
, x3
, y3
, z3
;
475 for (list_t
* i
= l
; i
; i
= i
->link
) {
476 tri_t
* t
= (tri_t
*)i
->val
;
477 x1
= (float)t
->a
.v
.x
; y1
= (float)t
->a
.v
.y
; z1
= (float)t
->a
.v
.z
;
478 x2
= (float)t
->b
.v
.x
; y2
= (float)t
->b
.v
.y
; z2
= (float)t
->b
.v
.z
;
479 x3
= (float)t
->c
.v
.x
; y3
= (float)t
->c
.v
.y
; z3
= (float)t
->c
.v
.z
;
480 _DO_OR_DONE(fwrite(&x1
, sizeof(float), 1, file
));
481 _DO_OR_DONE(fwrite(&y1
, sizeof(float), 1, file
));
482 _DO_OR_DONE(fwrite(&z1
, sizeof(float), 1, file
));
483 _DO_OR_DONE(fwrite(&x2
, sizeof(float), 1, file
));
484 _DO_OR_DONE(fwrite(&y2
, sizeof(float), 1, file
));
485 _DO_OR_DONE(fwrite(&z2
, sizeof(float), 1, file
));
486 _DO_OR_DONE(fwrite(&x3
, sizeof(float), 1, file
));
487 _DO_OR_DONE(fwrite(&y3
, sizeof(float), 1, file
));
488 _DO_OR_DONE(fwrite(&z3
, sizeof(float), 1, file
));
489 x1
= (float)t
->a
.n
.x
; y1
= (float)t
->a
.n
.y
; z1
= (float)t
->a
.n
.z
;
490 x2
= (float)t
->b
.n
.x
; y2
= (float)t
->b
.n
.y
; z2
= (float)t
->b
.n
.z
;
491 x3
= (float)t
->c
.n
.x
; y3
= (float)t
->c
.n
.y
; z3
= (float)t
->c
.n
.z
;
492 _DO_OR_DONE(fwrite(&x1
, sizeof(float), 1, file
));
493 _DO_OR_DONE(fwrite(&y1
, sizeof(float), 1, file
));
494 _DO_OR_DONE(fwrite(&z1
, sizeof(float), 1, file
));
495 _DO_OR_DONE(fwrite(&x2
, sizeof(float), 1, file
));
496 _DO_OR_DONE(fwrite(&y2
, sizeof(float), 1, file
));
497 _DO_OR_DONE(fwrite(&z2
, sizeof(float), 1, file
));
498 _DO_OR_DONE(fwrite(&x3
, sizeof(float), 1, file
));
499 _DO_OR_DONE(fwrite(&y3
, sizeof(float), 1, file
));
500 _DO_OR_DONE(fwrite(&z3
, sizeof(float), 1, file
));
501 x1
= (float)t
->a
.t
.x
; y1
= (float)t
->a
.t
.y
;
502 x2
= (float)t
->b
.t
.x
; y2
= (float)t
->b
.t
.y
;
503 x3
= (float)t
->c
.t
.x
; y3
= (float)t
->c
.t
.y
;
504 _DO_OR_DONE(fwrite(&x1
, sizeof(float), 1, file
));
505 _DO_OR_DONE(fwrite(&y1
, sizeof(float), 1, file
));
506 _DO_OR_DONE(fwrite(&x2
, sizeof(float), 1, file
));
507 _DO_OR_DONE(fwrite(&y2
, sizeof(float), 1, file
));
508 _DO_OR_DONE(fwrite(&x3
, sizeof(float), 1, file
));
509 _DO_OR_DONE(fwrite(&y3
, sizeof(float), 1, file
));
This page took 0.060823 seconds and 4 git commands to generate.