]>
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
);
30 static int _model_read_raw(model_t
* m
, const char* filename
);
31 static int _model_read_obj(model_t
* m
, const char* filename
);
33 static int _model_try_read_cache(const char* filename
, list_t
** l
);
34 static void _model_write_cache(const char* filename
, int count
, list_t
* l
);
37 model_t
* model_alloc(const char* filename
)
40 char* ext
= strrchr(filename
, '.');
46 if (strcmp(ext
, "raw") == 0) {
47 return model_alloc2(filename
, MODEL_TYPE_RAW
);
49 if (strcmp(ext
, "obj") == 0) {
50 return model_alloc2(filename
, MODEL_TYPE_OBJ
);
54 fprintf(stderr
, "Unknown file type: %s", filename
);
58 model_t
* model_alloc2(const char* filename
, int type
)
60 model_t
* m
= (model_t
*)mem_alloc(sizeof(model_t
));
62 m
->model
= MAT_IDENTITY
;
63 m
->specular
= COLOR_WHITE
;
64 m
->shininess
= S(64.0);
65 m
->name
= mem_strdup(filename
);
69 int count
= _model_try_read_cache(filename
, &m
->triangles
);
78 load
= _model_read_raw(m
, filename
);
81 load
= _model_read_obj(m
, filename
);
90 _model_write_cache(filename
, m
->count
, m
->triangles
);
96 void model_destroy(model_t
* m
)
98 list_destroy(&m
->triangles
);
104 const list_t
* model_geometry(const model_t
* m
)
109 int model_size(const model_t
* m
)
114 const char* model_name(const model_t
* m
)
119 color_t
model_specular(const model_t
* m
)
124 scal_t
model_shininess(const model_t
* m
)
129 void model_transformation(const model_t
* m
, mat_t
* transform
)
131 *transform
= m
->model
;
135 void model_transform(model_t
* m
, const mat_t
* transform
)
137 m
->model
= mat_mult(m
->model
, *transform
);
140 void model_material(model_t
* m
, color_t specular
, scal_t shininess
)
142 m
->specular
= specular
;
143 m
->shininess
= shininess
;
150 DEFINE_MAP_TYPE3(vec_t
, list_t
*, vnorm
, vec_compare(*a
, *b
));
154 * Associate a triangle with one of its vertices.
156 static void _find_normals_add_vertex(map_t
* m
, vec_t v
, tri_t
* t
)
158 list_t
** l
= map_vnorm_search(m
, v
);
160 map_vnorm_data_t
* d
= map_vnorm_insert(m
, v
, NULL
);
167 * Associate a triangle with all of its vertices.
169 static void _find_normals_add_triangle(map_t
* m
, tri_t
* t
)
171 _find_normals_add_vertex(m
, t
->a
.v
, t
);
172 _find_normals_add_vertex(m
, t
->b
.v
, t
);
173 _find_normals_add_vertex(m
, t
->c
.v
, t
);
177 * Calculate an averaged normal from a list of triangles that share a common
180 static void _find_normals_average(const vec_t
* v
, list_t
** l
)
182 // first, compute the average normal
184 for (list_t
* i
= *l
; i
; i
= i
->link
) {
185 tri_t
* t
= (tri_t
*)i
->val
;
186 n
= vec_add(n
, tri_normal(*t
));
188 n
= vec_normalize(n
);
190 // set the normal on each triangle's vertex that is shared
192 tri_t
* t
= (tri_t
*)(*l
)->val
;
193 if (vec_isequal(*v
, t
->a
.v
)) {
196 else if (vec_isequal(*v
, t
->b
.v
)) {
199 else if (vec_isequal(*v
, t
->c
.v
)) {
206 #endif // CALC_NORMALS
209 static int _model_read_raw(model_t
* m
, const char* filename
)
211 FILE* file
= fopen(filename
, "r");
213 fprintf(stderr
, "Cannot read %s: %s\n", filename
, strerror(errno
));
218 map_t
* nlookup
= map_vnorm_alloc();
221 double x1
, y1
, z1
, x2
, y2
, z2
, x3
, y3
, z3
;
222 while (fscanf(file
, " %lf %lf %lf %lf %lf %lf %lf %lf %lf",
223 &x1
, &y1
, &z1
, &x2
, &y2
, &z2
, &x3
, &y3
, &z3
) == 9) {
224 tri_t
* t
= tri_alloc(
225 vert_new2((scal_t
)x1
, (scal_t
)y1
, (scal_t
)z1
),
226 vert_new2((scal_t
)x2
, (scal_t
)y2
, (scal_t
)z2
),
227 vert_new2((scal_t
)x3
, (scal_t
)y3
, (scal_t
)z3
)
229 list_push2(&m
->triangles
, t
, mem_free
);
233 _find_normals_add_triangle(nlookup
, t
);
235 vec_t n
= vec_normalize(tri_normal(*t
));
243 map_vnorm_call(nlookup
, _find_normals_average
);
244 rbtree_destroy(nlookup
);
248 if (m
->triangles
== NULL
) {
249 fprintf(stderr
, "No triangles read from %s\n", filename
);
255 static int _model_read_obj(model_t
* m
, const char* filename
)
257 FILE* file
= fopen(filename
, "r");
259 fprintf(stderr
, "Cannot read %s: %s\n", filename
, strerror(errno
));
264 map_t
* nlookup
= map_vnorm_alloc();
267 array_t
* v
= array_vec_alloc();
268 array_t
* vt
= array_vec_alloc();
269 array_t
* vn
= array_vec_alloc();
271 array_vec_push(v
, VEC_ZERO
);
272 array_vec_push(vt
, VEC_ZERO
);
273 array_vec_push(vn
, VEC_ZERO
);
276 while (fgets(line
, 4096, file
)) {
278 double f1
, f2
, f3
, f4
;
280 int i1
, i2
, i3
, i4
, i5
, i6
, i7
, i8
, i9
;
281 if (sscanf(line
, "v %lf %lf %lf %lf ", &f1
, &f2
, &f3
, &f4
) == 4) {
282 array_vec_push(v
, vec_new2((scal_t
)f1
, (scal_t
)f2
, (scal_t
)f3
, (scal_t
)f4
));
284 else if (sscanf(line
, "v %lf %lf %lf ", &f1
, &f2
, &f3
) == 3) {
285 array_vec_push(v
, vec_new((scal_t
)f1
, (scal_t
)f2
, (scal_t
)f3
));
287 else if (sscanf(line
, "vt %lf %lf ", &f1
, &f2
) == 2) {
288 array_vec_push(vt
, vec_new((scal_t
)f1
, (scal_t
)f2
, S(0.0)));
290 else if (sscanf(line
, "vn %lf %lf %lf ", &f1
, &f2
, &f3
) == 3) {
291 array_vec_push(vn
, vec_new((scal_t
)f1
, (scal_t
)f2
, (scal_t
)f3
));
293 else if (sscanf(line
, "f %d %d %d ", &i1
, &i2
, &i3
) == 3) {
294 tri_t
* t
= tri_alloc(
295 vert_new(*array_vec_index(v
, i1
)),
296 vert_new(*array_vec_index(v
, i2
)),
297 vert_new(*array_vec_index(v
, i3
))
299 list_push2(&m
->triangles
, t
, mem_free
);
303 _find_normals_add_triangle(nlookup
, t
);
305 vec_t n
= vec_normalize(tri_normal(*t
));
311 else if (sscanf(line
, "f %d/%d %d/%d %d/%d ", &i1
, &i4
, &i2
, &i4
, &i3
, &i4
) == 6) {
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 ",
330 &i1
, &i2
, &i3
, &i4
, &i5
, &i6
) == 6) {
331 tri_t
* t
= tri_alloc(
332 vert_new(*array_vec_index(v
, i1
)),
333 vert_new(*array_vec_index(v
, i3
)),
334 vert_new(*array_vec_index(v
, i5
))
336 list_push2(&m
->triangles
, t
, mem_free
);
338 t
->a
.n
= *array_vec_index(vn
, i2
);
339 t
->b
.n
= *array_vec_index(vn
, i4
);
340 t
->c
.n
= *array_vec_index(vn
, i6
);
342 else if (sscanf(line
, "f %d/%d/%d %d/%d/%d %d/%d/%d ",
343 &i1
, &meh
, &i2
, &i3
, &meh
, &i4
, &i5
, &meh
, &i6
) == 9) {
344 tri_t
* t
= tri_alloc(
345 vert_new(*array_vec_index(v
, i1
)),
346 vert_new(*array_vec_index(v
, i3
)),
347 vert_new(*array_vec_index(v
, i5
))
349 list_push2(&m
->triangles
, t
, mem_free
);
351 t
->a
.n
= *array_vec_index(vn
, i2
);
352 t
->b
.n
= *array_vec_index(vn
, i4
);
353 t
->c
.n
= *array_vec_index(vn
, i6
);
356 // f 1/2/3 4/5/6 7/8/9
364 map_vnorm_call(nlookup
, _find_normals_average
);
365 rbtree_destroy(nlookup
);
369 if (m
->triangles
== NULL
) {
370 fprintf(stderr
, "No triangles read from %s\n", filename
);
377 #define _CHECK_IO(X) if ((X) <= 0) goto fail
380 * Try to read the triangle geometry from the cache file.
382 static int _model_try_read_cache(const char* filename
, list_t
** l
)
385 char* cachename
= mem_strcat(".", filename
);
386 FILE* file
= fopen(cachename
, "rb");
391 _CHECK_IO(fread(&count
, sizeof(count
), 1, file
));
393 float x1
, y1
, z1
, x2
, y2
, z2
, x3
, y3
, z3
;
394 for (int i
= 0; i
< count
; ++i
) {
395 _CHECK_IO(fread(&x1
, sizeof(float), 1, file
));
396 _CHECK_IO(fread(&y1
, sizeof(float), 1, file
));
397 _CHECK_IO(fread(&z1
, sizeof(float), 1, file
));
398 _CHECK_IO(fread(&x2
, sizeof(float), 1, file
));
399 _CHECK_IO(fread(&y2
, sizeof(float), 1, file
));
400 _CHECK_IO(fread(&z2
, sizeof(float), 1, file
));
401 _CHECK_IO(fread(&x3
, sizeof(float), 1, file
));
402 _CHECK_IO(fread(&y3
, sizeof(float), 1, file
));
403 _CHECK_IO(fread(&z3
, sizeof(float), 1, file
));
404 tri_t
* t
= tri_alloc(
405 vert_new2((scal_t
)x1
, (scal_t
)y1
, (scal_t
)z1
),
406 vert_new2((scal_t
)x2
, (scal_t
)y2
, (scal_t
)z2
),
407 vert_new2((scal_t
)x3
, (scal_t
)y3
, (scal_t
)z3
)
409 list_push2(l
, t
, mem_free
);
410 _CHECK_IO(fread(&x1
, sizeof(float), 1, file
));
411 _CHECK_IO(fread(&y1
, sizeof(float), 1, file
));
412 _CHECK_IO(fread(&z1
, sizeof(float), 1, file
));
413 _CHECK_IO(fread(&x2
, sizeof(float), 1, file
));
414 _CHECK_IO(fread(&y2
, sizeof(float), 1, file
));
415 _CHECK_IO(fread(&z2
, sizeof(float), 1, file
));
416 _CHECK_IO(fread(&x3
, sizeof(float), 1, file
));
417 _CHECK_IO(fread(&y3
, sizeof(float), 1, file
));
418 _CHECK_IO(fread(&z3
, sizeof(float), 1, file
));
419 t
->a
.n
= vec_new((scal_t
)x1
, (scal_t
)y1
, (scal_t
)z1
);
420 t
->b
.n
= vec_new((scal_t
)x2
, (scal_t
)y2
, (scal_t
)z2
);
421 t
->c
.n
= vec_new((scal_t
)x3
, (scal_t
)y3
, (scal_t
)z3
);
434 * Write the triangle data to the cache.
436 static void _model_write_cache(const char* filename
, int count
, list_t
* l
)
438 char* cachename
= mem_strcat(".", filename
);
439 FILE* file
= fopen(cachename
, "wb");
441 fprintf(stderr
, "Cannot write %s: %s\n", cachename
, strerror(errno
));
445 _CHECK_IO(fwrite(&count
, sizeof(count
), 1, file
));
446 for (list_t
* i
= l
; i
; i
= i
->link
) {
447 tri_t
* t
= (tri_t
*)i
->val
;
448 _CHECK_IO(fwrite(&t
->a
.v
.x
, sizeof(float), 1, file
));
449 _CHECK_IO(fwrite(&t
->a
.v
.y
, sizeof(float), 1, file
));
450 _CHECK_IO(fwrite(&t
->a
.v
.z
, sizeof(float), 1, file
));
451 _CHECK_IO(fwrite(&t
->b
.v
.x
, sizeof(float), 1, file
));
452 _CHECK_IO(fwrite(&t
->b
.v
.y
, sizeof(float), 1, file
));
453 _CHECK_IO(fwrite(&t
->b
.v
.z
, sizeof(float), 1, file
));
454 _CHECK_IO(fwrite(&t
->c
.v
.x
, sizeof(float), 1, file
));
455 _CHECK_IO(fwrite(&t
->c
.v
.y
, sizeof(float), 1, file
));
456 _CHECK_IO(fwrite(&t
->c
.v
.z
, sizeof(float), 1, file
));
457 _CHECK_IO(fwrite(&t
->a
.n
.x
, sizeof(float), 1, file
));
458 _CHECK_IO(fwrite(&t
->a
.n
.y
, sizeof(float), 1, file
));
459 _CHECK_IO(fwrite(&t
->a
.n
.z
, sizeof(float), 1, file
));
460 _CHECK_IO(fwrite(&t
->b
.n
.x
, sizeof(float), 1, file
));
461 _CHECK_IO(fwrite(&t
->b
.n
.y
, sizeof(float), 1, file
));
462 _CHECK_IO(fwrite(&t
->b
.n
.z
, sizeof(float), 1, file
));
463 _CHECK_IO(fwrite(&t
->c
.n
.x
, sizeof(float), 1, file
));
464 _CHECK_IO(fwrite(&t
->c
.n
.y
, sizeof(float), 1, file
));
465 _CHECK_IO(fwrite(&t
->c
.n
.z
, sizeof(float), 1, file
));
This page took 0.056149 seconds and 4 git commands to generate.