summaryrefslogtreecommitdiff
path: root/progs/objviewer/glm.c
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2010-05-21 09:32:38 -0700
committerEric Anholt <eric@anholt.net>2010-05-21 12:20:39 -0700
commit68fc4b415e322f6744299e39864fbc377c6eff74 (patch)
tree4bafffd8b0105174f3c5c0ae327a005be9145990 /progs/objviewer/glm.c
parente4f4489e3fc0b36d72821b55794fb843b2b7fa5f (diff)
Remove demos that have moved to git+ssh://git.freedesktop.org/git/mesa/demos.
The remaining programs are ones I've had difficulty finding a build environment for to make the build system or are unit tests that should probably live next to their code instead. Hopefully people can bring over the build for remaining pieces they care about.
Diffstat (limited to 'progs/objviewer/glm.c')
-rw-r--r--progs/objviewer/glm.c1919
1 files changed, 0 insertions, 1919 deletions
diff --git a/progs/objviewer/glm.c b/progs/objviewer/glm.c
deleted file mode 100644
index 77e62bfab1..0000000000
--- a/progs/objviewer/glm.c
+++ /dev/null
@@ -1,1919 +0,0 @@
-/*
- * GLM library. Wavefront .obj file format reader/writer/manipulator.
- *
- * Written by Nate Robins, 1997.
- * email: ndr@pobox.com
- * www: http://www.pobox.com/~ndr
- */
-
-/* includes */
-#include <math.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include "glm.h"
-#include "readtex.h"
-
-
-typedef unsigned char boolean;
-#define TRUE 1
-#define FALSE 0
-
-
-/* Some <math.h> files do not define M_PI... */
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-/* defines */
-#define T(x) model->triangles[(x)]
-
-
-/* enums */
-enum { X, Y, Z, W }; /* elements of a vertex */
-
-
-/* typedefs */
-
-/* _GLMnode: general purpose node
- */
-typedef struct _GLMnode {
- uint index;
- boolean averaged;
- struct _GLMnode* next;
-} GLMnode;
-
-/* strdup is actually not a standard ANSI C or POSIX routine
- so implement a private one. OpenVMS does not have a strdup; Linux's
- standard libc doesn't declare strdup by default (unless BSD or SVID
- interfaces are requested). */
-static char *
-stralloc(const char *string)
-{
- char *copy;
-
- copy = malloc(strlen(string) + 1);
- if (copy == NULL)
- return NULL;
- strcpy(copy, string);
- return copy;
-}
-
-/* private functions */
-
-/* _glmMax: returns the maximum of two floats */
-static float
-_glmMax(float a, float b)
-{
- if (a > b)
- return a;
- return b;
-}
-
-/* _glmAbs: returns the absolute value of a float */
-static float
-_glmAbs(float f)
-{
- if (f < 0)
- return -f;
- return f;
-}
-
-/* _glmDot: compute the dot product of two vectors
- *
- * u - array of 3 floats (float u[3])
- * v - array of 3 floats (float v[3])
- */
-static float
-_glmDot(float* u, float* v)
-{
- assert(u);
- assert(v);
-
- /* compute the dot product */
- return u[X] * v[X] + u[Y] * v[Y] + u[Z] * v[Z];
-}
-
-/* _glmCross: compute the cross product of two vectors
- *
- * u - array of 3 floats (float u[3])
- * v - array of 3 floats (float v[3])
- * n - array of 3 floats (float n[3]) to return the cross product in
- */
-static void
-_glmCross(float* u, float* v, float* n)
-{
- assert(u);
- assert(v);
- assert(n);
-
- /* compute the cross product (u x v for right-handed [ccw]) */
- n[X] = u[Y] * v[Z] - u[Z] * v[Y];
- n[Y] = u[Z] * v[X] - u[X] * v[Z];
- n[Z] = u[X] * v[Y] - u[Y] * v[X];
-}
-
-/* _glmNormalize: normalize a vector
- *
- * n - array of 3 floats (float n[3]) to be normalized
- */
-static void
-_glmNormalize(float* n)
-{
- float l;
-
- assert(n);
-
- /* normalize */
- l = (float)sqrt(n[X] * n[X] + n[Y] * n[Y] + n[Z] * n[Z]);
- n[0] /= l;
- n[1] /= l;
- n[2] /= l;
-}
-
-/* _glmEqual: compares two vectors and returns TRUE if they are
- * equal (within a certain threshold) or FALSE if not. An epsilon
- * that works fairly well is 0.000001.
- *
- * u - array of 3 floats (float u[3])
- * v - array of 3 floats (float v[3])
- */
-static boolean
-_glmEqual(float* u, float* v, float epsilon)
-{
- if (_glmAbs(u[0] - v[0]) < epsilon &&
- _glmAbs(u[1] - v[1]) < epsilon &&
- _glmAbs(u[2] - v[2]) < epsilon)
- {
- return TRUE;
- }
- return FALSE;
-}
-
-/* _glmWeldVectors: eliminate (weld) vectors that are within an
- * epsilon of each other.
- *
- * vectors - array of float[3]'s to be welded
- * numvectors - number of float[3]'s in vectors
- * epsilon - maximum difference between vectors
- *
- */
-static float*
-_glmWeldVectors(float* vectors, uint* numvectors, float epsilon)
-{
- float* copies;
- uint copied;
- uint i, j;
-
- copies = (float*)malloc(sizeof(float) * 3 * (*numvectors + 1));
- memcpy(copies, vectors, (sizeof(float) * 3 * (*numvectors + 1)));
-
- copied = 1;
- for (i = 1; i <= *numvectors; i++) {
- for (j = 1; j <= copied; j++) {
- if (_glmEqual(&vectors[3 * i], &copies[3 * j], epsilon)) {
- goto duplicate;
- }
- }
-
- /* must not be any duplicates -- add to the copies array */
- copies[3 * copied + 0] = vectors[3 * i + 0];
- copies[3 * copied + 1] = vectors[3 * i + 1];
- copies[3 * copied + 2] = vectors[3 * i + 2];
- j = copied; /* pass this along for below */
- copied++;
-
- duplicate:
- /* set the first component of this vector to point at the correct
- index into the new copies array */
- vectors[3 * i + 0] = (float)j;
- }
-
- *numvectors = copied-1;
- return copies;
-}
-
-/* _glmFindGroup: Find a group in the model
- */
-static GLMgroup*
-_glmFindGroup(GLMmodel* model, char* name)
-{
- GLMgroup* group;
-
- assert(model);
-
- group = model->groups;
- while(group) {
- if (!strcmp(name, group->name))
- break;
- group = group->next;
- }
-
- return group;
-}
-
-/* _glmAddGroup: Add a group to the model
- */
-static GLMgroup*
-_glmAddGroup(GLMmodel* model, char* name)
-{
- GLMgroup* group;
-
- group = _glmFindGroup(model, name);
- if (!group) {
- group = (GLMgroup*)malloc(sizeof(GLMgroup));
- group->name = stralloc(name);
- group->material = 0;
- group->numtriangles = 0;
- group->triangles = NULL;
- group->next = model->groups;
- model->groups = group;
- model->numgroups++;
- }
-
- return group;
-}
-
-/* _glmFindGroup: Find a material in the model
- */
-static uint
-_glmFindMaterial(GLMmodel* model, char* name)
-{
- uint i;
-
- for (i = 0; i < model->nummaterials; i++) {
- if (!strcmp(model->materials[i].name, name))
- goto found;
- }
-
- /* didn't find the name, so set it as the default material */
- printf("_glmFindMaterial(): can't find material \"%s\".\n", name);
- i = 0;
-
-found:
- return i;
-}
-
-
-/* _glmDirName: return the directory given a path
- *
- * path - filesystem path
- *
- * The return value should be free'd.
- */
-static char*
-_glmDirName(char* path)
-{
- char* dir;
- char* s;
-
- dir = stralloc(path);
-
- s = strrchr(dir, '/');
- if (s)
- s[1] = '\0';
- else
- dir[0] = '\0';
-
- return dir;
-}
-
-
-/* _glmReadMTL: read a wavefront material library file
- *
- * model - properly initialized GLMmodel structure
- * name - name of the material library
- */
-static void
-_glmReadMTL(GLMmodel* model, char* name)
-{
- FILE* file;
- char* dir;
- char* filename;
- char buf[128], buf2[128];
- uint nummaterials, i;
- GLMmaterial *mat;
-
- dir = _glmDirName(model->pathname);
- filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(name) + 1));
- strcpy(filename, dir);
- strcat(filename, name);
- free(dir);
-
- /* open the file */
- file = fopen(filename, "r");
- if (!file) {
- fprintf(stderr, "_glmReadMTL() failed: can't open material file \"%s\".\n",
- filename);
- exit(1);
- }
- free(filename);
-
- /* count the number of materials in the file */
- nummaterials = 1;
- while(fscanf(file, "%s", buf) != EOF) {
- switch(buf[0]) {
- case '#': /* comment */
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- break;
- case 'n': /* newmtl */
- fgets(buf, sizeof(buf), file);
- nummaterials++;
- sscanf(buf, "%s %s", buf, buf);
- break;
- default:
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- break;
- }
- }
-
- rewind(file);
-
- /* allocate memory for the materials */
- model->materials = (GLMmaterial*)calloc(nummaterials, sizeof(GLMmaterial));
- model->nummaterials = nummaterials;
-
- /* set the default material */
- for (i = 0; i < nummaterials; i++) {
- model->materials[i].name = NULL;
- model->materials[i].shininess = 0;
- model->materials[i].diffuse[0] = 0.8;
- model->materials[i].diffuse[1] = 0.8;
- model->materials[i].diffuse[2] = 0.8;
- model->materials[i].diffuse[3] = 1.0;
- model->materials[i].ambient[0] = 0.2;
- model->materials[i].ambient[1] = 0.2;
- model->materials[i].ambient[2] = 0.2;
- model->materials[i].ambient[3] = 0.0;
- model->materials[i].specular[0] = 0.0;
- model->materials[i].specular[1] = 0.0;
- model->materials[i].specular[2] = 0.0;
- model->materials[i].specular[3] = 0.0;
- }
- model->materials[0].name = stralloc("default");
-
- /* now, read in the data */
- nummaterials = 0;
-
- mat = &model->materials[nummaterials];
-
- while(fscanf(file, "%s", buf) != EOF) {
- switch(buf[0]) {
- case '#': /* comment */
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- break;
- case 'n': /* newmtl */
- fgets(buf, sizeof(buf), file);
- sscanf(buf, "%s %s", buf, buf);
- nummaterials++;
- model->materials[nummaterials].name = stralloc(buf);
- break;
- case 'N':
- fscanf(file, "%f", &model->materials[nummaterials].shininess);
- /* wavefront shininess is from [0, 1000], so scale for OpenGL */
- model->materials[nummaterials].shininess /= 1000.0;
- model->materials[nummaterials].shininess *= 128.0;
- mat = &model->materials[nummaterials];
- break;
- case 'K':
- switch(buf[1]) {
- case 'd':
- fscanf(file, "%f %f %f",
- &model->materials[nummaterials].diffuse[0],
- &model->materials[nummaterials].diffuse[1],
- &model->materials[nummaterials].diffuse[2]);
- break;
- case 's':
- fscanf(file, "%f %f %f",
- &model->materials[nummaterials].specular[0],
- &model->materials[nummaterials].specular[1],
- &model->materials[nummaterials].specular[2]);
- break;
- case 'a':
- fscanf(file, "%f %f %f",
- &model->materials[nummaterials].ambient[0],
- &model->materials[nummaterials].ambient[1],
- &model->materials[nummaterials].ambient[2]);
- break;
- default:
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- break;
- }
- break;
- case 'd': /* alpha? */
- fscanf(file, "%f",
- &model->materials[nummaterials].diffuse[3]);
- break;
- case 'm': /* texture map */
- fscanf(file, "%s", buf2);
- /*printf("map %s\n", buf2);*/
- mat->map_kd = strdup(buf2);
- break;
-
- default:
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- break;
- }
- }
- fclose(file);
-}
-
-
-/* _glmWriteMTL: write a wavefront material library file
- *
- * model - properly initialized GLMmodel structure
- * modelpath - pathname of the model being written
- * mtllibname - name of the material library to be written
- */
-static void
-_glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname)
-{
- FILE* file;
- char* dir;
- char* filename;
- GLMmaterial* material;
- uint i;
-
- dir = _glmDirName(modelpath);
- filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(mtllibname)));
- strcpy(filename, dir);
- strcat(filename, mtllibname);
- free(dir);
-
- /* open the file */
- file = fopen(filename, "w");
- if (!file) {
- fprintf(stderr, "_glmWriteMTL() failed: can't open file \"%s\".\n",
- filename);
- exit(1);
- }
- free(filename);
-
- /* spit out a header */
- fprintf(file, "# \n");
- fprintf(file, "# Wavefront MTL generated by GLM library\n");
- fprintf(file, "# \n");
- fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n");
- fprintf(file, "# email: ndr@pobox.com\n");
- fprintf(file, "# www: http://www.pobox.com/~ndr\n");
- fprintf(file, "# \n\n");
-
- for (i = 0; i < model->nummaterials; i++) {
- material = &model->materials[i];
- fprintf(file, "newmtl %s\n", material->name);
- fprintf(file, "Ka %f %f %f\n",
- material->ambient[0], material->ambient[1], material->ambient[2]);
- fprintf(file, "Kd %f %f %f\n",
- material->diffuse[0], material->diffuse[1], material->diffuse[2]);
- fprintf(file, "Ks %f %f %f\n",
- material->specular[0],material->specular[1],material->specular[2]);
- fprintf(file, "Ns %f\n", material->shininess);
- fprintf(file, "\n");
- }
- fclose(file);
-}
-
-
-/* _glmFirstPass: first pass at a Wavefront OBJ file that gets all the
- * statistics of the model (such as #vertices, #normals, etc)
- *
- * model - properly initialized GLMmodel structure
- * file - (fopen'd) file descriptor
- */
-static void
-_glmFirstPass(GLMmodel* model, FILE* file)
-{
- uint numvertices; /* number of vertices in model */
- uint numnormals; /* number of normals in model */
- uint numtexcoords; /* number of texcoords in model */
- uint numtriangles; /* number of triangles in model */
- GLMgroup* group; /* current group */
- unsigned v, n, t;
- char buf[128];
-
- /* make a default group */
- group = _glmAddGroup(model, "default");
-
- numvertices = numnormals = numtexcoords = numtriangles = 0;
- while(fscanf(file, "%s", buf) != EOF) {
- switch(buf[0]) {
- case '#': /* comment */
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- break;
- case 'v': /* v, vn, vt */
- switch(buf[1]) {
- case '\0': /* vertex */
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- numvertices++;
- break;
- case 'n': /* normal */
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- numnormals++;
- break;
- case 't': /* texcoord */
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- numtexcoords++;
- break;
- default:
- printf("_glmFirstPass(): Unknown token \"%s\".\n", buf);
- exit(1);
- break;
- }
- break;
- case 'm':
- fgets(buf, sizeof(buf), file);
- sscanf(buf, "%s %s", buf, buf);
- model->mtllibname = stralloc(buf);
- _glmReadMTL(model, buf);
- break;
- case 'u':
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- break;
- case 'g': /* group */
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- sscanf(buf, "%s", buf);
- group = _glmAddGroup(model, buf);
- break;
- case 'f': /* face */
- v = n = t = 0;
- fscanf(file, "%s", buf);
- /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
- if (strstr(buf, "//")) {
- /* v//n */
- sscanf(buf, "%u//%u", &v, &n);
- fscanf(file, "%u//%u", &v, &n);
- fscanf(file, "%u//%u", &v, &n);
- numtriangles++;
- group->numtriangles++;
- while(fscanf(file, "%u//%u", &v, &n) > 0) {
- numtriangles++;
- group->numtriangles++;
- }
- } else if (sscanf(buf, "%u/%u/%u", &v, &t, &n) == 3) {
- /* v/t/n */
- fscanf(file, "%u/%u/%u", &v, &t, &n);
- fscanf(file, "%u/%u/%u", &v, &t, &n);
- numtriangles++;
- group->numtriangles++;
- while(fscanf(file, "%u/%u/%u", &v, &t, &n) > 0) {
- numtriangles++;
- group->numtriangles++;
- }
- } else if (sscanf(buf, "%u/%u", &v, &t) == 2) {
- /* v/t */
- fscanf(file, "%u/%u", &v, &t);
- fscanf(file, "%u/%u", &v, &t);
- numtriangles++;
- group->numtriangles++;
- while(fscanf(file, "%u/%u", &v, &t) > 0) {
- numtriangles++;
- group->numtriangles++;
- }
- } else {
- /* v */
- fscanf(file, "%u", &v);
- fscanf(file, "%u", &v);
- numtriangles++;
- group->numtriangles++;
- while(fscanf(file, "%u", &v) > 0) {
- numtriangles++;
- group->numtriangles++;
- }
- }
- break;
-
- default:
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- break;
- }
- }
-
-#if 0
- /* announce the model statistics */
- printf(" Vertices: %d\n", numvertices);
- printf(" Normals: %d\n", numnormals);
- printf(" Texcoords: %d\n", numtexcoords);
- printf(" Triangles: %d\n", numtriangles);
- printf(" Groups: %d\n", model->numgroups);
-#endif
-
- /* set the stats in the model structure */
- model->numvertices = numvertices;
- model->numnormals = numnormals;
- model->numtexcoords = numtexcoords;
- model->numtriangles = numtriangles;
-
- /* allocate memory for the triangles in each group */
- group = model->groups;
- while(group) {
- group->triangles = (uint*)malloc(sizeof(uint) * group->numtriangles);
- group->numtriangles = 0;
- group = group->next;
- }
-}
-
-/* _glmSecondPass: second pass at a Wavefront OBJ file that gets all
- * the data.
- *
- * model - properly initialized GLMmodel structure
- * file - (fopen'd) file descriptor
- */
-static void
-_glmSecondPass(GLMmodel* model, FILE* file)
-{
- uint numvertices; /* number of vertices in model */
- uint numnormals; /* number of normals in model */
- uint numtexcoords; /* number of texcoords in model */
- uint numtriangles; /* number of triangles in model */
- float* vertices; /* array of vertices */
- float* normals; /* array of normals */
- float* texcoords; /* array of texture coordinates */
- GLMgroup* group; /* current group pointer */
- uint material; /* current material */
- uint v, n, t;
- char buf[128];
-
- /* set the pointer shortcuts */
- vertices = model->vertices;
- normals = model->normals;
- texcoords = model->texcoords;
- group = model->groups;
-
- /* on the second pass through the file, read all the data into the
- allocated arrays */
- numvertices = numnormals = numtexcoords = 1;
- numtriangles = 0;
- material = 0;
- while(fscanf(file, "%s", buf) != EOF) {
- switch(buf[0]) {
- case '#': /* comment */
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- break;
- case 'v': /* v, vn, vt */
- switch(buf[1]) {
- case '\0': /* vertex */
- fscanf(file, "%f %f %f",
- &vertices[3 * numvertices + X],
- &vertices[3 * numvertices + Y],
- &vertices[3 * numvertices + Z]);
- numvertices++;
- break;
- case 'n': /* normal */
- fscanf(file, "%f %f %f",
- &normals[3 * numnormals + X],
- &normals[3 * numnormals + Y],
- &normals[3 * numnormals + Z]);
- numnormals++;
- break;
- case 't': /* texcoord */
- fscanf(file, "%f %f",
- &texcoords[2 * numtexcoords + X],
- &texcoords[2 * numtexcoords + Y]);
- numtexcoords++;
- break;
- }
- break;
- case 'u':
- fgets(buf, sizeof(buf), file);
- sscanf(buf, "%s %s", buf, buf);
- material = _glmFindMaterial(model, buf);
- if (!group->material)
- group->material = material;
- /*printf("material %s = %u\n", buf, material);*/
- break;
- case 'g': /* group */
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- sscanf(buf, "%s", buf);
- group = _glmFindGroup(model, buf);
- group->material = material;
- /*printf("GROUP %s material %u\n", buf, material);*/
- break;
- case 'f': /* face */
- v = n = t = 0;
- fscanf(file, "%s", buf);
- /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
- if (strstr(buf, "//")) {
- /* v//n */
- sscanf(buf, "%u//%u", &v, &n);
- T(numtriangles).vindices[0] = v;
- T(numtriangles).nindices[0] = n;
- fscanf(file, "%u//%u", &v, &n);
- T(numtriangles).vindices[1] = v;
- T(numtriangles).nindices[1] = n;
- fscanf(file, "%u//%u", &v, &n);
- T(numtriangles).vindices[2] = v;
- T(numtriangles).nindices[2] = n;
- group->triangles[group->numtriangles++] = numtriangles;
- numtriangles++;
- while(fscanf(file, "%u//%u", &v, &n) > 0) {
- T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
- T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0];
- T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
- T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2];
- T(numtriangles).vindices[2] = v;
- T(numtriangles).nindices[2] = n;
- group->triangles[group->numtriangles++] = numtriangles;
- numtriangles++;
- }
- } else if (sscanf(buf, "%u/%u/%u", &v, &t, &n) == 3) {
- /* v/t/n */
- T(numtriangles).vindices[0] = v;
- T(numtriangles).tindices[0] = t;
- T(numtriangles).nindices[0] = n;
- fscanf(file, "%u/%u/%u", &v, &t, &n);
- T(numtriangles).vindices[1] = v;
- T(numtriangles).tindices[1] = t;
- T(numtriangles).nindices[1] = n;
- fscanf(file, "%u/%u/%u", &v, &t, &n);
- T(numtriangles).vindices[2] = v;
- T(numtriangles).tindices[2] = t;
- T(numtriangles).nindices[2] = n;
- group->triangles[group->numtriangles++] = numtriangles;
- numtriangles++;
- while(fscanf(file, "%u/%u/%u", &v, &t, &n) > 0) {
- T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
- T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0];
- T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0];
- T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
- T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2];
- T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2];
- T(numtriangles).vindices[2] = v;
- T(numtriangles).tindices[2] = t;
- T(numtriangles).nindices[2] = n;
- group->triangles[group->numtriangles++] = numtriangles;
- numtriangles++;
- }
- } else if (sscanf(buf, "%u/%u", &v, &t) == 2) {
- /* v/t */
- T(numtriangles).vindices[0] = v;
- T(numtriangles).tindices[0] = t;
- fscanf(file, "%u/%u", &v, &t);
- T(numtriangles).vindices[1] = v;
- T(numtriangles).tindices[1] = t;
- fscanf(file, "%u/%u", &v, &t);
- T(numtriangles).vindices[2] = v;
- T(numtriangles).tindices[2] = t;
- group->triangles[group->numtriangles++] = numtriangles;
- numtriangles++;
- while(fscanf(file, "%u/%u", &v, &t) > 0) {
- T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
- T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0];
- T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
- T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2];
- T(numtriangles).vindices[2] = v;
- T(numtriangles).tindices[2] = t;
- group->triangles[group->numtriangles++] = numtriangles;
- numtriangles++;
- }
- } else {
- /* v */
- sscanf(buf, "%u", &v);
- T(numtriangles).vindices[0] = v;
- fscanf(file, "%u", &v);
- T(numtriangles).vindices[1] = v;
- fscanf(file, "%u", &v);
- T(numtriangles).vindices[2] = v;
- group->triangles[group->numtriangles++] = numtriangles;
- numtriangles++;
- while(fscanf(file, "%u", &v) > 0) {
- T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
- T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
- T(numtriangles).vindices[2] = v;
- group->triangles[group->numtriangles++] = numtriangles;
- numtriangles++;
- }
- }
- break;
-
- default:
- /* eat up rest of line */
- fgets(buf, sizeof(buf), file);
- break;
- }
- }
-
-#if 0
- /* announce the memory requirements */
- printf(" Memory: %d bytes\n",
- numvertices * 3*sizeof(float) +
- numnormals * 3*sizeof(float) * (numnormals ? 1 : 0) +
- numtexcoords * 3*sizeof(float) * (numtexcoords ? 1 : 0) +
- numtriangles * sizeof(GLMtriangle));
-#endif
-}
-
-
-
-
-/* public functions */
-
-/* glmUnitize: "unitize" a model by translating it to the origin and
- * scaling it to fit in a unit cube around the origin. Returns the
- * scalefactor used.
- *
- * model - properly initialized GLMmodel structure
- */
-float
-glmUnitize(GLMmodel* model)
-{
- uint i;
- float maxx, minx, maxy, miny, maxz, minz;
- float cx, cy, cz, w, h, d;
- float scale;
-
- assert(model);
- assert(model->vertices);
-
- /* get the max/mins */
- maxx = minx = model->vertices[3 + X];
- maxy = miny = model->vertices[3 + Y];
- maxz = minz = model->vertices[3 + Z];
- for (i = 1; i <= model->numvertices; i++) {
- if (maxx < model->vertices[3 * i + X])
- maxx = model->vertices[3 * i + X];
- if (minx > model->vertices[3 * i + X])
- minx = model->vertices[3 * i + X];
-
- if (maxy < model->vertices[3 * i + Y])
- maxy = model->vertices[3 * i + Y];
- if (miny > model->vertices[3 * i + Y])
- miny = model->vertices[3 * i + Y];
-
- if (maxz < model->vertices[3 * i + Z])
- maxz = model->vertices[3 * i + Z];
- if (minz > model->vertices[3 * i + Z])
- minz = model->vertices[3 * i + Z];
- }
-
- /* calculate model width, height, and depth */
- w = _glmAbs(maxx) + _glmAbs(minx);
- h = _glmAbs(maxy) + _glmAbs(miny);
- d = _glmAbs(maxz) + _glmAbs(minz);
-
- /* calculate center of the model */
- cx = (maxx + minx) / 2.0;
- cy = (maxy + miny) / 2.0;
- cz = (maxz + minz) / 2.0;
-
- /* calculate unitizing scale factor */
- scale = 2.0 / _glmMax(_glmMax(w, h), d);
-
- /* translate around center then scale */
- for (i = 1; i <= model->numvertices; i++) {
- model->vertices[3 * i + X] -= cx;
- model->vertices[3 * i + Y] -= cy;
- model->vertices[3 * i + Z] -= cz;
- model->vertices[3 * i + X] *= scale;
- model->vertices[3 * i + Y] *= scale;
- model->vertices[3 * i + Z] *= scale;
- }
-
- return scale;
-}
-
-/* glmDimensions: Calculates the dimensions (width, height, depth) of
- * a model.
- *
- * model - initialized GLMmodel structure
- * dimensions - array of 3 floats (float dimensions[3])
- */
-void
-glmDimensions(GLMmodel* model, float* dimensions)
-{
- uint i;
- float maxx, minx, maxy, miny, maxz, minz;
-
- assert(model);
- assert(model->vertices);
- assert(dimensions);
-
- /* get the max/mins */
- maxx = minx = model->vertices[3 + X];
- maxy = miny = model->vertices[3 + Y];
- maxz = minz = model->vertices[3 + Z];
- for (i = 1; i <= model->numvertices; i++) {
- if (maxx < model->vertices[3 * i + X])
- maxx = model->vertices[3 * i + X];
- if (minx > model->vertices[3 * i + X])
- minx = model->vertices[3 * i + X];
-
- if (maxy < model->vertices[3 * i + Y])
- maxy = model->vertices[3 * i + Y];
- if (miny > model->vertices[3 * i + Y])
- miny = model->vertices[3 * i + Y];
-
- if (maxz < model->vertices[3 * i + Z])
- maxz = model->vertices[3 * i + Z];
- if (minz > model->vertices[3 * i + Z])
- minz = model->vertices[3 * i + Z];
- }
-
- /* calculate model width, height, and depth */
- dimensions[X] = _glmAbs(maxx) + _glmAbs(minx);
- dimensions[Y] = _glmAbs(maxy) + _glmAbs(miny);
- dimensions[Z] = _glmAbs(maxz) + _glmAbs(minz);
-}
-
-/* glmScale: Scales a model by a given amount.
- *
- * model - properly initialized GLMmodel structure
- * scale - scalefactor (0.5 = half as large, 2.0 = twice as large)
- */
-void
-glmScale(GLMmodel* model, float scale)
-{
- uint i;
-
- for (i = 1; i <= model->numvertices; i++) {
- model->vertices[3 * i + X] *= scale;
- model->vertices[3 * i + Y] *= scale;
- model->vertices[3 * i + Z] *= scale;
- }
-}
-
-/* glmReverseWinding: Reverse the polygon winding for all polygons in
- * this model. Default winding is counter-clockwise. Also changes
- * the direction of the normals.
- *
- * model - properly initialized GLMmodel structure
- */
-void
-glmReverseWinding(GLMmodel* model)
-{
- uint i, swap;
-
- assert(model);
-
- for (i = 0; i < model->numtriangles; i++) {
- swap = T(i).vindices[0];
- T(i).vindices[0] = T(i).vindices[2];
- T(i).vindices[2] = swap;
-
- if (model->numnormals) {
- swap = T(i).nindices[0];
- T(i).nindices[0] = T(i).nindices[2];
- T(i).nindices[2] = swap;
- }
-
- if (model->numtexcoords) {
- swap = T(i).tindices[0];
- T(i).tindices[0] = T(i).tindices[2];
- T(i).tindices[2] = swap;
- }
- }
-
- /* reverse facet normals */
- for (i = 1; i <= model->numfacetnorms; i++) {
- model->facetnorms[3 * i + X] = -model->facetnorms[3 * i + X];
- model->facetnorms[3 * i + Y] = -model->facetnorms[3 * i + Y];
- model->facetnorms[3 * i + Z] = -model->facetnorms[3 * i + Z];
- }
-
- /* reverse vertex normals */
- for (i = 1; i <= model->numnormals; i++) {
- model->normals[3 * i + X] = -model->normals[3 * i + X];
- model->normals[3 * i + Y] = -model->normals[3 * i + Y];
- model->normals[3 * i + Z] = -model->normals[3 * i + Z];
- }
-}
-
-/* glmFacetNormals: Generates facet normals for a model (by taking the
- * cross product of the two vectors derived from the sides of each
- * triangle). Assumes a counter-clockwise winding.
- *
- * model - initialized GLMmodel structure
- */
-void
-glmFacetNormals(GLMmodel* model)
-{
- uint i;
- float u[3];
- float v[3];
-
- assert(model);
- assert(model->vertices);
-
- /* clobber any old facetnormals */
- if (model->facetnorms)
- free(model->facetnorms);
-
- /* allocate memory for the new facet normals */
- model->numfacetnorms = model->numtriangles;
- model->facetnorms = (float*)malloc(sizeof(float) *
- 3 * (model->numfacetnorms + 1));
-
- for (i = 0; i < model->numtriangles; i++) {
- model->triangles[i].findex = i+1;
-
- u[X] = model->vertices[3 * T(i).vindices[1] + X] -
- model->vertices[3 * T(i).vindices[0] + X];
- u[Y] = model->vertices[3 * T(i).vindices[1] + Y] -
- model->vertices[3 * T(i).vindices[0] + Y];
- u[Z] = model->vertices[3 * T(i).vindices[1] + Z] -
- model->vertices[3 * T(i).vindices[0] + Z];
-
- v[X] = model->vertices[3 * T(i).vindices[2] + X] -
- model->vertices[3 * T(i).vindices[0] + X];
- v[Y] = model->vertices[3 * T(i).vindices[2] + Y] -
- model->vertices[3 * T(i).vindices[0] + Y];
- v[Z] = model->vertices[3 * T(i).vindices[2] + Z] -
- model->vertices[3 * T(i).vindices[0] + Z];
-
- _glmCross(u, v, &model->facetnorms[3 * (i+1)]);
- _glmNormalize(&model->facetnorms[3 * (i+1)]);
- }
-}
-
-/* glmVertexNormals: Generates smooth vertex normals for a model.
- * First builds a list of all the triangles each vertex is in. Then
- * loops through each vertex in the list averaging all the facet
- * normals of the triangles each vertex is in. Finally, sets the
- * normal index in the triangle for the vertex to the generated smooth
- * normal. If the dot product of a facet normal and the facet normal
- * associated with the first triangle in the list of triangles the
- * current vertex is in is greater than the cosine of the angle
- * parameter to the function, that facet normal is not added into the
- * average normal calculation and the corresponding vertex is given
- * the facet normal. This tends to preserve hard edges. The angle to
- * use depends on the model, but 90 degrees is usually a good start.
- *
- * model - initialized GLMmodel structure
- * angle - maximum angle (in degrees) to smooth across
- */
-void
-glmVertexNormals(GLMmodel* model, float angle)
-{
- GLMnode* node;
- GLMnode* tail;
- GLMnode** members;
- float* normals;
- uint numnormals;
- float average[3];
- float dot, cos_angle;
- uint i, avg;
-
- assert(model);
- assert(model->facetnorms);
-
- /* calculate the cosine of the angle (in degrees) */
- cos_angle = cos(angle * M_PI / 180.0);
-
- /* nuke any previous normals */
- if (model->normals)
- free(model->normals);
-
- /* allocate space for new normals */
- model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */
- model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1));
-
- /* allocate a structure that will hold a linked list of triangle
- indices for each vertex */
- members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1));
- for (i = 1; i <= model->numvertices; i++)
- members[i] = NULL;
-
- /* for every triangle, create a node for each vertex in it */
- for (i = 0; i < model->numtriangles; i++) {
- node = (GLMnode*)malloc(sizeof(GLMnode));
- node->index = i;
- node->next = members[T(i).vindices[0]];
- members[T(i).vindices[0]] = node;
-
- node = (GLMnode*)malloc(sizeof(GLMnode));
- node->index = i;
- node->next = members[T(i).vindices[1]];
- members[T(i).vindices[1]] = node;
-
- node = (GLMnode*)malloc(sizeof(GLMnode));
- node->index = i;
- node->next = members[T(i).vindices[2]];
- members[T(i).vindices[2]] = node;
- }
-
- /* calculate the average normal for each vertex */
- numnormals = 1;
- for (i = 1; i <= model->numvertices; i++) {
- /* calculate an average normal for this vertex by averaging the
- facet normal of every triangle this vertex is in */
- node = members[i];
- if (!node)
- fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n");
- average[0] = 0.0; average[1] = 0.0; average[2] = 0.0;
- avg = 0;
- while (node) {
- /* only average if the dot product of the angle between the two
- facet normals is greater than the cosine of the threshold
- angle -- or, said another way, the angle between the two
- facet normals is less than (or equal to) the threshold angle */
- dot = _glmDot(&model->facetnorms[3 * T(node->index).findex],
- &model->facetnorms[3 * T(members[i]->index).findex]);
- if (dot > cos_angle) {
- node->averaged = TRUE;
- average[0] += model->facetnorms[3 * T(node->index).findex + 0];
- average[1] += model->facetnorms[3 * T(node->index).findex + 1];
- average[2] += model->facetnorms[3 * T(node->index).findex + 2];
- avg = 1; /* we averaged at least one normal! */
- } else {
- node->averaged = FALSE;
- }
- node = node->next;
- }
-
- if (avg) {
- /* normalize the averaged normal */
- _glmNormalize(average);
-
- /* add the normal to the vertex normals list */
- model->normals[3 * numnormals + 0] = average[0];
- model->normals[3 * numnormals + 1] = average[1];
- model->normals[3 * numnormals + 2] = average[2];
- avg = numnormals;
- numnormals++;
- }
-
- /* set the normal of this vertex in each triangle it is in */
- node = members[i];
- while (node) {
- if (node->averaged) {
- /* if this node was averaged, use the average normal */
- if (T(node->index).vindices[0] == i)
- T(node->index).nindices[0] = avg;
- else if (T(node->index).vindices[1] == i)
- T(node->index).nindices[1] = avg;
- else if (T(node->index).vindices[2] == i)
- T(node->index).nindices[2] = avg;
- } else {
- /* if this node wasn't averaged, use the facet normal */
- model->normals[3 * numnormals + 0] =
- model->facetnorms[3 * T(node->index).findex + 0];
- model->normals[3 * numnormals + 1] =
- model->facetnorms[3 * T(node->index).findex + 1];
- model->normals[3 * numnormals + 2] =
- model->facetnorms[3 * T(node->index).findex + 2];
- if (T(node->index).vindices[0] == i)
- T(node->index).nindices[0] = numnormals;
- else if (T(node->index).vindices[1] == i)
- T(node->index).nindices[1] = numnormals;
- else if (T(node->index).vindices[2] == i)
- T(node->index).nindices[2] = numnormals;
- numnormals++;
- }
- node = node->next;
- }
- }
-
- model->numnormals = numnormals - 1;
-
- /* free the member information */
- for (i = 1; i <= model->numvertices; i++) {
- node = members[i];
- while (node) {
- tail = node;
- node = node->next;
- free(tail);
- }
- }
- free(members);
-
- /* pack the normals array (we previously allocated the maximum
- number of normals that could possibly be created (numtriangles *
- 3), so get rid of some of them (usually alot unless none of the
- facet normals were averaged)) */
- normals = model->normals;
- model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1));
- for (i = 1; i <= model->numnormals; i++) {
- model->normals[3 * i + 0] = normals[3 * i + 0];
- model->normals[3 * i + 1] = normals[3 * i + 1];
- model->normals[3 * i + 2] = normals[3 * i + 2];
- }
- free(normals);
-
- printf("glmVertexNormals(): %d normals generated\n", model->numnormals);
-}
-
-
-/* glmLinearTexture: Generates texture coordinates according to a
- * linear projection of the texture map. It generates these by
- * linearly mapping the vertices onto a square.
- *
- * model - pointer to initialized GLMmodel structure
- */
-void
-glmLinearTexture(GLMmodel* model)
-{
- GLMgroup *group;
- float dimensions[3];
- float x, y, scalefactor;
- uint i;
-
- assert(model);
-
- if (model->texcoords)
- free(model->texcoords);
- model->numtexcoords = model->numvertices;
- model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1));
-
- glmDimensions(model, dimensions);
- scalefactor = 2.0 /
- _glmAbs(_glmMax(_glmMax(dimensions[0], dimensions[1]), dimensions[2]));
-
- /* do the calculations */
- for(i = 1; i <= model->numvertices; i++) {
- x = model->vertices[3 * i + 0] * scalefactor;
- y = model->vertices[3 * i + 2] * scalefactor;
- model->texcoords[2 * i + 0] = (x + 1.0) / 2.0;
- model->texcoords[2 * i + 1] = (y + 1.0) / 2.0;
- }
-
- /* go through and put texture coordinate indices in all the triangles */
- group = model->groups;
- while(group) {
- for(i = 0; i < group->numtriangles; i++) {
- T(group->triangles[i]).tindices[0] = T(group->triangles[i]).vindices[0];
- T(group->triangles[i]).tindices[1] = T(group->triangles[i]).vindices[1];
- T(group->triangles[i]).tindices[2] = T(group->triangles[i]).vindices[2];
- }
- group = group->next;
- }
-
-#if 0
- printf("glmLinearTexture(): generated %d linear texture coordinates\n",
- model->numtexcoords);
-#endif
-}
-
-/* glmSpheremapTexture: Generates texture coordinates according to a
- * spherical projection of the texture map. Sometimes referred to as
- * spheremap, or reflection map texture coordinates. It generates
- * these by using the normal to calculate where that vertex would map
- * onto a sphere. Since it is impossible to map something flat
- * perfectly onto something spherical, there is distortion at the
- * poles. This particular implementation causes the poles along the X
- * axis to be distorted.
- *
- * model - pointer to initialized GLMmodel structure
- */
-void
-glmSpheremapTexture(GLMmodel* model)
-{
- GLMgroup* group;
- float theta, phi, rho, x, y, z, r;
- uint i;
-
- assert(model);
- assert(model->normals);
-
- if (model->texcoords)
- free(model->texcoords);
- model->numtexcoords = model->numnormals;
- model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1));
-
- /* do the calculations */
- for (i = 1; i <= model->numnormals; i++) {
- z = model->normals[3 * i + 0]; /* re-arrange for pole distortion */
- y = model->normals[3 * i + 1];
- x = model->normals[3 * i + 2];
- r = sqrt((x * x) + (y * y));
- rho = sqrt((r * r) + (z * z));
-
- if(r == 0.0) {
- theta = 0.0;
- phi = 0.0;
- } else {
- if(z == 0.0)
- phi = M_PI / 2.0;
- else
- phi = acos(z / rho);
-
-#if WE_DONT_NEED_THIS_CODE
- if(x == 0.0)
- theta = M_PI / 2.0; /* asin(y / r); */
- else
- theta = acos(x / r);
-#endif
-
- if(y == 0.0)
- theta = M_PI / 2.0; /* acos(x / r); */
- else
- theta = asin(y / r) + (M_PI / 2.0);
- }
-
- model->texcoords[2 * i + 0] = theta / M_PI;
- model->texcoords[2 * i + 1] = phi / M_PI;
- }
-
- /* go through and put texcoord indices in all the triangles */
- group = model->groups;
- while(group) {
- for (i = 0; i < group->numtriangles; i++) {
- T(group->triangles[i]).tindices[0] = T(group->triangles[i]).nindices[0];
- T(group->triangles[i]).tindices[1] = T(group->triangles[i]).nindices[1];
- T(group->triangles[i]).tindices[2] = T(group->triangles[i]).nindices[2];
- }
- group = group->next;
- }
-
-#if 0
- printf("glmSpheremapTexture(): generated %d spheremap texture coordinates\n",
- model->numtexcoords);
-#endif
-}
-
-/* glmDelete: Deletes a GLMmodel structure.
- *
- * model - initialized GLMmodel structure
- */
-void
-glmDelete(GLMmodel* model)
-{
- GLMgroup* group;
- uint i;
-
- assert(model);
-
- if (model->pathname) free(model->pathname);
- if (model->mtllibname) free(model->mtllibname);
- if (model->vertices) free(model->vertices);
- if (model->normals) free(model->normals);
- if (model->texcoords) free(model->texcoords);
- if (model->facetnorms) free(model->facetnorms);
- if (model->triangles) free(model->triangles);
- if (model->materials) {
- for (i = 0; i < model->nummaterials; i++)
- free(model->materials[i].name);
- }
- free(model->materials);
- while(model->groups) {
- group = model->groups;
- model->groups = model->groups->next;
- free(group->name);
- free(group->triangles);
- free(group);
- }
-
- free(model);
-}
-
-static GLMmaterial *
-glmDefaultMaterial(void)
-{
- GLMmaterial *m = (GLMmaterial *) calloc(1, sizeof(GLMmaterial));
-
- m->diffuse[0] = 0.75;
- m->diffuse[1] = 0.75;
- m->diffuse[2] = 0.75;
- m->diffuse[3] = 1.0;
-
- m->specular[0] = 1.0;
- m->specular[1] = 1.0;
- m->specular[2] = 1.0;
- m->specular[3] = 1.0;
-
- m->shininess = 5;
-
- return m;
-}
-
-
-/* glmReadOBJ: Reads a model description from a Wavefront .OBJ file.
- * Returns a pointer to the created object which should be free'd with
- * glmDelete().
- *
- * filename - name of the file containing the Wavefront .OBJ format data.
- */
-GLMmodel*
-glmReadOBJ(char* filename)
-{
- GLMmodel* model;
- FILE* file;
-
- /* open the file */
- file = fopen(filename, "r");
- if (!file) {
- fprintf(stderr, "glmReadOBJ() failed: can't open data file \"%s\".\n",
- filename);
- exit(1);
- }
-
-#if 0
- /* announce the model name */
- printf("Model: %s\n", filename);
-#endif
-
- /* allocate a new model */
- model = (GLMmodel*)malloc(sizeof(GLMmodel));
- model->pathname = stralloc(filename);
- model->mtllibname = NULL;
- model->numvertices = 0;
- model->vertices = NULL;
- model->numnormals = 0;
- model->normals = NULL;
- model->numtexcoords = 0;
- model->texcoords = NULL;
- model->numfacetnorms = 0;
- model->facetnorms = NULL;
- model->numtriangles = 0;
- model->triangles = NULL;
- model->nummaterials = 0;
- model->materials = NULL;
- model->numgroups = 0;
- model->groups = NULL;
- model->position[0] = 0.0;
- model->position[1] = 0.0;
- model->position[2] = 0.0;
- model->scale = 1.0;
-
- /* make a first pass through the file to get a count of the number
- of vertices, normals, texcoords & triangles */
- _glmFirstPass(model, file);
-
- /* allocate memory */
- model->vertices = (float*)malloc(sizeof(float) *
- 3 * (model->numvertices + 1));
- model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) *
- model->numtriangles);
- if (model->numnormals) {
- model->normals = (float*)malloc(sizeof(float) *
- 3 * (model->numnormals + 1));
- }
- if (model->numtexcoords) {
- model->texcoords = (float*)malloc(sizeof(float) *
- 2 * (model->numtexcoords + 1));
- }
-
- /* rewind to beginning of file and read in the data this pass */
- rewind(file);
-
- _glmSecondPass(model, file);
-
- /* close the file */
- fclose(file);
-
- if (!model->materials) {
- model->materials = glmDefaultMaterial();
- model->nummaterials = 1;
- }
-
- return model;
-}
-
-/* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to
- * a file.
- *
- * model - initialized GLMmodel structure
- * filename - name of the file to write the Wavefront .OBJ format data to
- * mode - a bitwise or of values describing what is written to the file
- * GLM_NONE - render with only vertices
- * GLM_FLAT - render with facet normals
- * GLM_SMOOTH - render with vertex normals
- * GLM_TEXTURE - render with texture coords
- * GLM_COLOR - render with colors (color material)
- * GLM_MATERIAL - render with materials
- * GLM_COLOR and GLM_MATERIAL should not both be specified.
- * GLM_FLAT and GLM_SMOOTH should not both be specified.
- */
-void
-glmWriteOBJ(GLMmodel* model, char* filename, uint mode)
-{
- uint i;
- FILE* file;
- GLMgroup* group;
-
- assert(model);
-
- /* do a bit of warning */
- if (mode & GLM_FLAT && !model->facetnorms) {
- printf("glmWriteOBJ() warning: flat normal output requested "
- "with no facet normals defined.\n");
- mode &= ~GLM_FLAT;
- }
- if (mode & GLM_SMOOTH && !model->normals) {
- printf("glmWriteOBJ() warning: smooth normal output requested "
- "with no normals defined.\n");
- mode &= ~GLM_SMOOTH;
- }
- if (mode & GLM_TEXTURE && !model->texcoords) {
- printf("glmWriteOBJ() warning: texture coordinate output requested "
- "with no texture coordinates defined.\n");
- mode &= ~GLM_TEXTURE;
- }
- if (mode & GLM_FLAT && mode & GLM_SMOOTH) {
- printf("glmWriteOBJ() warning: flat normal output requested "
- "and smooth normal output requested (using smooth).\n");
- mode &= ~GLM_FLAT;
- }
-
- /* open the file */
- file = fopen(filename, "w");
- if (!file) {
- fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n",
- filename);
- exit(1);
- }
-
- /* spit out a header */
- fprintf(file, "# \n");
- fprintf(file, "# Wavefront OBJ generated by GLM library\n");
- fprintf(file, "# \n");
- fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n");
- fprintf(file, "# email: ndr@pobox.com\n");
- fprintf(file, "# www: http://www.pobox.com/~ndr\n");
- fprintf(file, "# \n");
-
- if (mode & GLM_MATERIAL && model->mtllibname) {
- fprintf(file, "\nmtllib %s\n\n", model->mtllibname);
- _glmWriteMTL(model, filename, model->mtllibname);
- }
-
- /* spit out the vertices */
- fprintf(file, "\n");
- fprintf(file, "# %d vertices\n", model->numvertices);
- for (i = 1; i <= model->numvertices; i++) {
- fprintf(file, "v %f %f %f\n",
- model->vertices[3 * i + 0],
- model->vertices[3 * i + 1],
- model->vertices[3 * i + 2]);
- }
-
- /* spit out the smooth/flat normals */
- if (mode & GLM_SMOOTH) {
- fprintf(file, "\n");
- fprintf(file, "# %d normals\n", model->numnormals);
- for (i = 1; i <= model->numnormals; i++) {
- fprintf(file, "vn %f %f %f\n",
- model->normals[3 * i + 0],
- model->normals[3 * i + 1],
- model->normals[3 * i + 2]);
- }
- } else if (mode & GLM_FLAT) {
- fprintf(file, "\n");
- fprintf(file, "# %d normals\n", model->numfacetnorms);
- for (i = 1; i <= model->numnormals; i++) {
- fprintf(file, "vn %f %f %f\n",
- model->facetnorms[3 * i + 0],
- model->facetnorms[3 * i + 1],
- model->facetnorms[3 * i + 2]);
- }
- }
-
- /* spit out the texture coordinates */
- if (mode & GLM_TEXTURE) {
- fprintf(file, "\n");
- fprintf(file, "# %d texcoords\n", model->numtexcoords);
- for (i = 1; i <= model->numtexcoords; i++) {
- fprintf(file, "vt %f %f\n",
- model->texcoords[2 * i + 0],
- model->texcoords[2 * i + 1]);
- }
- }
-
- fprintf(file, "\n");
- fprintf(file, "# %d groups\n", model->numgroups);
- fprintf(file, "# %d faces (triangles)\n", model->numtriangles);
- fprintf(file, "\n");
-
- group = model->groups;
- while(group) {
- fprintf(file, "g %s\n", group->name);
- if (mode & GLM_MATERIAL)
- fprintf(file, "usemtl %s\n", model->materials[group->material].name);
- for (i = 0; i < group->numtriangles; i++) {
- if (mode & GLM_SMOOTH && mode & GLM_TEXTURE) {
- fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
- T(group->triangles[i]).vindices[0],
- T(group->triangles[i]).nindices[0],
- T(group->triangles[i]).tindices[0],
- T(group->triangles[i]).vindices[1],
- T(group->triangles[i]).nindices[1],
- T(group->triangles[i]).tindices[1],
- T(group->triangles[i]).vindices[2],
- T(group->triangles[i]).nindices[2],
- T(group->triangles[i]).tindices[2]);
- } else if (mode & GLM_FLAT && mode & GLM_TEXTURE) {
- fprintf(file, "f %d/%d %d/%d %d/%d\n",
- T(group->triangles[i]).vindices[0],
- T(group->triangles[i]).findex,
- T(group->triangles[i]).vindices[1],
- T(group->triangles[i]).findex,
- T(group->triangles[i]).vindices[2],
- T(group->triangles[i]).findex);
- } else if (mode & GLM_TEXTURE) {
- fprintf(file, "f %d/%d %d/%d %d/%d\n",
- T(group->triangles[i]).vindices[0],
- T(group->triangles[i]).tindices[0],
- T(group->triangles[i]).vindices[1],
- T(group->triangles[i]).tindices[1],
- T(group->triangles[i]).vindices[2],
- T(group->triangles[i]).tindices[2]);
- } else if (mode & GLM_SMOOTH) {
- fprintf(file, "f %d//%d %d//%d %d//%d\n",
- T(group->triangles[i]).vindices[0],
- T(group->triangles[i]).nindices[0],
- T(group->triangles[i]).vindices[1],
- T(group->triangles[i]).nindices[1],
- T(group->triangles[i]).vindices[2],
- T(group->triangles[i]).nindices[2]);
- } else if (mode & GLM_FLAT) {
- fprintf(file, "f %d//%d %d//%d %d//%d\n",
- T(group->triangles[i]).vindices[0],
- T(group->triangles[i]).findex,
- T(group->triangles[i]).vindices[1],
- T(group->triangles[i]).findex,
- T(group->triangles[i]).vindices[2],
- T(group->triangles[i]).findex);
- } else {
- fprintf(file, "f %d %d %d\n",
- T(group->triangles[i]).vindices[0],
- T(group->triangles[i]).vindices[1],
- T(group->triangles[i]).vindices[2]);
- }
- }
- fprintf(file, "\n");
- group = group->next;
- }
-
- fclose(file);
-}
-
-/* glmWeld: eliminate (weld) vectors that are within an epsilon of
- * each other.
- *
- * model - initialized GLMmodel structure
- * epsilon - maximum difference between vertices
- * ( 0.00001 is a good start for a unitized model)
- *
- */
-void
-glmWeld(GLMmodel* model, float epsilon)
-{
- float* vectors;
- float* copies;
- uint numvectors;
- uint i;
-
- /* vertices */
- numvectors = model->numvertices;
- vectors = model->vertices;
- copies = _glmWeldVectors(vectors, &numvectors, epsilon);
-
- printf("glmWeld(): %d redundant vertices.\n",
- model->numvertices - numvectors - 1);
-
- for (i = 0; i < model->numtriangles; i++) {
- T(i).vindices[0] = (uint)vectors[3 * T(i).vindices[0] + 0];
- T(i).vindices[1] = (uint)vectors[3 * T(i).vindices[1] + 0];
- T(i).vindices[2] = (uint)vectors[3 * T(i).vindices[2] + 0];
- }
-
- /* free space for old vertices */
- free(vectors);
-
- /* allocate space for the new vertices */
- model->numvertices = numvectors;
- model->vertices = (float*)malloc(sizeof(float) *
- 3 * (model->numvertices + 1));
-
- /* copy the optimized vertices into the actual vertex list */
- for (i = 1; i <= model->numvertices; i++) {
- model->vertices[3 * i + 0] = copies[3 * i + 0];
- model->vertices[3 * i + 1] = copies[3 * i + 1];
- model->vertices[3 * i + 2] = copies[3 * i + 2];
- }
-
- free(copies);
-}
-
-
-void
-glmReIndex(GLMmodel *model)
-{
- uint i, j, n;
- GLMgroup* group;
- float *newNormals = NULL;
- float *newTexcoords = NULL;
- const uint numv = model->numvertices;
-
- if (model->numnormals > 0)
- newNormals = (float *) malloc((numv + 1) * 3 * sizeof(float));
-
- if (model->numtexcoords > 0)
- newTexcoords = (float *) malloc((numv + 1) * 2 * sizeof(float));
-
- for (group = model->groups; group; group = group->next) {
-
- n = group->numtriangles;
-
- group->triIndexes = (uint *) malloc(n * 3 * sizeof(uint));
-
- group->minIndex = 10000000;
- group->maxIndex = 0;
-
- for (i = 0; i < n; i++) {
-
- for (j = 0; j < 3; j++) {
- uint vindex = T(group->triangles[i]).vindices[j];
- uint nindex = T(group->triangles[i]).nindices[j];
- uint tindex = T(group->triangles[i]).tindices[j];
-
- float *nrm = &model->normals[nindex * 3];
- float *tex = &model->texcoords[tindex * 2];
-
- if (newNormals) {
- assert(vindex * 3 + 2 < (numv + 1) * 3);
- newNormals[vindex * 3 + 0] = nrm[0];
- newNormals[vindex * 3 + 1] = nrm[1];
- newNormals[vindex * 3 + 2] = nrm[2];
- }
- if (newTexcoords) {
- newTexcoords[vindex * 2 + 0] = tex[0];
- newTexcoords[vindex * 2 + 1] = tex[1];
- }
-
- T(group->triangles[i]).nindices[j] = vindex;
- T(group->triangles[i]).tindices[j] = vindex;
-
- group->triIndexes[i * 3 + j] = vindex;
-
- if (vindex > group->maxIndex)
- group->maxIndex = vindex;
- if (vindex < group->minIndex)
- group->minIndex = vindex;
- }
- }
- }
-
- if (newNormals) {
- free(model->normals);
- model->normals = newNormals;
- model->numnormals = model->numvertices;
- }
-
- if (newTexcoords) {
- free(model->texcoords);
- model->texcoords = newTexcoords;
- model->numtexcoords = model->numvertices;
- }
-}
-
-
-
-void
-glmPrint(const GLMmodel *model)
-{
- uint i, j, grp, n;
- GLMgroup* group;
- uint totalTris = 0;
-
- grp = 0;
-
- printf("%u vertices\n", model->numvertices);
- printf("%u normals\n", model->numnormals);
- printf("%u texcoords\n", model->numtexcoords);
-
- for (group = model->groups; group; group = group->next, grp++) {
- printf("Group %u:\n", grp);
- printf(" Min index %u, max index %u\n", group->minIndex, group->maxIndex);
-
-#if 0
- if (mode & GLM_MATERIAL) {
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,
- model->materials[group->material].ambient);
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
- model->materials[group->material].diffuse);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,
- model->materials[group->material].specular);
- glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS,
- model->materials[group->material].shininess);
- }
-
- if (mode & GLM_COLOR) {
- glColor3fv(model->materials[group->material].diffuse);
- }
-#endif
- totalTris += group->numtriangles;
-
- printf(" %u triangles\n", group->numtriangles);
- n = group->numtriangles;
- if (n > 10)
- n = 10;
-
- for (i = 0; i < n; i++) {
-
- printf(" %u: vert ", i);
- for (j = 0; j < 3; j++) {
- printf("%u ", T(group->triangles[i]).vindices[j]);
- }
-
- printf(" normal ");
- for (j = 0; j < 3; j++) {
- printf("%u ", T(group->triangles[i]).nindices[j]);
- }
-
- printf(" tex ");
- for (j = 0; j < 3; j++) {
- printf("%u ", T(group->triangles[i]).tindices[j]);
- }
-
- printf("\n");
- }
- }
- printf("Total tris: %u\n", totalTris);
-}
-
-
-
-#if 0
- /* normals */
- if (model->numnormals) {
- numvectors = model->numnormals;
- vectors = model->normals;
- copies = _glmOptimizeVectors(vectors, &numvectors);
-
- printf("glmOptimize(): %d redundant normals.\n",
- model->numnormals - numvectors);
-
- for (i = 0; i < model->numtriangles; i++) {
- T(i).nindices[0] = (uint)vectors[3 * T(i).nindices[0] + 0];
- T(i).nindices[1] = (uint)vectors[3 * T(i).nindices[1] + 0];
- T(i).nindices[2] = (uint)vectors[3 * T(i).nindices[2] + 0];
- }
-
- /* free space for old normals */
- free(vectors);
-
- /* allocate space for the new normals */
- model->numnormals = numvectors;
- model->normals = (float*)malloc(sizeof(float) *
- 3 * (model->numnormals + 1));
-
- /* copy the optimized vertices into the actual vertex list */
- for (i = 1; i <= model->numnormals; i++) {
- model->normals[3 * i + 0] = copies[3 * i + 0];
- model->normals[3 * i + 1] = copies[3 * i + 1];
- model->normals[3 * i + 2] = copies[3 * i + 2];
- }
-
- free(copies);
- }
-
- /* texcoords */
- if (model->numtexcoords) {
- numvectors = model->numtexcoords;
- vectors = model->texcoords;
- copies = _glmOptimizeVectors(vectors, &numvectors);
-
- printf("glmOptimize(): %d redundant texcoords.\n",
- model->numtexcoords - numvectors);
-
- for (i = 0; i < model->numtriangles; i++) {
- for (j = 0; j < 3; j++) {
- T(i).tindices[j] = (uint)vectors[3 * T(i).tindices[j] + 0];
- }
- }
-
- /* free space for old texcoords */
- free(vectors);
-
- /* allocate space for the new texcoords */
- model->numtexcoords = numvectors;
- model->texcoords = (float*)malloc(sizeof(float) *
- 2 * (model->numtexcoords + 1));
-
- /* copy the optimized vertices into the actual vertex list */
- for (i = 1; i <= model->numtexcoords; i++) {
- model->texcoords[2 * i + 0] = copies[2 * i + 0];
- model->texcoords[2 * i + 1] = copies[2 * i + 1];
- }
-
- free(copies);
- }
-#endif
-
-#if 0
- /* look for unused vertices */
- /* look for unused normals */
- /* look for unused texcoords */
- for (i = 1; i <= model->numvertices; i++) {
- for (j = 0; j < model->numtriangles; i++) {
- if (T(j).vindices[0] == i ||
- T(j).vindices[1] == i ||
- T(j).vindices[1] == i)
- break;
- }
- }
-#endif