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