]> Dogcows Code - chaz/rasterize/blob - model.c
refactor triangle group into a separate class
[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 "tri.h"
11 #include "model.h"
12
13
14 struct model
15 {
16 list_t* triangles;
17 mat_t model;
18 color_t specular;
19 scal_t shininess;
20 char* name;
21 int count;
22 };
23
24
25 static int _model_read_raw(model_t* m, const char* filename);
26 static int _model_read_obj(model_t* m, const char* filename);
27
28 static int _model_try_read_cache(const char* filename, list_t** l);
29 static void _model_write_cache(const char* filename, int count, list_t* l);
30
31
32 model_t* model_alloc(const char* filename)
33 {
34 int type = 0;
35 char* ext = strrchr(filename, '.');
36 if (ext == NULL) {
37 goto fail;
38 }
39 ++ext;
40
41 if (strcmp(ext, "raw") == 0) {
42 return model_alloc2(filename, MODEL_TYPE_RAW);
43 }
44 if (strcmp(ext, "obj") == 0) {
45 return model_alloc2(filename, MODEL_TYPE_OBJ);
46 }
47
48 fail:
49 fprintf(stderr, "Unknown file type: %s", filename);
50 return NULL;
51 }
52
53 model_t* model_alloc2(const char* filename, int type)
54 {
55 model_t* m = (model_t*)mem_alloc(sizeof(model_t));
56 m->triangles = NULL;
57 m->model = MAT_IDENTITY;
58 m->specular = COLOR_WHITE;
59 m->shininess = S(64.0);
60 m->name = mem_strdup(filename);
61 m->count = 0;
62
63 #if CACHE_GEOMETRY
64 int count = _model_try_read_cache(filename, &m->triangles);
65 if (0 < count) {
66 return m;
67 }
68 #endif
69
70 int load;
71 switch (type) {
72 case MODEL_TYPE_RAW:
73 load = _model_read_raw(m, filename);
74 break;
75 case MODEL_TYPE_OBJ:
76 load = _model_read_obj(m, filename);
77 break;
78 }
79 if (load != 0) {
80 model_destroy(m);
81 return NULL;
82 }
83
84 #if CACHE_GEOMETRY
85 _model_write_cache(filename, m->count, m->triangles);
86 #endif
87
88 return m;
89 }
90
91 void model_destroy(model_t* m)
92 {
93 list_destroy(&m->triangles);
94 mem_free(m->name);
95 mem_free(m);
96 }
97
98
99 const list_t* model_geometry(const model_t* m)
100 {
101 return m->triangles;
102 }
103
104 int model_size(const model_t* m)
105 {
106 return m->count;
107 }
108
109 const char* model_name(const model_t* m)
110 {
111 return m->name;
112 }
113
114 color_t model_specular(const model_t* m)
115 {
116 return m->specular;
117 }
118
119 scal_t model_shininess(const model_t* m)
120 {
121 return m->shininess;
122 }
123
124 void model_transformation(const model_t* m, mat_t* transform)
125 {
126 *transform = m->model;
127 }
128
129
130 void model_transform(model_t* m, const mat_t* transform)
131 {
132 m->model = mat_mult(m->model, *transform);
133 }
134
135 void model_material(model_t* m, color_t specular, scal_t shininess)
136 {
137 m->specular = specular;
138 m->shininess = shininess;
139 }
140
141
142 #if CALC_NORMALS
143
144 #include "map.h"
145 DECLARE_AND_DEFINE_MAP_TYPE3(vec_t, list_t*, vnorm, vec_compare(*a, *b));
146
147
148 /*
149 * Associate a triangle with one of its vertices.
150 */
151 static void _find_normals_add_vertex(map_t* m, vec_t v, tri_t* t)
152 {
153 list_t** l = map_vnorm_search(m, v);
154 if (l == NULL) {
155 map_vnorm_data_t* d = map_vnorm_insert(m, v, NULL);
156 l = &d->val;
157 }
158 list_push(l, t);
159 }
160
161 /*
162 * Associate a triangle with all of its vertices.
163 */
164 static void _find_normals_add_triangle(map_t* m, tri_t* t)
165 {
166 _find_normals_add_vertex(m, t->a.v, t);
167 _find_normals_add_vertex(m, t->b.v, t);
168 _find_normals_add_vertex(m, t->c.v, t);
169 }
170
171 /*
172 * Calculate an averaged normal from a list of triangles that share a common
173 * vertex.
174 */
175 static void _find_normals_average(const vec_t* v, list_t** l)
176 {
177 // first, compute the average normal
178 vec_t n = VEC_ZERO;
179 for (list_t* i = *l; i; i = i->link) {
180 tri_t* t = (tri_t*)i->val;
181 n = vec_add(n, tri_normal(*t));
182 }
183 n = vec_normalize(n);
184
185 // set the normal on each triangle's vertex that is shared
186 while (*l) {
187 tri_t* t = (tri_t*)(*l)->val;
188 if (vec_isequal(*v, t->a.v)) {
189 t->a.n = n;
190 }
191 else if (vec_isequal(*v, t->b.v)) {
192 t->b.n = n;
193 }
194 else if (vec_isequal(*v, t->c.v)) {
195 t->c.n = n;
196 }
197 list_pop(l);
198 }
199 }
200
201 #endif // CALC_NORMALS
202
203
204 static int _model_read_raw(model_t* m, const char* filename)
205 {
206 FILE* file = fopen(filename, "r");
207 if (file == NULL) {
208 fprintf(stderr, "Cannot read %s: %s\n", filename, strerror(errno));
209 return -1;
210 }
211
212 #if CALC_NORMALS
213 map_t* nlookup = map_vnorm_alloc();
214 #endif
215
216 double x1, y1, z1, x2, y2, z2, x3, y3, z3;
217 while (fscanf(file, " %lf %lf %lf %lf %lf %lf %lf %lf %lf",
218 &x1, &y1, &z1, &x2, &y2, &z2, &x3, &y3, &z3) == 9) {
219 tri_t* t = tri_alloc(
220 vert_new2((scal_t)x1, (scal_t)y1, (scal_t)z1),
221 vert_new2((scal_t)x2, (scal_t)y2, (scal_t)z2),
222 vert_new2((scal_t)x3, (scal_t)y3, (scal_t)z3)
223 );
224 list_push2(&m->triangles, t, mem_free);
225 ++m->count;
226
227 #if CALC_NORMALS
228 _find_normals_add_triangle(nlookup, t);
229 #else
230 vec_t n = vec_normalize(tri_normal(*t));
231 t->a.n = n;
232 t->b.n = n;
233 t->c.n = n;
234 #endif
235 }
236
237 #if CALC_NORMALS
238 map_vnorm_call(nlookup, _find_normals_average);
239 rbtree_destroy(nlookup);
240 #endif
241
242 fclose(file);
243 if (m->triangles == NULL) {
244 fprintf(stderr, "No triangles read from %s\n", filename);
245 return -1;
246 }
247 return 0;
248 }
249
250 static int _model_read_obj(model_t* m, const char* filename)
251 {
252 }
253
254
255 #define _CHECK_IO(X) if ((X) <= 0) goto fail
256
257 /*
258 * Try to read the triangle geometry from the cache file.
259 */
260 static int _model_try_read_cache(const char* filename, list_t** l)
261 {
262 int count = 0;
263 char* cachename = mem_strcat(".", filename);
264 FILE* file = fopen(cachename, "rb");
265 if (file == NULL) {
266 goto fail;
267 }
268
269 _CHECK_IO(fread(&count, sizeof(count), 1, file));
270
271 float x1, y1, z1, x2, y2, z2, x3, y3, z3;
272 for (int i = 0; i < count; ++i) {
273 _CHECK_IO(fread(&x1, sizeof(float), 1, file));
274 _CHECK_IO(fread(&y1, sizeof(float), 1, file));
275 _CHECK_IO(fread(&z1, sizeof(float), 1, file));
276 _CHECK_IO(fread(&x2, sizeof(float), 1, file));
277 _CHECK_IO(fread(&y2, sizeof(float), 1, file));
278 _CHECK_IO(fread(&z2, sizeof(float), 1, file));
279 _CHECK_IO(fread(&x3, sizeof(float), 1, file));
280 _CHECK_IO(fread(&y3, sizeof(float), 1, file));
281 _CHECK_IO(fread(&z3, sizeof(float), 1, file));
282 tri_t* t = tri_alloc(
283 vert_new2((scal_t)x1, (scal_t)y1, (scal_t)z1),
284 vert_new2((scal_t)x2, (scal_t)y2, (scal_t)z2),
285 vert_new2((scal_t)x3, (scal_t)y3, (scal_t)z3)
286 );
287 list_push2(l, t, mem_free);
288 _CHECK_IO(fread(&x1, sizeof(float), 1, file));
289 _CHECK_IO(fread(&y1, sizeof(float), 1, file));
290 _CHECK_IO(fread(&z1, sizeof(float), 1, file));
291 _CHECK_IO(fread(&x2, sizeof(float), 1, file));
292 _CHECK_IO(fread(&y2, sizeof(float), 1, file));
293 _CHECK_IO(fread(&z2, sizeof(float), 1, file));
294 _CHECK_IO(fread(&x3, sizeof(float), 1, file));
295 _CHECK_IO(fread(&y3, sizeof(float), 1, file));
296 _CHECK_IO(fread(&z3, sizeof(float), 1, file));
297 t->a.n = vec_new((scal_t)x1, (scal_t)y1, (scal_t)z1);
298 t->b.n = vec_new((scal_t)x2, (scal_t)y2, (scal_t)z2);
299 t->c.n = vec_new((scal_t)x3, (scal_t)y3, (scal_t)z3);
300 }
301
302 fail:
303 mem_free(cachename);
304 if (file != NULL) {
305 fclose(file);
306 }
307
308 return count;
309 }
310
311 /*
312 * Write the triangle data to the cache.
313 */
314 static void _model_write_cache(const char* filename, int count, list_t* l)
315 {
316 char* cachename = mem_strcat(".", filename);
317 FILE* file = fopen(cachename, "wb");
318 if (file == NULL) {
319 fprintf(stderr, "Cannot write %s: %s\n", cachename, strerror(errno));
320 goto fail;
321 }
322
323 _CHECK_IO(fwrite(&count, sizeof(count), 1, file));
324 for (list_t* i = l; i; i = i->link) {
325 tri_t* t = (tri_t*)i->val;
326 _CHECK_IO(fwrite(&t->a.v.x, sizeof(float), 1, file));
327 _CHECK_IO(fwrite(&t->a.v.y, sizeof(float), 1, file));
328 _CHECK_IO(fwrite(&t->a.v.z, sizeof(float), 1, file));
329 _CHECK_IO(fwrite(&t->b.v.x, sizeof(float), 1, file));
330 _CHECK_IO(fwrite(&t->b.v.y, sizeof(float), 1, file));
331 _CHECK_IO(fwrite(&t->b.v.z, sizeof(float), 1, file));
332 _CHECK_IO(fwrite(&t->c.v.x, sizeof(float), 1, file));
333 _CHECK_IO(fwrite(&t->c.v.y, sizeof(float), 1, file));
334 _CHECK_IO(fwrite(&t->c.v.z, sizeof(float), 1, file));
335 _CHECK_IO(fwrite(&t->a.n.x, sizeof(float), 1, file));
336 _CHECK_IO(fwrite(&t->a.n.y, sizeof(float), 1, file));
337 _CHECK_IO(fwrite(&t->a.n.z, sizeof(float), 1, file));
338 _CHECK_IO(fwrite(&t->b.n.x, sizeof(float), 1, file));
339 _CHECK_IO(fwrite(&t->b.n.y, sizeof(float), 1, file));
340 _CHECK_IO(fwrite(&t->b.n.z, sizeof(float), 1, file));
341 _CHECK_IO(fwrite(&t->c.n.x, sizeof(float), 1, file));
342 _CHECK_IO(fwrite(&t->c.n.y, sizeof(float), 1, file));
343 _CHECK_IO(fwrite(&t->c.n.z, sizeof(float), 1, file));
344 }
345
346 fail:
347 mem_free(cachename);
348 if (file != NULL) {
349 fclose(file);
350 }
351 }
352
353 #undef _CHECK_IO
354
355
This page took 0.046772 seconds and 4 git commands to generate.