Mercurial > pidgin
comparison plugins/crazychat/glm.c @ 11218:ed017b9c532d
[gaim-migrate @ 13350]
crazychat commit, first one.
committer: Tailor Script <tailor@pidgin.im>
author | Charlie Stockman <chuckleberry> |
---|---|
date | Tue, 09 Aug 2005 07:10:23 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
11217:f854402837ba | 11218:ed017b9c532d |
---|---|
1 /* | |
2 glm.c | |
3 Nate Robins, 1997 | |
4 ndr@pobox.com, http://www.pobox.com/~ndr/ | |
5 | |
6 Wavefront OBJ model file format reader/writer/manipulator. | |
7 | |
8 Includes routines for generating smooth normals with | |
9 preservation of edges, welding redundant vertices & texture | |
10 coordinate generation (spheremap and planar projections) + more. | |
11 | |
12 */ | |
13 | |
14 | |
15 #include <math.h> | |
16 #include <stdio.h> | |
17 #include <stdlib.h> | |
18 #include <string.h> | |
19 #include <assert.h> | |
20 #include "glm.h" | |
21 | |
22 | |
23 #define T(x) (model->triangles[(x)]) | |
24 | |
25 | |
26 /* _GLMnode: general purpose node | |
27 */ | |
28 typedef struct _GLMnode { | |
29 GLuint index; | |
30 GLboolean averaged; | |
31 struct _GLMnode* next; | |
32 } GLMnode; | |
33 | |
34 | |
35 /* glmMax: returns the maximum of two floats */ | |
36 static GLfloat | |
37 glmMax(GLfloat a, GLfloat b) | |
38 { | |
39 if (b > a) | |
40 return b; | |
41 return a; | |
42 } | |
43 | |
44 /* glmAbs: returns the absolute value of a float */ | |
45 static GLfloat | |
46 glmAbs(GLfloat f) | |
47 { | |
48 if (f < 0) | |
49 return -f; | |
50 return f; | |
51 } | |
52 | |
53 /* glmDot: compute the dot product of two vectors | |
54 * | |
55 * u - array of 3 GLfloats (GLfloat u[3]) | |
56 * v - array of 3 GLfloats (GLfloat v[3]) | |
57 */ | |
58 static GLfloat | |
59 glmDot(GLfloat* u, GLfloat* v) | |
60 { | |
61 assert(u); assert(v); | |
62 | |
63 return u[0]*v[0] + u[1]*v[1] + u[2]*v[2]; | |
64 } | |
65 | |
66 /* glmCross: compute the cross product of two vectors | |
67 * | |
68 * u - array of 3 GLfloats (GLfloat u[3]) | |
69 * v - array of 3 GLfloats (GLfloat v[3]) | |
70 * n - array of 3 GLfloats (GLfloat n[3]) to return the cross product in | |
71 */ | |
72 static GLvoid | |
73 glmCross(GLfloat* u, GLfloat* v, GLfloat* n) | |
74 { | |
75 assert(u); assert(v); assert(n); | |
76 | |
77 n[0] = u[1]*v[2] - u[2]*v[1]; | |
78 n[1] = u[2]*v[0] - u[0]*v[2]; | |
79 n[2] = u[0]*v[1] - u[1]*v[0]; | |
80 } | |
81 | |
82 /* glmNormalize: normalize a vector | |
83 * | |
84 * v - array of 3 GLfloats (GLfloat v[3]) to be normalized | |
85 */ | |
86 static GLvoid | |
87 glmNormalize(GLfloat* v) | |
88 { | |
89 GLfloat l; | |
90 | |
91 assert(v); | |
92 | |
93 l = (GLfloat)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); | |
94 v[0] /= l; | |
95 v[1] /= l; | |
96 v[2] /= l; | |
97 } | |
98 | |
99 /* glmEqual: compares two vectors and returns GL_TRUE if they are | |
100 * equal (within a certain threshold) or GL_FALSE if not. An epsilon | |
101 * that works fairly well is 0.000001. | |
102 * | |
103 * u - array of 3 GLfloats (GLfloat u[3]) | |
104 * v - array of 3 GLfloats (GLfloat v[3]) | |
105 */ | |
106 static GLboolean | |
107 glmEqual(GLfloat* u, GLfloat* v, GLfloat epsilon) | |
108 { | |
109 if (glmAbs(u[0] - v[0]) < epsilon && | |
110 glmAbs(u[1] - v[1]) < epsilon && | |
111 glmAbs(u[2] - v[2]) < epsilon) | |
112 { | |
113 return GL_TRUE; | |
114 } | |
115 return GL_FALSE; | |
116 } | |
117 | |
118 /* glmWeldVectors: eliminate (weld) vectors that are within an | |
119 * epsilon of each other. | |
120 * | |
121 * vectors - array of GLfloat[3]'s to be welded | |
122 * numvectors - number of GLfloat[3]'s in vectors | |
123 * epsilon - maximum difference between vectors | |
124 * | |
125 */ | |
126 GLfloat* | |
127 glmWeldVectors(GLfloat* vectors, GLuint* numvectors, GLfloat epsilon) | |
128 { | |
129 GLfloat* copies; | |
130 GLuint copied; | |
131 GLuint i, j; | |
132 | |
133 copies = (GLfloat*)malloc(sizeof(GLfloat) * 3 * (*numvectors + 1)); | |
134 memcpy(copies, vectors, (sizeof(GLfloat) * 3 * (*numvectors + 1))); | |
135 | |
136 copied = 1; | |
137 for (i = 1; i <= *numvectors; i++) { | |
138 for (j = 1; j <= copied; j++) { | |
139 if (glmEqual(&vectors[3 * i], &copies[3 * j], epsilon)) { | |
140 goto duplicate; | |
141 } | |
142 } | |
143 | |
144 /* must not be any duplicates -- add to the copies array */ | |
145 copies[3 * copied + 0] = vectors[3 * i + 0]; | |
146 copies[3 * copied + 1] = vectors[3 * i + 1]; | |
147 copies[3 * copied + 2] = vectors[3 * i + 2]; | |
148 j = copied; /* pass this along for below */ | |
149 copied++; | |
150 | |
151 duplicate: | |
152 /* set the first component of this vector to point at the correct | |
153 index into the new copies array */ | |
154 vectors[3 * i + 0] = (GLfloat)j; | |
155 } | |
156 | |
157 *numvectors = copied-1; | |
158 return copies; | |
159 } | |
160 | |
161 /* glmFindGroup: Find a group in the model | |
162 */ | |
163 GLMgroup* | |
164 glmFindGroup(GLMmodel* model, char* name) | |
165 { | |
166 GLMgroup* group; | |
167 | |
168 assert(model); | |
169 | |
170 group = model->groups; | |
171 while(group) { | |
172 if (!strcmp(name, group->name)) | |
173 break; | |
174 group = group->next; | |
175 } | |
176 | |
177 return group; | |
178 } | |
179 | |
180 /* glmAddGroup: Add a group to the model | |
181 */ | |
182 GLMgroup* | |
183 glmAddGroup(GLMmodel* model, char* name) | |
184 { | |
185 GLMgroup* group; | |
186 | |
187 group = glmFindGroup(model, name); | |
188 if (!group) { | |
189 group = (GLMgroup*)malloc(sizeof(GLMgroup)); | |
190 group->name = strdup(name); | |
191 group->material = 0; | |
192 group->numtriangles = 0; | |
193 group->triangles = NULL; | |
194 group->next = model->groups; | |
195 model->groups = group; | |
196 model->numgroups++; | |
197 } | |
198 | |
199 return group; | |
200 } | |
201 | |
202 /* glmFindGroup: Find a material in the model | |
203 */ | |
204 GLuint | |
205 glmFindMaterial(GLMmodel* model, char* name) | |
206 { | |
207 GLuint i; | |
208 | |
209 /* XXX doing a linear search on a string key'd list is pretty lame, | |
210 but it works and is fast enough for now. */ | |
211 for (i = 0; i < model->nummaterials; i++) { | |
212 if (!strcmp(model->materials[i].name, name)) | |
213 goto found; | |
214 } | |
215 | |
216 /* didn't find the name, so print a warning and return the default | |
217 material (0). */ | |
218 //fprintf(stderr, "glmFindMaterial(): can't find material \"%s\".\n", name); | |
219 i = 0; | |
220 | |
221 found: | |
222 return i; | |
223 } | |
224 | |
225 | |
226 /* glmDirName: return the directory given a path | |
227 * | |
228 * path - filesystem path | |
229 * | |
230 * NOTE: the return value should be free'd. | |
231 */ | |
232 static char* | |
233 glmDirName(char* path) | |
234 { | |
235 char* dir; | |
236 char* s; | |
237 | |
238 dir = strdup(path); | |
239 | |
240 s = strrchr(dir, '/'); | |
241 if (s) | |
242 s[1] = '\0'; | |
243 else | |
244 dir[0] = '\0'; | |
245 | |
246 return dir; | |
247 } | |
248 | |
249 | |
250 void glmSetMat(GLMmat_str* mats, GLint index){ | |
251 GLMmaterial* material; | |
252 assert(!(index<0 || index >=mats->num_materials)); | |
253 material = &mats->materials[index]; | |
254 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient); | |
255 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse); | |
256 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material->specular); | |
257 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material->shininess); | |
258 } | |
259 | |
260 | |
261 GLMmat_str* glmMTL(char* name){ | |
262 FILE* file; | |
263 char* dir; | |
264 char* filename; | |
265 char buf[128]; | |
266 GLuint nummaterials, i; | |
267 GLMmat_str* ret; | |
268 | |
269 file = fopen(name, "r"); | |
270 if (!file) { | |
271 fprintf(stderr, "glmReadMTL() failed: can't open material file \"%s\".\n", | |
272 name); | |
273 exit(1); | |
274 } | |
275 | |
276 /* count the number of materials in the file */ | |
277 nummaterials = 1; | |
278 while(fscanf(file, "%s", buf) != EOF) { | |
279 switch(buf[0]) { | |
280 case '#': /* comment */ | |
281 /* eat up rest of line */ | |
282 fgets(buf, sizeof(buf), file); | |
283 break; | |
284 case 'n': /* newmtl */ | |
285 fgets(buf, sizeof(buf), file); | |
286 nummaterials++; | |
287 sscanf(buf, "%s %s", buf, buf); | |
288 break; | |
289 default: | |
290 /* eat up rest of line */ | |
291 fgets(buf, sizeof(buf), file); | |
292 break; | |
293 } | |
294 } | |
295 | |
296 rewind(file); | |
297 | |
298 ret = (GLMmat_str*)malloc(sizeof(GLMmat_str)); | |
299 ret->materials = (GLMmaterial*)malloc(sizeof(GLMmaterial) * nummaterials); | |
300 ret->num_materials = nummaterials; | |
301 | |
302 /* set the default material */ | |
303 for (i = 0; i < nummaterials; i++) { | |
304 ret->materials[i].name = NULL; | |
305 ret->materials[i].shininess = 65.0; | |
306 ret->materials[i].diffuse[0] = 0.8; | |
307 ret->materials[i].diffuse[1] = 0.1; | |
308 ret->materials[i].diffuse[2] = 0.1; | |
309 ret->materials[i].diffuse[3] = 1.0; | |
310 ret->materials[i].ambient[0] = 0.2; | |
311 ret->materials[i].ambient[1] = 0.2; | |
312 ret->materials[i].ambient[2] = 0.2; | |
313 ret->materials[i].ambient[3] = 1.0; | |
314 ret->materials[i].specular[0] = 0.0; | |
315 ret->materials[i].specular[1] = 0.0; | |
316 ret->materials[i].specular[2] = 0.0; | |
317 ret->materials[i].specular[3] = 1.0; | |
318 } | |
319 ret->materials[0].name = strdup("default"); | |
320 | |
321 /* now, read in the data */ | |
322 nummaterials = 0; | |
323 while(fscanf(file, "%s", buf) != EOF) { | |
324 switch(buf[0]) { | |
325 case '#': /* comment */ | |
326 /* eat up rest of line */ | |
327 fgets(buf, sizeof(buf), file); | |
328 break; | |
329 case 'n': /* newmtl */ | |
330 fgets(buf, sizeof(buf), file); | |
331 sscanf(buf, "%s %s", buf, buf); | |
332 nummaterials++; | |
333 ret->materials[nummaterials].name = strdup(buf); | |
334 break; | |
335 case 'N': | |
336 fscanf(file, "%f", &ret->materials[nummaterials].shininess); | |
337 /* wavefront shininess is from [0, 1000], so scale for OpenGL */ | |
338 ret->materials[nummaterials].shininess /= 1000.0; | |
339 ret->materials[nummaterials].shininess *= 128.0; | |
340 break; | |
341 case 'K': | |
342 switch(buf[1]) { | |
343 case 'd': | |
344 fscanf(file, "%f %f %f", | |
345 &ret->materials[nummaterials].diffuse[0], | |
346 &ret->materials[nummaterials].diffuse[1], | |
347 &ret->materials[nummaterials].diffuse[2]); | |
348 break; | |
349 case 's': | |
350 fscanf(file, "%f %f %f", | |
351 &ret->materials[nummaterials].specular[0], | |
352 &ret->materials[nummaterials].specular[1], | |
353 &ret->materials[nummaterials].specular[2]); | |
354 break; | |
355 case 'a': | |
356 fscanf(file, "%f %f %f", | |
357 &ret->materials[nummaterials].ambient[0], | |
358 &ret->materials[nummaterials].ambient[1], | |
359 &ret->materials[nummaterials].ambient[2]); | |
360 break; | |
361 default: | |
362 /* eat up rest of line */ | |
363 fgets(buf, sizeof(buf), file); | |
364 break; | |
365 } | |
366 break; | |
367 default: | |
368 /* eat up rest of line */ | |
369 fgets(buf, sizeof(buf), file); | |
370 break; | |
371 } | |
372 } | |
373 return ret; | |
374 } | |
375 | |
376 //^^^^charlie^^^^^ | |
377 | |
378 /* glmReadMTL: read a wavefront material library file | |
379 * | |
380 * model - properly initialized GLMmodel structure | |
381 * name - name of the material library | |
382 */ | |
383 static GLvoid | |
384 glmReadMTL(GLMmodel* model, char* name) | |
385 { | |
386 FILE* file; | |
387 char* dir; | |
388 char* filename; | |
389 char buf[128]; | |
390 GLuint nummaterials, i; | |
391 | |
392 dir = glmDirName(model->pathname); | |
393 filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(name) + 1)); | |
394 strcpy(filename, dir); | |
395 strcat(filename, name); | |
396 free(dir); | |
397 | |
398 file = fopen(filename, "r"); | |
399 if (!file) { | |
400 fprintf(stderr, "glmReadMTL() failed: can't open material file \"%s\".\n", | |
401 filename); | |
402 exit(1); | |
403 } | |
404 free(filename); | |
405 | |
406 /* count the number of materials in the file */ | |
407 nummaterials = 1; | |
408 while(fscanf(file, "%s", buf) != EOF) { | |
409 switch(buf[0]) { | |
410 case '#': /* comment */ | |
411 /* eat up rest of line */ | |
412 fgets(buf, sizeof(buf), file); | |
413 break; | |
414 case 'n': /* newmtl */ | |
415 fgets(buf, sizeof(buf), file); | |
416 nummaterials++; | |
417 sscanf(buf, "%s %s", buf, buf); | |
418 break; | |
419 default: | |
420 /* eat up rest of line */ | |
421 fgets(buf, sizeof(buf), file); | |
422 break; | |
423 } | |
424 } | |
425 | |
426 rewind(file); | |
427 model->materials = (GLMmaterial*)malloc(sizeof(GLMmaterial) * nummaterials); | |
428 model->nummaterials = nummaterials; | |
429 | |
430 /* set the default material */ | |
431 for (i = 0; i < nummaterials; i++) { | |
432 model->materials[i].name = NULL; | |
433 model->materials[i].shininess = 65.0; | |
434 model->materials[i].diffuse[0] = 0.8; | |
435 model->materials[i].diffuse[1] = 0.1; | |
436 model->materials[i].diffuse[2] = 0.1; | |
437 model->materials[i].diffuse[3] = 1.0; | |
438 model->materials[i].ambient[0] = 0.2; | |
439 model->materials[i].ambient[1] = 0.2; | |
440 model->materials[i].ambient[2] = 0.2; | |
441 model->materials[i].ambient[3] = 1.0; | |
442 model->materials[i].specular[0] = 0.0; | |
443 model->materials[i].specular[1] = 0.0; | |
444 model->materials[i].specular[2] = 0.0; | |
445 model->materials[i].specular[3] = 1.0; | |
446 } | |
447 model->materials[0].name = strdup("default"); | |
448 | |
449 /* now, read in the data */ | |
450 nummaterials = 0; | |
451 while(fscanf(file, "%s", buf) != EOF) { | |
452 switch(buf[0]) { | |
453 case '#': /* comment */ | |
454 /* eat up rest of line */ | |
455 fgets(buf, sizeof(buf), file); | |
456 break; | |
457 case 'n': /* newmtl */ | |
458 fgets(buf, sizeof(buf), file); | |
459 sscanf(buf, "%s %s", buf, buf); | |
460 nummaterials++; | |
461 model->materials[nummaterials].name = strdup(buf); | |
462 break; | |
463 case 'N': | |
464 fscanf(file, "%f", &model->materials[nummaterials].shininess); | |
465 /* wavefront shininess is from [0, 1000], so scale for OpenGL */ | |
466 model->materials[nummaterials].shininess /= 1000.0; | |
467 model->materials[nummaterials].shininess *= 128.0; | |
468 break; | |
469 case 'K': | |
470 switch(buf[1]) { | |
471 case 'd': | |
472 fscanf(file, "%f %f %f", | |
473 &model->materials[nummaterials].diffuse[0], | |
474 &model->materials[nummaterials].diffuse[1], | |
475 &model->materials[nummaterials].diffuse[2]); | |
476 break; | |
477 case 's': | |
478 fscanf(file, "%f %f %f", | |
479 &model->materials[nummaterials].specular[0], | |
480 &model->materials[nummaterials].specular[1], | |
481 &model->materials[nummaterials].specular[2]); | |
482 break; | |
483 case 'a': | |
484 fscanf(file, "%f %f %f", | |
485 &model->materials[nummaterials].ambient[0], | |
486 &model->materials[nummaterials].ambient[1], | |
487 &model->materials[nummaterials].ambient[2]); | |
488 break; | |
489 default: | |
490 /* eat up rest of line */ | |
491 fgets(buf, sizeof(buf), file); | |
492 break; | |
493 } | |
494 break; | |
495 default: | |
496 /* eat up rest of line */ | |
497 fgets(buf, sizeof(buf), file); | |
498 break; | |
499 } | |
500 } | |
501 } | |
502 | |
503 /* glmWriteMTL: write a wavefront material library file | |
504 * | |
505 * model - properly initialized GLMmodel structure | |
506 * modelpath - pathname of the model being written | |
507 * mtllibname - name of the material library to be written | |
508 */ | |
509 static GLvoid | |
510 glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname) | |
511 { | |
512 FILE* file; | |
513 char* dir; | |
514 char* filename; | |
515 GLMmaterial* material; | |
516 GLuint i; | |
517 | |
518 dir = glmDirName(modelpath); | |
519 filename = (char*)malloc(sizeof(char) * (strlen(dir)+strlen(mtllibname))); | |
520 strcpy(filename, dir); | |
521 strcat(filename, mtllibname); | |
522 free(dir); | |
523 | |
524 /* open the file */ | |
525 file = fopen(filename, "w"); | |
526 if (!file) { | |
527 fprintf(stderr, "glmWriteMTL() failed: can't open file \"%s\".\n", | |
528 filename); | |
529 exit(1); | |
530 } | |
531 free(filename); | |
532 | |
533 /* spit out a header */ | |
534 fprintf(file, "# \n"); | |
535 fprintf(file, "# Wavefront MTL generated by GLM library\n"); | |
536 fprintf(file, "# \n"); | |
537 fprintf(file, "# GLM library\n"); | |
538 fprintf(file, "# Nate Robins\n"); | |
539 fprintf(file, "# ndr@pobox.com\n"); | |
540 fprintf(file, "# http://www.pobox.com/~ndr\n"); | |
541 fprintf(file, "# \n\n"); | |
542 | |
543 for (i = 0; i < model->nummaterials; i++) { | |
544 material = &model->materials[i]; | |
545 fprintf(file, "newmtl %s\n", material->name); | |
546 fprintf(file, "Ka %f %f %f\n", | |
547 material->ambient[0], material->ambient[1], material->ambient[2]); | |
548 fprintf(file, "Kd %f %f %f\n", | |
549 material->diffuse[0], material->diffuse[1], material->diffuse[2]); | |
550 fprintf(file, "Ks %f %f %f\n", | |
551 material->specular[0],material->specular[1],material->specular[2]); | |
552 fprintf(file, "Ns %f\n", material->shininess / 128.0 * 1000.0); | |
553 fprintf(file, "\n"); | |
554 } | |
555 } | |
556 | |
557 | |
558 /* glmFirstPass: first pass at a Wavefront OBJ file that gets all the | |
559 * statistics of the model (such as #vertices, #normals, etc) | |
560 * | |
561 * model - properly initialized GLMmodel structure | |
562 * file - (fopen'd) file descriptor | |
563 */ | |
564 static GLvoid | |
565 glmFirstPass(GLMmodel* model, FILE* file) | |
566 { | |
567 GLuint numvertices; /* number of vertices in model */ | |
568 GLuint numnormals; /* number of normals in model */ | |
569 GLuint numtexcoords; /* number of texcoords in model */ | |
570 GLuint numtriangles; /* number of triangles in model */ | |
571 GLMgroup* group; /* current group */ | |
572 unsigned v, n, t; | |
573 char buf[128]; | |
574 | |
575 /* make a default group */ | |
576 group = glmAddGroup(model, "default"); | |
577 | |
578 numvertices = numnormals = numtexcoords = numtriangles = 0; | |
579 while(fscanf(file, "%s", buf) != EOF) { | |
580 switch(buf[0]) { | |
581 case '#': /* comment */ | |
582 /* eat up rest of line */ | |
583 fgets(buf, sizeof(buf), file); | |
584 break; | |
585 case 'v': /* v, vn, vt */ | |
586 switch(buf[1]) { | |
587 case '\0': /* vertex */ | |
588 /* eat up rest of line */ | |
589 fgets(buf, sizeof(buf), file); | |
590 numvertices++; | |
591 break; | |
592 case 'n': /* normal */ | |
593 /* eat up rest of line */ | |
594 fgets(buf, sizeof(buf), file); | |
595 numnormals++; | |
596 break; | |
597 case 't': /* texcoord */ | |
598 /* eat up rest of line */ | |
599 fgets(buf, sizeof(buf), file); | |
600 numtexcoords++; | |
601 break; | |
602 default: | |
603 printf("glmFirstPass(): Unknown token \"%s\".\n", buf); | |
604 exit(1); | |
605 break; | |
606 } | |
607 break; | |
608 case 'm': | |
609 fgets(buf, sizeof(buf), file); | |
610 sscanf(buf, "%s %s", buf, buf); | |
611 model->mtllibname = strdup(buf); | |
612 //glmReadMTL(model, buf); | |
613 break; | |
614 case 'u': | |
615 /* eat up rest of line */ | |
616 fgets(buf, sizeof(buf), file); | |
617 break; | |
618 case 'g': /* group */ | |
619 /* eat up rest of line */ | |
620 fgets(buf, sizeof(buf), file); | |
621 #if SINGLE_STRING_GROUP_NAMES | |
622 sscanf(buf, "%s", buf); | |
623 #else | |
624 buf[strlen(buf)-1] = '\0'; /* nuke '\n' */ | |
625 #endif | |
626 group = glmAddGroup(model, buf); | |
627 break; | |
628 case 'f': /* face */ | |
629 v = n = t = 0; | |
630 fscanf(file, "%s", buf); | |
631 /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ | |
632 if (strstr(buf, "//")) { | |
633 /* v//n */ | |
634 sscanf(buf, "%d//%d", &v, &n); | |
635 fscanf(file, "%d//%d", &v, &n); | |
636 fscanf(file, "%d//%d", &v, &n); | |
637 numtriangles++; | |
638 group->numtriangles++; | |
639 while(fscanf(file, "%d//%d", &v, &n) > 0) { | |
640 numtriangles++; | |
641 group->numtriangles++; | |
642 } | |
643 } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { | |
644 /* v/t/n */ | |
645 fscanf(file, "%d/%d/%d", &v, &t, &n); | |
646 fscanf(file, "%d/%d/%d", &v, &t, &n); | |
647 numtriangles++; | |
648 group->numtriangles++; | |
649 while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { | |
650 numtriangles++; | |
651 group->numtriangles++; | |
652 } | |
653 } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { | |
654 /* v/t */ | |
655 fscanf(file, "%d/%d", &v, &t); | |
656 fscanf(file, "%d/%d", &v, &t); | |
657 numtriangles++; | |
658 group->numtriangles++; | |
659 while(fscanf(file, "%d/%d", &v, &t) > 0) { | |
660 numtriangles++; | |
661 group->numtriangles++; | |
662 } | |
663 } else { | |
664 /* v */ | |
665 fscanf(file, "%d", &v); | |
666 fscanf(file, "%d", &v); | |
667 numtriangles++; | |
668 group->numtriangles++; | |
669 while(fscanf(file, "%d", &v) > 0) { | |
670 numtriangles++; | |
671 group->numtriangles++; | |
672 } | |
673 } | |
674 break; | |
675 | |
676 default: | |
677 /* eat up rest of line */ | |
678 fgets(buf, sizeof(buf), file); | |
679 break; | |
680 } | |
681 } | |
682 | |
683 /* set the stats in the model structure */ | |
684 model->numvertices = numvertices; | |
685 model->numnormals = numnormals; | |
686 model->numtexcoords = numtexcoords; | |
687 model->numtriangles = numtriangles; | |
688 | |
689 /* allocate memory for the triangles in each group */ | |
690 group = model->groups; | |
691 while(group) { | |
692 group->triangles = (GLuint*)malloc(sizeof(GLuint) * group->numtriangles); | |
693 group->numtriangles = 0; | |
694 group = group->next; | |
695 } | |
696 } | |
697 | |
698 /* glmSecondPass: second pass at a Wavefront OBJ file that gets all | |
699 * the data. | |
700 * | |
701 * model - properly initialized GLMmodel structure | |
702 * file - (fopen'd) file descriptor | |
703 */ | |
704 static GLvoid | |
705 glmSecondPass(GLMmodel* model, FILE* file) | |
706 { | |
707 GLuint numvertices; /* number of vertices in model */ | |
708 GLuint numnormals; /* number of normals in model */ | |
709 GLuint numtexcoords; /* number of texcoords in model */ | |
710 GLuint numtriangles; /* number of triangles in model */ | |
711 GLfloat* vertices; /* array of vertices */ | |
712 GLfloat* normals; /* array of normals */ | |
713 GLfloat* texcoords; /* array of texture coordinates */ | |
714 GLMgroup* group; /* current group pointer */ | |
715 GLuint material; /* current material */ | |
716 GLuint v, n, t; | |
717 char buf[128]; | |
718 | |
719 /* set the pointer shortcuts */ | |
720 vertices = model->vertices; | |
721 normals = model->normals; | |
722 texcoords = model->texcoords; | |
723 group = model->groups; | |
724 | |
725 /* on the second pass through the file, read all the data into the | |
726 allocated arrays */ | |
727 numvertices = numnormals = numtexcoords = 1; | |
728 numtriangles = 0; | |
729 material = 0; | |
730 while(fscanf(file, "%s", buf) != EOF) { | |
731 switch(buf[0]) { | |
732 case '#': /* comment */ | |
733 /* eat up rest of line */ | |
734 fgets(buf, sizeof(buf), file); | |
735 break; | |
736 case 'v': /* v, vn, vt */ | |
737 switch(buf[1]) { | |
738 case '\0': /* vertex */ | |
739 fscanf(file, "%f %f %f", | |
740 &vertices[3 * numvertices + 0], | |
741 &vertices[3 * numvertices + 1], | |
742 &vertices[3 * numvertices + 2]); | |
743 numvertices++; | |
744 break; | |
745 case 'n': /* normal */ | |
746 fscanf(file, "%f %f %f", | |
747 &normals[3 * numnormals + 0], | |
748 &normals[3 * numnormals + 1], | |
749 &normals[3 * numnormals + 2]); | |
750 numnormals++; | |
751 break; | |
752 case 't': /* texcoord */ | |
753 fscanf(file, "%f %f", | |
754 &texcoords[2 * numtexcoords + 0], | |
755 &texcoords[2 * numtexcoords + 1]); | |
756 numtexcoords++; | |
757 break; | |
758 } | |
759 break; | |
760 case 'u': | |
761 fgets(buf, sizeof(buf), file); | |
762 sscanf(buf, "%s %s", buf, buf); | |
763 group->material = material = glmFindMaterial(model, buf); | |
764 break; | |
765 case 'g': /* group */ | |
766 /* eat up rest of line */ | |
767 fgets(buf, sizeof(buf), file); | |
768 #if SINGLE_STRING_GROUP_NAMES | |
769 sscanf(buf, "%s", buf); | |
770 #else | |
771 buf[strlen(buf)-1] = '\0'; /* nuke '\n' */ | |
772 #endif | |
773 group = glmFindGroup(model, buf); | |
774 group->material = material; | |
775 break; | |
776 case 'f': /* face */ | |
777 v = n = t = 0; | |
778 fscanf(file, "%s", buf); | |
779 /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ | |
780 if (strstr(buf, "//")) { | |
781 /* v//n */ | |
782 sscanf(buf, "%d//%d", &v, &n); | |
783 T(numtriangles).vindices[0] = v; | |
784 T(numtriangles).nindices[0] = n; | |
785 fscanf(file, "%d//%d", &v, &n); | |
786 T(numtriangles).vindices[1] = v; | |
787 T(numtriangles).nindices[1] = n; | |
788 fscanf(file, "%d//%d", &v, &n); | |
789 T(numtriangles).vindices[2] = v; | |
790 T(numtriangles).nindices[2] = n; | |
791 group->triangles[group->numtriangles++] = numtriangles; | |
792 numtriangles++; | |
793 while(fscanf(file, "%d//%d", &v, &n) > 0) { | |
794 T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; | |
795 T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; | |
796 T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; | |
797 T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; | |
798 T(numtriangles).vindices[2] = v; | |
799 T(numtriangles).nindices[2] = n; | |
800 group->triangles[group->numtriangles++] = numtriangles; | |
801 numtriangles++; | |
802 } | |
803 } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { | |
804 /* v/t/n */ | |
805 T(numtriangles).vindices[0] = v; | |
806 T(numtriangles).tindices[0] = t; | |
807 T(numtriangles).nindices[0] = n; | |
808 fscanf(file, "%d/%d/%d", &v, &t, &n); | |
809 T(numtriangles).vindices[1] = v; | |
810 T(numtriangles).tindices[1] = t; | |
811 T(numtriangles).nindices[1] = n; | |
812 fscanf(file, "%d/%d/%d", &v, &t, &n); | |
813 T(numtriangles).vindices[2] = v; | |
814 T(numtriangles).tindices[2] = t; | |
815 T(numtriangles).nindices[2] = n; | |
816 group->triangles[group->numtriangles++] = numtriangles; | |
817 numtriangles++; | |
818 while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { | |
819 T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; | |
820 T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; | |
821 T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; | |
822 T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; | |
823 T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; | |
824 T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; | |
825 T(numtriangles).vindices[2] = v; | |
826 T(numtriangles).tindices[2] = t; | |
827 T(numtriangles).nindices[2] = n; | |
828 group->triangles[group->numtriangles++] = numtriangles; | |
829 numtriangles++; | |
830 } | |
831 } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { | |
832 /* v/t */ | |
833 T(numtriangles).vindices[0] = v; | |
834 T(numtriangles).tindices[0] = t; | |
835 fscanf(file, "%d/%d", &v, &t); | |
836 T(numtriangles).vindices[1] = v; | |
837 T(numtriangles).tindices[1] = t; | |
838 fscanf(file, "%d/%d", &v, &t); | |
839 T(numtriangles).vindices[2] = v; | |
840 T(numtriangles).tindices[2] = t; | |
841 group->triangles[group->numtriangles++] = numtriangles; | |
842 numtriangles++; | |
843 while(fscanf(file, "%d/%d", &v, &t) > 0) { | |
844 T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; | |
845 T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; | |
846 T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; | |
847 T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; | |
848 T(numtriangles).vindices[2] = v; | |
849 T(numtriangles).tindices[2] = t; | |
850 group->triangles[group->numtriangles++] = numtriangles; | |
851 numtriangles++; | |
852 } | |
853 } else { | |
854 /* v */ | |
855 sscanf(buf, "%d", &v); | |
856 T(numtriangles).vindices[0] = v; | |
857 fscanf(file, "%d", &v); | |
858 T(numtriangles).vindices[1] = v; | |
859 fscanf(file, "%d", &v); | |
860 T(numtriangles).vindices[2] = v; | |
861 group->triangles[group->numtriangles++] = numtriangles; | |
862 numtriangles++; | |
863 while(fscanf(file, "%d", &v) > 0) { | |
864 T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; | |
865 T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; | |
866 T(numtriangles).vindices[2] = v; | |
867 group->triangles[group->numtriangles++] = numtriangles; | |
868 numtriangles++; | |
869 } | |
870 } | |
871 break; | |
872 | |
873 default: | |
874 /* eat up rest of line */ | |
875 fgets(buf, sizeof(buf), file); | |
876 break; | |
877 } | |
878 } | |
879 | |
880 #if 0 | |
881 /* announce the memory requirements */ | |
882 printf(" Memory: %d bytes\n", | |
883 numvertices * 3*sizeof(GLfloat) + | |
884 numnormals * 3*sizeof(GLfloat) * (numnormals ? 1 : 0) + | |
885 numtexcoords * 3*sizeof(GLfloat) * (numtexcoords ? 1 : 0) + | |
886 numtriangles * sizeof(GLMtriangle)); | |
887 #endif | |
888 } | |
889 | |
890 | |
891 /* public functions */ | |
892 | |
893 | |
894 /* glmUnitize: "unitize" a model by translating it to the origin and | |
895 * scaling it to fit in a unit cube around the origin. Modelurns the | |
896 * scalefactor used. | |
897 * | |
898 * model - properly initialized GLMmodel structure | |
899 */ | |
900 GLfloat | |
901 glmUnitize(GLMmodel* model) | |
902 { | |
903 GLuint i; | |
904 GLfloat maxx, minx, maxy, miny, maxz, minz; | |
905 GLfloat cx, cy, cz, w, h, d; | |
906 GLfloat scale; | |
907 | |
908 assert(model); | |
909 assert(model->vertices); | |
910 | |
911 /* get the max/mins */ | |
912 maxx = minx = model->vertices[3 + 0]; | |
913 maxy = miny = model->vertices[3 + 1]; | |
914 maxz = minz = model->vertices[3 + 2]; | |
915 for (i = 1; i <= model->numvertices; i++) { | |
916 if (maxx < model->vertices[3 * i + 0]) | |
917 maxx = model->vertices[3 * i + 0]; | |
918 if (minx > model->vertices[3 * i + 0]) | |
919 minx = model->vertices[3 * i + 0]; | |
920 | |
921 if (maxy < model->vertices[3 * i + 1]) | |
922 maxy = model->vertices[3 * i + 1]; | |
923 if (miny > model->vertices[3 * i + 1]) | |
924 miny = model->vertices[3 * i + 1]; | |
925 | |
926 if (maxz < model->vertices[3 * i + 2]) | |
927 maxz = model->vertices[3 * i + 2]; | |
928 if (minz > model->vertices[3 * i + 2]) | |
929 minz = model->vertices[3 * i + 2]; | |
930 } | |
931 | |
932 /* calculate model width, height, and depth */ | |
933 w = glmAbs(maxx) + glmAbs(minx); | |
934 h = glmAbs(maxy) + glmAbs(miny); | |
935 d = glmAbs(maxz) + glmAbs(minz); | |
936 | |
937 /* calculate center of the model */ | |
938 cx = (maxx + minx) / 2.0; | |
939 cy = (maxy + miny) / 2.0; | |
940 cz = (maxz + minz) / 2.0; | |
941 | |
942 /* calculate unitizing scale factor */ | |
943 scale = 2.0 / glmMax(glmMax(w, h), d); | |
944 | |
945 /* translate around center then scale */ | |
946 for (i = 1; i <= model->numvertices; i++) { | |
947 model->vertices[3 * i + 0] -= cx; | |
948 model->vertices[3 * i + 1] -= cy; | |
949 model->vertices[3 * i + 2] -= cz; | |
950 //charlie, i took this out, i just want to center | |
951 /* | |
952 model->vertices[3 * i + 0] *= scale; | |
953 model->vertices[3 * i + 1] *= scale; | |
954 model->vertices[3 * i + 2] *= scale; | |
955 */ | |
956 } | |
957 | |
958 return scale; | |
959 } | |
960 | |
961 /* glmDimensions: Calculates the dimensions (width, height, depth) of | |
962 * a model. | |
963 * | |
964 * model - initialized GLMmodel structure | |
965 * dimensions - array of 3 GLfloats (GLfloat dimensions[3]) | |
966 */ | |
967 GLvoid | |
968 glmDimensions(GLMmodel* model, GLfloat* dimensions) | |
969 { | |
970 GLuint i; | |
971 GLfloat maxx, minx, maxy, miny, maxz, minz; | |
972 | |
973 assert(model); | |
974 assert(model->vertices); | |
975 assert(dimensions); | |
976 | |
977 /* get the max/mins */ | |
978 maxx = minx = model->vertices[3 + 0]; | |
979 maxy = miny = model->vertices[3 + 1]; | |
980 maxz = minz = model->vertices[3 + 2]; | |
981 for (i = 1; i <= model->numvertices; i++) { | |
982 if (maxx < model->vertices[3 * i + 0]) | |
983 maxx = model->vertices[3 * i + 0]; | |
984 if (minx > model->vertices[3 * i + 0]) | |
985 minx = model->vertices[3 * i + 0]; | |
986 | |
987 if (maxy < model->vertices[3 * i + 1]) | |
988 maxy = model->vertices[3 * i + 1]; | |
989 if (miny > model->vertices[3 * i + 1]) | |
990 miny = model->vertices[3 * i + 1]; | |
991 | |
992 if (maxz < model->vertices[3 * i + 2]) | |
993 maxz = model->vertices[3 * i + 2]; | |
994 if (minz > model->vertices[3 * i + 2]) | |
995 minz = model->vertices[3 * i + 2]; | |
996 } | |
997 | |
998 /* calculate model width, height, and depth */ | |
999 dimensions[0] = glmAbs(maxx) + glmAbs(minx); | |
1000 dimensions[1] = glmAbs(maxy) + glmAbs(miny); | |
1001 dimensions[2] = glmAbs(maxz) + glmAbs(minz); | |
1002 } | |
1003 | |
1004 /* glmScale: Scales a model by a given amount. | |
1005 * | |
1006 * model - properly initialized GLMmodel structure | |
1007 * scale - scalefactor (0.5 = half as large, 2.0 = twice as large) | |
1008 */ | |
1009 GLvoid | |
1010 glmScale(GLMmodel* model, GLfloat scale) | |
1011 { | |
1012 GLuint i; | |
1013 | |
1014 for (i = 1; i <= model->numvertices; i++) { | |
1015 model->vertices[3 * i + 0] *= scale; | |
1016 model->vertices[3 * i + 1] *= scale; | |
1017 model->vertices[3 * i + 2] *= scale; | |
1018 } | |
1019 } | |
1020 | |
1021 /* glmReverseWinding: Reverse the polygon winding for all polygons in | |
1022 * this model. Default winding is counter-clockwise. Also changes | |
1023 * the direction of the normals. | |
1024 * | |
1025 * model - properly initialized GLMmodel structure | |
1026 */ | |
1027 GLvoid | |
1028 glmReverseWinding(GLMmodel* model) | |
1029 { | |
1030 GLuint i, swap; | |
1031 | |
1032 assert(model); | |
1033 | |
1034 for (i = 0; i < model->numtriangles; i++) { | |
1035 swap = T(i).vindices[0]; | |
1036 T(i).vindices[0] = T(i).vindices[2]; | |
1037 T(i).vindices[2] = swap; | |
1038 | |
1039 if (model->numnormals) { | |
1040 swap = T(i).nindices[0]; | |
1041 T(i).nindices[0] = T(i).nindices[2]; | |
1042 T(i).nindices[2] = swap; | |
1043 } | |
1044 | |
1045 if (model->numtexcoords) { | |
1046 swap = T(i).tindices[0]; | |
1047 T(i).tindices[0] = T(i).tindices[2]; | |
1048 T(i).tindices[2] = swap; | |
1049 } | |
1050 } | |
1051 | |
1052 /* reverse facet normals */ | |
1053 for (i = 1; i <= model->numfacetnorms; i++) { | |
1054 model->facetnorms[3 * i + 0] = -model->facetnorms[3 * i + 0]; | |
1055 model->facetnorms[3 * i + 1] = -model->facetnorms[3 * i + 1]; | |
1056 model->facetnorms[3 * i + 2] = -model->facetnorms[3 * i + 2]; | |
1057 } | |
1058 | |
1059 /* reverse vertex normals */ | |
1060 for (i = 1; i <= model->numnormals; i++) { | |
1061 model->normals[3 * i + 0] = -model->normals[3 * i + 0]; | |
1062 model->normals[3 * i + 1] = -model->normals[3 * i + 1]; | |
1063 model->normals[3 * i + 2] = -model->normals[3 * i + 2]; | |
1064 } | |
1065 } | |
1066 | |
1067 /* glmFacetNormals: Generates facet normals for a model (by taking the | |
1068 * cross product of the two vectors derived from the sides of each | |
1069 * triangle). Assumes a counter-clockwise winding. | |
1070 * | |
1071 * model - initialized GLMmodel structure | |
1072 */ | |
1073 GLvoid | |
1074 glmFacetNormals(GLMmodel* model) | |
1075 { | |
1076 GLuint i; | |
1077 GLfloat u[3]; | |
1078 GLfloat v[3]; | |
1079 | |
1080 assert(model); | |
1081 assert(model->vertices); | |
1082 | |
1083 /* clobber any old facetnormals */ | |
1084 if (model->facetnorms) | |
1085 free(model->facetnorms); | |
1086 | |
1087 /* allocate memory for the new facet normals */ | |
1088 model->numfacetnorms = model->numtriangles; | |
1089 model->facetnorms = (GLfloat*)malloc(sizeof(GLfloat) * | |
1090 3 * (model->numfacetnorms + 1)); | |
1091 | |
1092 for (i = 0; i < model->numtriangles; i++) { | |
1093 model->triangles[i].findex = i+1; | |
1094 | |
1095 u[0] = model->vertices[3 * T(i).vindices[1] + 0] - | |
1096 model->vertices[3 * T(i).vindices[0] + 0]; | |
1097 u[1] = model->vertices[3 * T(i).vindices[1] + 1] - | |
1098 model->vertices[3 * T(i).vindices[0] + 1]; | |
1099 u[2] = model->vertices[3 * T(i).vindices[1] + 2] - | |
1100 model->vertices[3 * T(i).vindices[0] + 2]; | |
1101 | |
1102 v[0] = model->vertices[3 * T(i).vindices[2] + 0] - | |
1103 model->vertices[3 * T(i).vindices[0] + 0]; | |
1104 v[1] = model->vertices[3 * T(i).vindices[2] + 1] - | |
1105 model->vertices[3 * T(i).vindices[0] + 1]; | |
1106 v[2] = model->vertices[3 * T(i).vindices[2] + 2] - | |
1107 model->vertices[3 * T(i).vindices[0] + 2]; | |
1108 | |
1109 glmCross(u, v, &model->facetnorms[3 * (i+1)]); | |
1110 glmNormalize(&model->facetnorms[3 * (i+1)]); | |
1111 } | |
1112 } | |
1113 | |
1114 /* glmVertexNormals: Generates smooth vertex normals for a model. | |
1115 * First builds a list of all the triangles each vertex is in. Then | |
1116 * loops through each vertex in the the list averaging all the facet | |
1117 * normals of the triangles each vertex is in. Finally, sets the | |
1118 * normal index in the triangle for the vertex to the generated smooth | |
1119 * normal. If the dot product of a facet normal and the facet normal | |
1120 * associated with the first triangle in the list of triangles the | |
1121 * current vertex is in is greater than the cosine of the angle | |
1122 * parameter to the function, that facet normal is not added into the | |
1123 * average normal calculation and the corresponding vertex is given | |
1124 * the facet normal. This tends to preserve hard edges. The angle to | |
1125 * use depends on the model, but 90 degrees is usually a good start. | |
1126 * | |
1127 * model - initialized GLMmodel structure | |
1128 * angle - maximum angle (in degrees) to smooth across | |
1129 */ | |
1130 GLvoid | |
1131 glmVertexNormals(GLMmodel* model, GLfloat angle) | |
1132 { | |
1133 GLMnode* node; | |
1134 GLMnode* tail; | |
1135 GLMnode** members; | |
1136 GLfloat* normals; | |
1137 GLuint numnormals; | |
1138 GLfloat average[3]; | |
1139 GLfloat dot, cos_angle; | |
1140 GLuint i, avg; | |
1141 | |
1142 assert(model); | |
1143 assert(model->facetnorms); | |
1144 | |
1145 /* calculate the cosine of the angle (in degrees) */ | |
1146 cos_angle = cos(angle * M_PI / 180.0); | |
1147 | |
1148 /* nuke any previous normals */ | |
1149 if (model->normals) | |
1150 free(model->normals); | |
1151 | |
1152 /* allocate space for new normals */ | |
1153 model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */ | |
1154 model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1)); | |
1155 | |
1156 /* allocate a structure that will hold a linked list of triangle | |
1157 indices for each vertex */ | |
1158 members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1)); | |
1159 for (i = 1; i <= model->numvertices; i++) | |
1160 members[i] = NULL; | |
1161 | |
1162 /* for every triangle, create a node for each vertex in it */ | |
1163 for (i = 0; i < model->numtriangles; i++) { | |
1164 node = (GLMnode*)malloc(sizeof(GLMnode)); | |
1165 node->index = i; | |
1166 node->next = members[T(i).vindices[0]]; | |
1167 members[T(i).vindices[0]] = node; | |
1168 | |
1169 node = (GLMnode*)malloc(sizeof(GLMnode)); | |
1170 node->index = i; | |
1171 node->next = members[T(i).vindices[1]]; | |
1172 members[T(i).vindices[1]] = node; | |
1173 | |
1174 node = (GLMnode*)malloc(sizeof(GLMnode)); | |
1175 node->index = i; | |
1176 node->next = members[T(i).vindices[2]]; | |
1177 members[T(i).vindices[2]] = node; | |
1178 } | |
1179 | |
1180 /* calculate the average normal for each vertex */ | |
1181 numnormals = 1; | |
1182 for (i = 1; i <= model->numvertices; i++) { | |
1183 /* calculate an average normal for this vertex by averaging the | |
1184 facet normal of every triangle this vertex is in */ | |
1185 node = members[i]; | |
1186 if (!node) | |
1187 fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n"); | |
1188 average[0] = 0.0; average[1] = 0.0; average[2] = 0.0; | |
1189 avg = 0; | |
1190 while (node) { | |
1191 /* only average if the dot product of the angle between the two | |
1192 facet normals is greater than the cosine of the threshold | |
1193 angle -- or, said another way, the angle between the two | |
1194 facet normals is less than (or equal to) the threshold angle */ | |
1195 dot = glmDot(&model->facetnorms[3 * T(node->index).findex], | |
1196 &model->facetnorms[3 * T(members[i]->index).findex]); | |
1197 if (dot > cos_angle) { | |
1198 node->averaged = GL_TRUE; | |
1199 average[0] += model->facetnorms[3 * T(node->index).findex + 0]; | |
1200 average[1] += model->facetnorms[3 * T(node->index).findex + 1]; | |
1201 average[2] += model->facetnorms[3 * T(node->index).findex + 2]; | |
1202 avg = 1; /* we averaged at least one normal! */ | |
1203 } else { | |
1204 node->averaged = GL_FALSE; | |
1205 } | |
1206 node = node->next; | |
1207 } | |
1208 | |
1209 if (avg) { | |
1210 /* normalize the averaged normal */ | |
1211 glmNormalize(average); | |
1212 | |
1213 /* add the normal to the vertex normals list */ | |
1214 model->normals[3 * numnormals + 0] = average[0]; | |
1215 model->normals[3 * numnormals + 1] = average[1]; | |
1216 model->normals[3 * numnormals + 2] = average[2]; | |
1217 avg = numnormals; | |
1218 numnormals++; | |
1219 } | |
1220 | |
1221 /* set the normal of this vertex in each triangle it is in */ | |
1222 node = members[i]; | |
1223 while (node) { | |
1224 if (node->averaged) { | |
1225 /* if this node was averaged, use the average normal */ | |
1226 if (T(node->index).vindices[0] == i) | |
1227 T(node->index).nindices[0] = avg; | |
1228 else if (T(node->index).vindices[1] == i) | |
1229 T(node->index).nindices[1] = avg; | |
1230 else if (T(node->index).vindices[2] == i) | |
1231 T(node->index).nindices[2] = avg; | |
1232 } else { | |
1233 /* if this node wasn't averaged, use the facet normal */ | |
1234 model->normals[3 * numnormals + 0] = | |
1235 model->facetnorms[3 * T(node->index).findex + 0]; | |
1236 model->normals[3 * numnormals + 1] = | |
1237 model->facetnorms[3 * T(node->index).findex + 1]; | |
1238 model->normals[3 * numnormals + 2] = | |
1239 model->facetnorms[3 * T(node->index).findex + 2]; | |
1240 if (T(node->index).vindices[0] == i) | |
1241 T(node->index).nindices[0] = numnormals; | |
1242 else if (T(node->index).vindices[1] == i) | |
1243 T(node->index).nindices[1] = numnormals; | |
1244 else if (T(node->index).vindices[2] == i) | |
1245 T(node->index).nindices[2] = numnormals; | |
1246 numnormals++; | |
1247 } | |
1248 node = node->next; | |
1249 } | |
1250 } | |
1251 | |
1252 model->numnormals = numnormals - 1; | |
1253 | |
1254 /* free the member information */ | |
1255 for (i = 1; i <= model->numvertices; i++) { | |
1256 node = members[i]; | |
1257 while (node) { | |
1258 tail = node; | |
1259 node = node->next; | |
1260 free(tail); | |
1261 } | |
1262 } | |
1263 free(members); | |
1264 | |
1265 /* pack the normals array (we previously allocated the maximum | |
1266 number of normals that could possibly be created (numtriangles * | |
1267 3), so get rid of some of them (usually alot unless none of the | |
1268 facet normals were averaged)) */ | |
1269 normals = model->normals; | |
1270 model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1)); | |
1271 for (i = 1; i <= model->numnormals; i++) { | |
1272 model->normals[3 * i + 0] = normals[3 * i + 0]; | |
1273 model->normals[3 * i + 1] = normals[3 * i + 1]; | |
1274 model->normals[3 * i + 2] = normals[3 * i + 2]; | |
1275 } | |
1276 free(normals); | |
1277 } | |
1278 | |
1279 | |
1280 /* glmLinearTexture: Generates texture coordinates according to a | |
1281 * linear projection of the texture map. It generates these by | |
1282 * linearly mapping the vertices onto a square. | |
1283 * | |
1284 * model - pointer to initialized GLMmodel structure | |
1285 */ | |
1286 GLvoid | |
1287 glmLinearTexture(GLMmodel* model) | |
1288 { | |
1289 GLMgroup *group; | |
1290 GLfloat dimensions[3]; | |
1291 GLfloat x, y, scalefactor; | |
1292 GLuint i; | |
1293 | |
1294 assert(model); | |
1295 | |
1296 if (model->texcoords) | |
1297 free(model->texcoords); | |
1298 model->numtexcoords = model->numvertices; | |
1299 model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1)); | |
1300 | |
1301 glmDimensions(model, dimensions); | |
1302 scalefactor = 2.0 / | |
1303 glmAbs(glmMax(glmMax(dimensions[0], dimensions[1]), dimensions[2])); | |
1304 | |
1305 /* do the calculations */ | |
1306 for(i = 1; i <= model->numvertices; i++) { | |
1307 x = model->vertices[3 * i + 0] * scalefactor; | |
1308 y = model->vertices[3 * i + 2] * scalefactor; | |
1309 model->texcoords[2 * i + 0] = (x + 1.0) / 2.0; | |
1310 model->texcoords[2 * i + 1] = (y + 1.0) / 2.0; | |
1311 } | |
1312 | |
1313 /* go through and put texture coordinate indices in all the triangles */ | |
1314 group = model->groups; | |
1315 while(group) { | |
1316 for(i = 0; i < group->numtriangles; i++) { | |
1317 T(group->triangles[i]).tindices[0] = T(group->triangles[i]).vindices[0]; | |
1318 T(group->triangles[i]).tindices[1] = T(group->triangles[i]).vindices[1]; | |
1319 T(group->triangles[i]).tindices[2] = T(group->triangles[i]).vindices[2]; | |
1320 } | |
1321 group = group->next; | |
1322 } | |
1323 | |
1324 #if 0 | |
1325 printf("glmLinearTexture(): generated %d linear texture coordinates\n", | |
1326 model->numtexcoords); | |
1327 #endif | |
1328 } | |
1329 | |
1330 /* glmSpheremapTexture: Generates texture coordinates according to a | |
1331 * spherical projection of the texture map. Sometimes referred to as | |
1332 * spheremap, or reflection map texture coordinates. It generates | |
1333 * these by using the normal to calculate where that vertex would map | |
1334 * onto a sphere. Since it is impossible to map something flat | |
1335 * perfectly onto something spherical, there is distortion at the | |
1336 * poles. This particular implementation causes the poles along the X | |
1337 * axis to be distorted. | |
1338 * | |
1339 * model - pointer to initialized GLMmodel structure | |
1340 */ | |
1341 GLvoid | |
1342 glmSpheremapTexture(GLMmodel* model) | |
1343 { | |
1344 GLMgroup* group; | |
1345 GLfloat theta, phi, rho, x, y, z, r; | |
1346 GLuint i; | |
1347 | |
1348 assert(model); | |
1349 assert(model->normals); | |
1350 | |
1351 if (model->texcoords) | |
1352 free(model->texcoords); | |
1353 model->numtexcoords = model->numnormals; | |
1354 model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1)); | |
1355 | |
1356 for (i = 1; i <= model->numnormals; i++) { | |
1357 z = model->normals[3 * i + 0]; /* re-arrange for pole distortion */ | |
1358 y = model->normals[3 * i + 1]; | |
1359 x = model->normals[3 * i + 2]; | |
1360 r = sqrt((x * x) + (y * y)); | |
1361 rho = sqrt((r * r) + (z * z)); | |
1362 | |
1363 if(r == 0.0) { | |
1364 theta = 0.0; | |
1365 phi = 0.0; | |
1366 } else { | |
1367 if(z == 0.0) | |
1368 phi = 3.14159265 / 2.0; | |
1369 else | |
1370 phi = acos(z / rho); | |
1371 | |
1372 if(y == 0.0) | |
1373 theta = 3.141592365 / 2.0; | |
1374 else | |
1375 theta = asin(y / r) + (3.14159265 / 2.0); | |
1376 } | |
1377 | |
1378 model->texcoords[2 * i + 0] = theta / 3.14159265; | |
1379 model->texcoords[2 * i + 1] = phi / 3.14159265; | |
1380 } | |
1381 | |
1382 /* go through and put texcoord indices in all the triangles */ | |
1383 group = model->groups; | |
1384 while(group) { | |
1385 for (i = 0; i < group->numtriangles; i++) { | |
1386 T(group->triangles[i]).tindices[0] = T(group->triangles[i]).nindices[0]; | |
1387 T(group->triangles[i]).tindices[1] = T(group->triangles[i]).nindices[1]; | |
1388 T(group->triangles[i]).tindices[2] = T(group->triangles[i]).nindices[2]; | |
1389 } | |
1390 group = group->next; | |
1391 } | |
1392 } | |
1393 | |
1394 /* glmDelete: Deletes a GLMmodel structure. | |
1395 * | |
1396 * model - initialized GLMmodel structure | |
1397 */ | |
1398 GLvoid | |
1399 glmDelete(GLMmodel* model) | |
1400 { | |
1401 GLMgroup* group; | |
1402 GLuint i; | |
1403 | |
1404 assert(model); | |
1405 | |
1406 if (model->pathname) free(model->pathname); | |
1407 if (model->mtllibname) free(model->mtllibname); | |
1408 if (model->vertices) free(model->vertices); | |
1409 if (model->normals) free(model->normals); | |
1410 if (model->texcoords) free(model->texcoords); | |
1411 if (model->facetnorms) free(model->facetnorms); | |
1412 if (model->triangles) free(model->triangles); | |
1413 if (model->materials) { | |
1414 for (i = 0; i < model->nummaterials; i++) | |
1415 free(model->materials[i].name); | |
1416 } | |
1417 free(model->materials); | |
1418 while(model->groups) { | |
1419 group = model->groups; | |
1420 model->groups = model->groups->next; | |
1421 free(group->name); | |
1422 free(group->triangles); | |
1423 free(group); | |
1424 } | |
1425 | |
1426 free(model); | |
1427 } | |
1428 | |
1429 /* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. | |
1430 * Modelurns a pointer to the created object which should be free'd with | |
1431 * glmDelete(). | |
1432 * | |
1433 * filename - name of the file containing the Wavefront .OBJ format data. | |
1434 */ | |
1435 GLMmodel* | |
1436 glmReadOBJ(char* filename) | |
1437 { | |
1438 GLMmodel* model; | |
1439 FILE* file; | |
1440 printf("*"); | |
1441 fflush(NULL); | |
1442 | |
1443 /* open the file */ | |
1444 file = fopen(filename, "r"); | |
1445 if (!file) { | |
1446 fprintf(stderr, "glmReadOBJ() failed: can't open data file \"%s\".\n", | |
1447 filename); | |
1448 exit(1); | |
1449 } | |
1450 | |
1451 /* allocate a new model */ | |
1452 model = (GLMmodel*)malloc(sizeof(GLMmodel)); | |
1453 model->pathname = strdup(filename); | |
1454 model->mtllibname = NULL; | |
1455 model->numvertices = 0; | |
1456 model->vertices = NULL; | |
1457 model->numnormals = 0; | |
1458 model->normals = NULL; | |
1459 model->numtexcoords = 0; | |
1460 model->texcoords = NULL; | |
1461 model->numfacetnorms = 0; | |
1462 model->facetnorms = NULL; | |
1463 model->numtriangles = 0; | |
1464 model->triangles = NULL; | |
1465 model->nummaterials = 0; | |
1466 model->materials = NULL; | |
1467 model->numgroups = 0; | |
1468 model->groups = NULL; | |
1469 model->position[0] = 0.0; | |
1470 model->position[1] = 0.0; | |
1471 model->position[2] = 0.0; | |
1472 | |
1473 /* make a first pass through the file to get a count of the number | |
1474 of vertices, normals, texcoords & triangles */ | |
1475 glmFirstPass(model, file); | |
1476 | |
1477 /* allocate memory */ | |
1478 model->vertices = (GLfloat*)malloc(sizeof(GLfloat) * | |
1479 3 * (model->numvertices + 1)); | |
1480 model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) * | |
1481 model->numtriangles); | |
1482 if (model->numnormals) { | |
1483 model->normals = (GLfloat*)malloc(sizeof(GLfloat) * | |
1484 3 * (model->numnormals + 1)); | |
1485 } | |
1486 if (model->numtexcoords) { | |
1487 model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * | |
1488 2 * (model->numtexcoords + 1)); | |
1489 } | |
1490 | |
1491 /* rewind to beginning of file and read in the data this pass */ | |
1492 rewind(file); | |
1493 | |
1494 glmSecondPass(model, file); | |
1495 | |
1496 /* close the file */ | |
1497 fclose(file); | |
1498 | |
1499 return model; | |
1500 } | |
1501 | |
1502 /* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to | |
1503 * a file. | |
1504 * | |
1505 * model - initialized GLMmodel structure | |
1506 * filename - name of the file to write the Wavefront .OBJ format data to | |
1507 * mode - a bitwise or of values describing what is written to the file | |
1508 * GLM_NONE - render with only vertices | |
1509 * GLM_FLAT - render with facet normals | |
1510 * GLM_SMOOTH - render with vertex normals | |
1511 * GLM_TEXTURE - render with texture coords | |
1512 * GLM_COLOR - render with colors (color material) | |
1513 * GLM_MATERIAL - render with materials | |
1514 * GLM_COLOR and GLM_MATERIAL should not both be specified. | |
1515 * GLM_FLAT and GLM_SMOOTH should not both be specified. | |
1516 */ | |
1517 GLvoid | |
1518 glmWriteOBJ(GLMmodel* model, char* filename, GLuint mode) | |
1519 { | |
1520 GLuint i; | |
1521 FILE* file; | |
1522 GLMgroup* group; | |
1523 | |
1524 assert(model); | |
1525 | |
1526 /* do a bit of warning */ | |
1527 if (mode & GLM_FLAT && !model->facetnorms) { | |
1528 printf("glmWriteOBJ() warning: flat normal output requested " | |
1529 "with no facet normals defined.\n"); | |
1530 mode &= ~GLM_FLAT; | |
1531 } | |
1532 if (mode & GLM_SMOOTH && !model->normals) { | |
1533 printf("glmWriteOBJ() warning: smooth normal output requested " | |
1534 "with no normals defined.\n"); | |
1535 mode &= ~GLM_SMOOTH; | |
1536 } | |
1537 if (mode & GLM_TEXTURE && !model->texcoords) { | |
1538 printf("glmWriteOBJ() warning: texture coordinate output requested " | |
1539 "with no texture coordinates defined.\n"); | |
1540 mode &= ~GLM_TEXTURE; | |
1541 } | |
1542 if (mode & GLM_FLAT && mode & GLM_SMOOTH) { | |
1543 printf("glmWriteOBJ() warning: flat normal output requested " | |
1544 "and smooth normal output requested (using smooth).\n"); | |
1545 mode &= ~GLM_FLAT; | |
1546 } | |
1547 if (mode & GLM_COLOR && !model->materials) { | |
1548 printf("glmWriteOBJ() warning: color output requested " | |
1549 "with no colors (materials) defined.\n"); | |
1550 mode &= ~GLM_COLOR; | |
1551 } | |
1552 if (mode & GLM_MATERIAL && !model->materials) { | |
1553 printf("glmWriteOBJ() warning: material output requested " | |
1554 "with no materials defined.\n"); | |
1555 mode &= ~GLM_MATERIAL; | |
1556 } | |
1557 if (mode & GLM_COLOR && mode & GLM_MATERIAL) { | |
1558 printf("glmWriteOBJ() warning: color and material output requested " | |
1559 "outputting only materials.\n"); | |
1560 mode &= ~GLM_COLOR; | |
1561 } | |
1562 | |
1563 | |
1564 /* open the file */ | |
1565 file = fopen(filename, "w"); | |
1566 if (!file) { | |
1567 fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n", | |
1568 filename); | |
1569 exit(1); | |
1570 } | |
1571 | |
1572 /* spit out a header */ | |
1573 fprintf(file, "# \n"); | |
1574 fprintf(file, "# Wavefront OBJ generated by GLM library\n"); | |
1575 fprintf(file, "# \n"); | |
1576 fprintf(file, "# GLM library\n"); | |
1577 fprintf(file, "# Nate Robins\n"); | |
1578 fprintf(file, "# ndr@pobox.com\n"); | |
1579 fprintf(file, "# http://www.pobox.com/~ndr\n"); | |
1580 fprintf(file, "# \n"); | |
1581 | |
1582 if (mode & GLM_MATERIAL && model->mtllibname) { | |
1583 fprintf(file, "\nmtllib %s\n\n", model->mtllibname); | |
1584 glmWriteMTL(model, filename, model->mtllibname); | |
1585 } | |
1586 | |
1587 /* spit out the vertices */ | |
1588 fprintf(file, "\n"); | |
1589 fprintf(file, "# %d vertices\n", model->numvertices); | |
1590 for (i = 1; i <= model->numvertices; i++) { | |
1591 fprintf(file, "v %f %f %f\n", | |
1592 model->vertices[3 * i + 0], | |
1593 model->vertices[3 * i + 1], | |
1594 model->vertices[3 * i + 2]); | |
1595 } | |
1596 | |
1597 /* spit out the smooth/flat normals */ | |
1598 if (mode & GLM_SMOOTH) { | |
1599 fprintf(file, "\n"); | |
1600 fprintf(file, "# %d normals\n", model->numnormals); | |
1601 for (i = 1; i <= model->numnormals; i++) { | |
1602 fprintf(file, "vn %f %f %f\n", | |
1603 model->normals[3 * i + 0], | |
1604 model->normals[3 * i + 1], | |
1605 model->normals[3 * i + 2]); | |
1606 } | |
1607 } else if (mode & GLM_FLAT) { | |
1608 fprintf(file, "\n"); | |
1609 fprintf(file, "# %d normals\n", model->numfacetnorms); | |
1610 for (i = 1; i <= model->numnormals; i++) { | |
1611 fprintf(file, "vn %f %f %f\n", | |
1612 model->facetnorms[3 * i + 0], | |
1613 model->facetnorms[3 * i + 1], | |
1614 model->facetnorms[3 * i + 2]); | |
1615 } | |
1616 } | |
1617 | |
1618 /* spit out the texture coordinates */ | |
1619 if (mode & GLM_TEXTURE) { | |
1620 fprintf(file, "\n"); | |
1621 fprintf(file, "# %d texcoords\n", model->texcoords); | |
1622 for (i = 1; i <= model->numtexcoords; i++) { | |
1623 fprintf(file, "vt %f %f\n", | |
1624 model->texcoords[2 * i + 0], | |
1625 model->texcoords[2 * i + 1]); | |
1626 } | |
1627 } | |
1628 | |
1629 fprintf(file, "\n"); | |
1630 fprintf(file, "# %d groups\n", model->numgroups); | |
1631 fprintf(file, "# %d faces (triangles)\n", model->numtriangles); | |
1632 fprintf(file, "\n"); | |
1633 | |
1634 group = model->groups; | |
1635 while(group) { | |
1636 fprintf(file, "g %s\n", group->name); | |
1637 if (mode & GLM_MATERIAL) | |
1638 fprintf(file, "usemtl %s\n", model->materials[group->material].name); | |
1639 for (i = 0; i < group->numtriangles; i++) { | |
1640 if (mode & GLM_SMOOTH && mode & GLM_TEXTURE) { | |
1641 fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", | |
1642 T(group->triangles[i]).vindices[0], | |
1643 T(group->triangles[i]).nindices[0], | |
1644 T(group->triangles[i]).tindices[0], | |
1645 T(group->triangles[i]).vindices[1], | |
1646 T(group->triangles[i]).nindices[1], | |
1647 T(group->triangles[i]).tindices[1], | |
1648 T(group->triangles[i]).vindices[2], | |
1649 T(group->triangles[i]).nindices[2], | |
1650 T(group->triangles[i]).tindices[2]); | |
1651 } else if (mode & GLM_FLAT && mode & GLM_TEXTURE) { | |
1652 fprintf(file, "f %d/%d %d/%d %d/%d\n", | |
1653 T(group->triangles[i]).vindices[0], | |
1654 T(group->triangles[i]).findex, | |
1655 T(group->triangles[i]).vindices[1], | |
1656 T(group->triangles[i]).findex, | |
1657 T(group->triangles[i]).vindices[2], | |
1658 T(group->triangles[i]).findex); | |
1659 } else if (mode & GLM_TEXTURE) { | |
1660 fprintf(file, "f %d/%d %d/%d %d/%d\n", | |
1661 T(group->triangles[i]).vindices[0], | |
1662 T(group->triangles[i]).tindices[0], | |
1663 T(group->triangles[i]).vindices[1], | |
1664 T(group->triangles[i]).tindices[1], | |
1665 T(group->triangles[i]).vindices[2], | |
1666 T(group->triangles[i]).tindices[2]); | |
1667 } else if (mode & GLM_SMOOTH) { | |
1668 fprintf(file, "f %d//%d %d//%d %d//%d\n", | |
1669 T(group->triangles[i]).vindices[0], | |
1670 T(group->triangles[i]).nindices[0], | |
1671 T(group->triangles[i]).vindices[1], | |
1672 T(group->triangles[i]).nindices[1], | |
1673 T(group->triangles[i]).vindices[2], | |
1674 T(group->triangles[i]).nindices[2]); | |
1675 } else if (mode & GLM_FLAT) { | |
1676 fprintf(file, "f %d//%d %d//%d %d//%d\n", | |
1677 T(group->triangles[i]).vindices[0], | |
1678 T(group->triangles[i]).findex, | |
1679 T(group->triangles[i]).vindices[1], | |
1680 T(group->triangles[i]).findex, | |
1681 T(group->triangles[i]).vindices[2], | |
1682 T(group->triangles[i]).findex); | |
1683 } else { | |
1684 fprintf(file, "f %d %d %d\n", | |
1685 T(group->triangles[i]).vindices[0], | |
1686 T(group->triangles[i]).vindices[1], | |
1687 T(group->triangles[i]).vindices[2]); | |
1688 } | |
1689 } | |
1690 fprintf(file, "\n"); | |
1691 group = group->next; | |
1692 } | |
1693 | |
1694 fclose(file); | |
1695 } | |
1696 | |
1697 /* glmDraw: Renders the model to the current OpenGL context using the | |
1698 * mode specified. | |
1699 * | |
1700 * model - initialized GLMmodel structure | |
1701 * mode - a bitwise OR of values describing what is to be rendered. | |
1702 * GLM_NONE - render with only vertices | |
1703 * GLM_FLAT - render with facet normals | |
1704 * GLM_SMOOTH - render with vertex normals | |
1705 * GLM_TEXTURE - render with texture coords | |
1706 * GLM_COLOR - render with colors (color material) | |
1707 * GLM_MATERIAL - render with materials | |
1708 * GLM_COLOR and GLM_MATERIAL should not both be specified. | |
1709 * GLM_FLAT and GLM_SMOOTH should not both be specified. | |
1710 */ | |
1711 GLvoid | |
1712 glmDraw(GLMmodel* model, GLuint mode) | |
1713 { | |
1714 static GLuint i; | |
1715 static GLMgroup* group; | |
1716 static GLMtriangle* triangle; | |
1717 static GLMmaterial* material; | |
1718 | |
1719 assert(model); | |
1720 assert(model->vertices); | |
1721 | |
1722 /* do a bit of warning */ | |
1723 if (mode & GLM_FLAT && !model->facetnorms) { | |
1724 printf("glmDraw() warning: flat render mode requested " | |
1725 "with no facet normals defined.\n"); | |
1726 mode &= ~GLM_FLAT; | |
1727 } | |
1728 if (mode & GLM_SMOOTH && !model->normals) { | |
1729 printf("glmDraw() warning: smooth render mode requested " | |
1730 "with no normals defined.\n"); | |
1731 mode &= ~GLM_SMOOTH; | |
1732 } | |
1733 if (mode & GLM_TEXTURE && !model->texcoords) { | |
1734 printf("glmDraw() warning: texture render mode requested " | |
1735 "with no texture coordinates defined.\n"); | |
1736 mode &= ~GLM_TEXTURE; | |
1737 } | |
1738 if (mode & GLM_FLAT && mode & GLM_SMOOTH) { | |
1739 printf("glmDraw() warning: flat render mode requested " | |
1740 "and smooth render mode requested (using smooth).\n"); | |
1741 mode &= ~GLM_FLAT; | |
1742 } | |
1743 if (mode & GLM_COLOR && !model->materials) { | |
1744 printf("glmDraw() warning: color render mode requested " | |
1745 "with no materials defined.\n"); | |
1746 mode &= ~GLM_COLOR; | |
1747 } | |
1748 if (mode & GLM_MATERIAL && !model->materials) { | |
1749 printf("glmDraw() warning: material render mode requested " | |
1750 "with no materials defined.\n"); | |
1751 mode &= ~GLM_MATERIAL; | |
1752 } | |
1753 if (mode & GLM_COLOR && mode & GLM_MATERIAL) { | |
1754 printf("glmDraw() warning: color and material render mode requested " | |
1755 "using only material mode.\n"); | |
1756 mode &= ~GLM_COLOR; | |
1757 } | |
1758 if (mode & GLM_COLOR) | |
1759 glEnable(GL_COLOR_MATERIAL); | |
1760 else if (mode & GLM_MATERIAL) | |
1761 glDisable(GL_COLOR_MATERIAL); | |
1762 | |
1763 /* perhaps this loop should be unrolled into material, color, flat, | |
1764 smooth, etc. loops? since most cpu's have good branch prediction | |
1765 schemes (and these branches will always go one way), probably | |
1766 wouldn't gain too much? */ | |
1767 | |
1768 group = model->groups; | |
1769 while (group) { | |
1770 if (mode & GLM_MATERIAL) { | |
1771 material = &model->materials[group->material]; | |
1772 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient); | |
1773 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse); | |
1774 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material->specular); | |
1775 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material->shininess); | |
1776 } | |
1777 | |
1778 if (mode & GLM_COLOR) { | |
1779 glColor3fv(material->diffuse); | |
1780 } | |
1781 | |
1782 glBegin(GL_TRIANGLES); | |
1783 for (i = 0; i < group->numtriangles; i++) { | |
1784 triangle = &T(group->triangles[i]); | |
1785 | |
1786 if (mode & GLM_FLAT) | |
1787 glNormal3fv(&model->facetnorms[3 * triangle->findex]); | |
1788 | |
1789 if (mode & GLM_SMOOTH) | |
1790 glNormal3fv(&model->normals[3 * triangle->nindices[0]]); | |
1791 if (mode & GLM_TEXTURE) | |
1792 glTexCoord2fv(&model->texcoords[2 * triangle->tindices[0]]); | |
1793 glVertex3fv(&model->vertices[3 * triangle->vindices[0]]); | |
1794 | |
1795 if (mode & GLM_SMOOTH) | |
1796 glNormal3fv(&model->normals[3 * triangle->nindices[1]]); | |
1797 if (mode & GLM_TEXTURE) | |
1798 glTexCoord2fv(&model->texcoords[2 * triangle->tindices[1]]); | |
1799 glVertex3fv(&model->vertices[3 * triangle->vindices[1]]); | |
1800 | |
1801 if (mode & GLM_SMOOTH) | |
1802 glNormal3fv(&model->normals[3 * triangle->nindices[2]]); | |
1803 if (mode & GLM_TEXTURE) | |
1804 glTexCoord2fv(&model->texcoords[2 * triangle->tindices[2]]); | |
1805 glVertex3fv(&model->vertices[3 * triangle->vindices[2]]); | |
1806 | |
1807 } | |
1808 glEnd(); | |
1809 | |
1810 group = group->next; | |
1811 } | |
1812 } | |
1813 | |
1814 /* glmList: Generates and modelurns a display list for the model using | |
1815 * the mode specified. | |
1816 * | |
1817 * model - initialized GLMmodel structure | |
1818 * mode - a bitwise OR of values describing what is to be rendered. | |
1819 * GLM_NONE - render with only vertices | |
1820 * GLM_FLAT - render with facet normals | |
1821 * GLM_SMOOTH - render with vertex normals | |
1822 * GLM_TEXTURE - render with texture coords | |
1823 * GLM_COLOR - render with colors (color material) | |
1824 * GLM_MATERIAL - render with materials | |
1825 * GLM_COLOR and GLM_MATERIAL should not both be specified. | |
1826 * GLM_FLAT and GLM_SMOOTH should not both be specified. */ | |
1827 GLuint | |
1828 glmList(GLMmodel* model, GLuint mode) | |
1829 { | |
1830 GLuint list; | |
1831 | |
1832 list = glGenLists(1); | |
1833 glNewList(list, GL_COMPILE); | |
1834 glmDraw(model, mode); | |
1835 glEndList(); | |
1836 | |
1837 return list; | |
1838 } | |
1839 | |
1840 /* glmWeld: eliminate (weld) vectors that are within an epsilon of | |
1841 * each other. | |
1842 * | |
1843 * model - initialized GLMmodel structure | |
1844 * epsilon - maximum difference between vertices | |
1845 * ( 0.00001 is a good start for a unitized model) | |
1846 * | |
1847 */ | |
1848 GLvoid | |
1849 glmWeld(GLMmodel* model, GLfloat epsilon) | |
1850 { | |
1851 GLfloat* vectors; | |
1852 GLfloat* copies; | |
1853 GLuint numvectors; | |
1854 GLuint i; | |
1855 | |
1856 /* vertices */ | |
1857 numvectors = model->numvertices; | |
1858 vectors = model->vertices; | |
1859 copies = glmWeldVectors(vectors, &numvectors, epsilon); | |
1860 | |
1861 #if 0 | |
1862 printf("glmWeld(): %d redundant vertices.\n", | |
1863 model->numvertices - numvectors - 1); | |
1864 #endif | |
1865 | |
1866 for (i = 0; i < model->numtriangles; i++) { | |
1867 T(i).vindices[0] = (GLuint)vectors[3 * T(i).vindices[0] + 0]; | |
1868 T(i).vindices[1] = (GLuint)vectors[3 * T(i).vindices[1] + 0]; | |
1869 T(i).vindices[2] = (GLuint)vectors[3 * T(i).vindices[2] + 0]; | |
1870 } | |
1871 | |
1872 /* free space for old vertices */ | |
1873 free(vectors); | |
1874 | |
1875 /* allocate space for the new vertices */ | |
1876 model->numvertices = numvectors; | |
1877 model->vertices = (GLfloat*)malloc(sizeof(GLfloat) * | |
1878 3 * (model->numvertices + 1)); | |
1879 | |
1880 /* copy the optimized vertices into the actual vertex list */ | |
1881 for (i = 1; i <= model->numvertices; i++) { | |
1882 model->vertices[3 * i + 0] = copies[3 * i + 0]; | |
1883 model->vertices[3 * i + 1] = copies[3 * i + 1]; | |
1884 model->vertices[3 * i + 2] = copies[3 * i + 2]; | |
1885 } | |
1886 | |
1887 free(copies); | |
1888 } | |
1889 | |
1890 | |
1891 #if 0 | |
1892 /* normals */ | |
1893 if (model->numnormals) { | |
1894 numvectors = model->numnormals; | |
1895 vectors = model->normals; | |
1896 copies = glmOptimizeVectors(vectors, &numvectors); | |
1897 | |
1898 printf("glmOptimize(): %d redundant normals.\n", | |
1899 model->numnormals - numvectors); | |
1900 | |
1901 for (i = 0; i < model->numtriangles; i++) { | |
1902 T(i).nindices[0] = (GLuint)vectors[3 * T(i).nindices[0] + 0]; | |
1903 T(i).nindices[1] = (GLuint)vectors[3 * T(i).nindices[1] + 0]; | |
1904 T(i).nindices[2] = (GLuint)vectors[3 * T(i).nindices[2] + 0]; | |
1905 } | |
1906 | |
1907 /* free space for old normals */ | |
1908 free(vectors); | |
1909 | |
1910 /* allocate space for the new normals */ | |
1911 model->numnormals = numvectors; | |
1912 model->normals = (GLfloat*)malloc(sizeof(GLfloat) * | |
1913 3 * (model->numnormals + 1)); | |
1914 | |
1915 /* copy the optimized vertices into the actual vertex list */ | |
1916 for (i = 1; i <= model->numnormals; i++) { | |
1917 model->normals[3 * i + 0] = copies[3 * i + 0]; | |
1918 model->normals[3 * i + 1] = copies[3 * i + 1]; | |
1919 model->normals[3 * i + 2] = copies[3 * i + 2]; | |
1920 } | |
1921 | |
1922 free(copies); | |
1923 } | |
1924 | |
1925 /* texcoords */ | |
1926 if (model->numtexcoords) { | |
1927 numvectors = model->numtexcoords; | |
1928 vectors = model->texcoords; | |
1929 copies = glmOptimizeVectors(vectors, &numvectors); | |
1930 | |
1931 printf("glmOptimize(): %d redundant texcoords.\n", | |
1932 model->numtexcoords - numvectors); | |
1933 | |
1934 for (i = 0; i < model->numtriangles; i++) { | |
1935 for (j = 0; j < 3; j++) { | |
1936 T(i).tindices[j] = (GLuint)vectors[3 * T(i).tindices[j] + 0]; | |
1937 } | |
1938 } | |
1939 | |
1940 /* free space for old texcoords */ | |
1941 free(vectors); | |
1942 | |
1943 /* allocate space for the new texcoords */ | |
1944 model->numtexcoords = numvectors; | |
1945 model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * | |
1946 2 * (model->numtexcoords + 1)); | |
1947 | |
1948 /* copy the optimized vertices into the actual vertex list */ | |
1949 for (i = 1; i <= model->numtexcoords; i++) { | |
1950 model->texcoords[2 * i + 0] = copies[2 * i + 0]; | |
1951 model->texcoords[2 * i + 1] = copies[2 * i + 1]; | |
1952 } | |
1953 | |
1954 free(copies); | |
1955 } | |
1956 | |
1957 #endif | |
1958 | |
1959 #if 0 | |
1960 /* look for unused vertices */ | |
1961 /* look for unused normals */ | |
1962 /* look for unused texcoords */ | |
1963 for (i = 1; i <= model->numvertices; i++) { | |
1964 for (j = 0; j < model->numtriangles; i++) { | |
1965 if (T(j).vindices[0] == i || | |
1966 T(j).vindices[1] == i || | |
1967 T(j).vindices[1] == i) | |
1968 break; | |
1969 } | |
1970 } | |
1971 #endif |