132001f49Smrg/* 232001f49Smrg * GLM library. Wavefront .obj file format reader/writer/manipulator. 332001f49Smrg * 432001f49Smrg * Written by Nate Robins, 1997. 532001f49Smrg * email: ndr@pobox.com 632001f49Smrg * www: http://www.pobox.com/~ndr 732001f49Smrg */ 832001f49Smrg 932001f49Smrg/* includes */ 1032001f49Smrg#include <math.h> 1132001f49Smrg#include <stdio.h> 1232001f49Smrg#include <string.h> 1332001f49Smrg#include <stdlib.h> 1432001f49Smrg#include <assert.h> 1532001f49Smrg#include "glm.h" 1632001f49Smrg#include "readtex.h" 1732001f49Smrg 1832001f49Smrg 1932001f49Smrgtypedef unsigned char boolean; 2032001f49Smrg#define TRUE 1 2132001f49Smrg#define FALSE 0 2232001f49Smrg 2332001f49Smrg 2432001f49Smrg/* Some <math.h> files do not define M_PI... */ 2532001f49Smrg#ifndef M_PI 2632001f49Smrg#define M_PI 3.14159265358979323846 2732001f49Smrg#endif 2832001f49Smrg 2932001f49Smrg/* defines */ 3032001f49Smrg#define T(x) model->triangles[(x)] 3132001f49Smrg 3232001f49Smrg 3332001f49Smrg/* enums */ 3432001f49Smrgenum { X, Y, Z, W }; /* elements of a vertex */ 3532001f49Smrg 3632001f49Smrg 3732001f49Smrg/* typedefs */ 3832001f49Smrg 3932001f49Smrg/* _GLMnode: general purpose node 4032001f49Smrg */ 4132001f49Smrgtypedef struct _GLMnode { 4232001f49Smrg uint index; 4332001f49Smrg boolean averaged; 4432001f49Smrg struct _GLMnode* next; 4532001f49Smrg} GLMnode; 4632001f49Smrg 4732001f49Smrg/* strdup is actually not a standard ANSI C or POSIX routine 4832001f49Smrg so implement a private one. OpenVMS does not have a strdup; Linux's 4932001f49Smrg standard libc doesn't declare strdup by default (unless BSD or SVID 5032001f49Smrg interfaces are requested). */ 5132001f49Smrgstatic char * 5232001f49Smrgstralloc(const char *string) 5332001f49Smrg{ 5432001f49Smrg char *copy; 5532001f49Smrg 5632001f49Smrg copy = malloc(strlen(string) + 1); 5732001f49Smrg if (copy == NULL) 5832001f49Smrg return NULL; 5932001f49Smrg strcpy(copy, string); 6032001f49Smrg return copy; 6132001f49Smrg} 6232001f49Smrg 6332001f49Smrg/* private functions */ 6432001f49Smrg 6532001f49Smrg/* _glmMax: returns the maximum of two floats */ 6632001f49Smrgstatic float 6732001f49Smrg_glmMax(float a, float b) 6832001f49Smrg{ 6932001f49Smrg if (a > b) 7032001f49Smrg return a; 7132001f49Smrg return b; 7232001f49Smrg} 7332001f49Smrg 7432001f49Smrg/* _glmAbs: returns the absolute value of a float */ 7532001f49Smrgstatic float 7632001f49Smrg_glmAbs(float f) 7732001f49Smrg{ 7832001f49Smrg if (f < 0) 7932001f49Smrg return -f; 8032001f49Smrg return f; 8132001f49Smrg} 8232001f49Smrg 8332001f49Smrg/* _glmDot: compute the dot product of two vectors 8432001f49Smrg * 8532001f49Smrg * u - array of 3 floats (float u[3]) 8632001f49Smrg * v - array of 3 floats (float v[3]) 8732001f49Smrg */ 8832001f49Smrgstatic float 8932001f49Smrg_glmDot(float* u, float* v) 9032001f49Smrg{ 9132001f49Smrg assert(u); 9232001f49Smrg assert(v); 9332001f49Smrg 9432001f49Smrg /* compute the dot product */ 9532001f49Smrg return u[X] * v[X] + u[Y] * v[Y] + u[Z] * v[Z]; 9632001f49Smrg} 9732001f49Smrg 9832001f49Smrg/* _glmCross: compute the cross product of two vectors 9932001f49Smrg * 10032001f49Smrg * u - array of 3 floats (float u[3]) 10132001f49Smrg * v - array of 3 floats (float v[3]) 10232001f49Smrg * n - array of 3 floats (float n[3]) to return the cross product in 10332001f49Smrg */ 10432001f49Smrgstatic void 10532001f49Smrg_glmCross(float* u, float* v, float* n) 10632001f49Smrg{ 10732001f49Smrg assert(u); 10832001f49Smrg assert(v); 10932001f49Smrg assert(n); 11032001f49Smrg 11132001f49Smrg /* compute the cross product (u x v for right-handed [ccw]) */ 11232001f49Smrg n[X] = u[Y] * v[Z] - u[Z] * v[Y]; 11332001f49Smrg n[Y] = u[Z] * v[X] - u[X] * v[Z]; 11432001f49Smrg n[Z] = u[X] * v[Y] - u[Y] * v[X]; 11532001f49Smrg} 11632001f49Smrg 11732001f49Smrg/* _glmNormalize: normalize a vector 11832001f49Smrg * 11932001f49Smrg * n - array of 3 floats (float n[3]) to be normalized 12032001f49Smrg */ 12132001f49Smrgstatic void 12232001f49Smrg_glmNormalize(float* n) 12332001f49Smrg{ 12432001f49Smrg float l; 12532001f49Smrg 12632001f49Smrg assert(n); 12732001f49Smrg 12832001f49Smrg /* normalize */ 12932001f49Smrg l = (float)sqrt(n[X] * n[X] + n[Y] * n[Y] + n[Z] * n[Z]); 13032001f49Smrg n[0] /= l; 13132001f49Smrg n[1] /= l; 13232001f49Smrg n[2] /= l; 13332001f49Smrg} 13432001f49Smrg 13532001f49Smrg/* _glmEqual: compares two vectors and returns TRUE if they are 13632001f49Smrg * equal (within a certain threshold) or FALSE if not. An epsilon 13732001f49Smrg * that works fairly well is 0.000001. 13832001f49Smrg * 13932001f49Smrg * u - array of 3 floats (float u[3]) 14032001f49Smrg * v - array of 3 floats (float v[3]) 14132001f49Smrg */ 14232001f49Smrgstatic boolean 14332001f49Smrg_glmEqual(float* u, float* v, float epsilon) 14432001f49Smrg{ 14532001f49Smrg if (_glmAbs(u[0] - v[0]) < epsilon && 14632001f49Smrg _glmAbs(u[1] - v[1]) < epsilon && 14732001f49Smrg _glmAbs(u[2] - v[2]) < epsilon) 14832001f49Smrg { 14932001f49Smrg return TRUE; 15032001f49Smrg } 15132001f49Smrg return FALSE; 15232001f49Smrg} 15332001f49Smrg 15432001f49Smrg/* _glmWeldVectors: eliminate (weld) vectors that are within an 15532001f49Smrg * epsilon of each other. 15632001f49Smrg * 15732001f49Smrg * vectors - array of float[3]'s to be welded 15832001f49Smrg * numvectors - number of float[3]'s in vectors 15932001f49Smrg * epsilon - maximum difference between vectors 16032001f49Smrg * 16132001f49Smrg */ 16232001f49Smrgstatic float* 16332001f49Smrg_glmWeldVectors(float* vectors, uint* numvectors, float epsilon) 16432001f49Smrg{ 16532001f49Smrg float* copies; 16632001f49Smrg uint copied; 16732001f49Smrg uint i, j; 16832001f49Smrg 16932001f49Smrg copies = (float*)malloc(sizeof(float) * 3 * (*numvectors + 1)); 17032001f49Smrg memcpy(copies, vectors, (sizeof(float) * 3 * (*numvectors + 1))); 17132001f49Smrg 17232001f49Smrg copied = 1; 17332001f49Smrg for (i = 1; i <= *numvectors; i++) { 17432001f49Smrg for (j = 1; j <= copied; j++) { 17532001f49Smrg if (_glmEqual(&vectors[3 * i], &copies[3 * j], epsilon)) { 17632001f49Smrg goto duplicate; 17732001f49Smrg } 17832001f49Smrg } 17932001f49Smrg 18032001f49Smrg /* must not be any duplicates -- add to the copies array */ 18132001f49Smrg copies[3 * copied + 0] = vectors[3 * i + 0]; 18232001f49Smrg copies[3 * copied + 1] = vectors[3 * i + 1]; 18332001f49Smrg copies[3 * copied + 2] = vectors[3 * i + 2]; 18432001f49Smrg j = copied; /* pass this along for below */ 18532001f49Smrg copied++; 18632001f49Smrg 18732001f49Smrg duplicate: 18832001f49Smrg /* set the first component of this vector to point at the correct 18932001f49Smrg index into the new copies array */ 19032001f49Smrg vectors[3 * i + 0] = (float)j; 19132001f49Smrg } 19232001f49Smrg 19332001f49Smrg *numvectors = copied-1; 19432001f49Smrg return copies; 19532001f49Smrg} 19632001f49Smrg 19732001f49Smrg/* _glmFindGroup: Find a group in the model 19832001f49Smrg */ 19932001f49Smrgstatic GLMgroup* 20032001f49Smrg_glmFindGroup(GLMmodel* model, char* name) 20132001f49Smrg{ 20232001f49Smrg GLMgroup* group; 20332001f49Smrg 20432001f49Smrg assert(model); 20532001f49Smrg 20632001f49Smrg group = model->groups; 20732001f49Smrg while(group) { 20832001f49Smrg if (!strcmp(name, group->name)) 20932001f49Smrg break; 21032001f49Smrg group = group->next; 21132001f49Smrg } 21232001f49Smrg 21332001f49Smrg return group; 21432001f49Smrg} 21532001f49Smrg 21632001f49Smrg/* _glmAddGroup: Add a group to the model 21732001f49Smrg */ 21832001f49Smrgstatic GLMgroup* 21932001f49Smrg_glmAddGroup(GLMmodel* model, char* name) 22032001f49Smrg{ 22132001f49Smrg GLMgroup* group; 22232001f49Smrg 22332001f49Smrg group = _glmFindGroup(model, name); 22432001f49Smrg if (!group) { 22532001f49Smrg group = (GLMgroup*)malloc(sizeof(GLMgroup)); 22632001f49Smrg group->name = stralloc(name); 22732001f49Smrg group->material = 0; 22832001f49Smrg group->numtriangles = 0; 22932001f49Smrg group->triangles = NULL; 23032001f49Smrg group->next = model->groups; 23132001f49Smrg model->groups = group; 23232001f49Smrg model->numgroups++; 23332001f49Smrg } 23432001f49Smrg 23532001f49Smrg return group; 23632001f49Smrg} 23732001f49Smrg 23832001f49Smrg/* _glmFindGroup: Find a material in the model 23932001f49Smrg */ 24032001f49Smrgstatic uint 24132001f49Smrg_glmFindMaterial(GLMmodel* model, char* name) 24232001f49Smrg{ 24332001f49Smrg uint i; 24432001f49Smrg 24532001f49Smrg for (i = 0; i < model->nummaterials; i++) { 24632001f49Smrg if (!strcmp(model->materials[i].name, name)) 24732001f49Smrg goto found; 24832001f49Smrg } 24932001f49Smrg 25032001f49Smrg /* didn't find the name, so set it as the default material */ 25132001f49Smrg printf("_glmFindMaterial(): can't find material \"%s\".\n", name); 25232001f49Smrg i = 0; 25332001f49Smrg 25432001f49Smrgfound: 25532001f49Smrg return i; 25632001f49Smrg} 25732001f49Smrg 25832001f49Smrg 25932001f49Smrg/* _glmDirName: return the directory given a path 26032001f49Smrg * 26132001f49Smrg * path - filesystem path 26232001f49Smrg * 26332001f49Smrg * The return value should be free'd. 26432001f49Smrg */ 26532001f49Smrgstatic char* 26632001f49Smrg_glmDirName(char* path) 26732001f49Smrg{ 26832001f49Smrg char* dir; 26932001f49Smrg char* s; 27032001f49Smrg 27132001f49Smrg dir = stralloc(path); 27232001f49Smrg 27332001f49Smrg s = strrchr(dir, '/'); 27432001f49Smrg if (s) 27532001f49Smrg s[1] = '\0'; 27632001f49Smrg else 27732001f49Smrg dir[0] = '\0'; 27832001f49Smrg 27932001f49Smrg return dir; 28032001f49Smrg} 28132001f49Smrg 28232001f49Smrg 28332001f49Smrg/* _glmReadMTL: read a wavefront material library file 28432001f49Smrg * 28532001f49Smrg * model - properly initialized GLMmodel structure 28632001f49Smrg * name - name of the material library 28732001f49Smrg */ 28832001f49Smrgstatic void 28932001f49Smrg_glmReadMTL(GLMmodel* model, char* name) 29032001f49Smrg{ 29132001f49Smrg FILE* file; 29232001f49Smrg char* dir; 29332001f49Smrg char* filename; 29432001f49Smrg char buf[128], buf2[128]; 29532001f49Smrg uint nummaterials, i; 29632001f49Smrg GLMmaterial *mat; 29732001f49Smrg 29832001f49Smrg dir = _glmDirName(model->pathname); 29932001f49Smrg filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(name) + 1)); 30032001f49Smrg strcpy(filename, dir); 30132001f49Smrg strcat(filename, name); 30232001f49Smrg free(dir); 30332001f49Smrg 30432001f49Smrg /* open the file */ 30532001f49Smrg file = fopen(filename, "r"); 30632001f49Smrg if (!file) { 30732001f49Smrg fprintf(stderr, "_glmReadMTL() failed: can't open material file \"%s\".\n", 30832001f49Smrg filename); 30932001f49Smrg exit(1); 31032001f49Smrg } 31132001f49Smrg free(filename); 31232001f49Smrg 31332001f49Smrg /* count the number of materials in the file */ 31432001f49Smrg nummaterials = 1; 31532001f49Smrg while(fscanf(file, "%s", buf) != EOF) { 31632001f49Smrg switch(buf[0]) { 31732001f49Smrg case '#': /* comment */ 31832001f49Smrg /* eat up rest of line */ 31932001f49Smrg fgets(buf, sizeof(buf), file); 32032001f49Smrg break; 32132001f49Smrg case 'n': /* newmtl */ 32232001f49Smrg fgets(buf, sizeof(buf), file); 32332001f49Smrg nummaterials++; 32432001f49Smrg sscanf(buf, "%s %s", buf, buf); 32532001f49Smrg break; 32632001f49Smrg default: 32732001f49Smrg /* eat up rest of line */ 32832001f49Smrg fgets(buf, sizeof(buf), file); 32932001f49Smrg break; 33032001f49Smrg } 33132001f49Smrg } 33232001f49Smrg 33332001f49Smrg rewind(file); 33432001f49Smrg 33532001f49Smrg /* allocate memory for the materials */ 33632001f49Smrg model->materials = (GLMmaterial*)calloc(nummaterials, sizeof(GLMmaterial)); 33732001f49Smrg model->nummaterials = nummaterials; 33832001f49Smrg 33932001f49Smrg /* set the default material */ 34032001f49Smrg for (i = 0; i < nummaterials; i++) { 34132001f49Smrg model->materials[i].name = NULL; 34232001f49Smrg model->materials[i].shininess = 0; 34332001f49Smrg model->materials[i].diffuse[0] = 0.8; 34432001f49Smrg model->materials[i].diffuse[1] = 0.8; 34532001f49Smrg model->materials[i].diffuse[2] = 0.8; 34632001f49Smrg model->materials[i].diffuse[3] = 1.0; 34732001f49Smrg model->materials[i].ambient[0] = 0.2; 34832001f49Smrg model->materials[i].ambient[1] = 0.2; 34932001f49Smrg model->materials[i].ambient[2] = 0.2; 35032001f49Smrg model->materials[i].ambient[3] = 0.0; 35132001f49Smrg model->materials[i].specular[0] = 0.0; 35232001f49Smrg model->materials[i].specular[1] = 0.0; 35332001f49Smrg model->materials[i].specular[2] = 0.0; 35432001f49Smrg model->materials[i].specular[3] = 0.0; 35532001f49Smrg } 35632001f49Smrg model->materials[0].name = stralloc("default"); 35732001f49Smrg 35832001f49Smrg /* now, read in the data */ 35932001f49Smrg nummaterials = 0; 36032001f49Smrg 36132001f49Smrg mat = &model->materials[nummaterials]; 36232001f49Smrg 36332001f49Smrg while(fscanf(file, "%s", buf) != EOF) { 36432001f49Smrg switch(buf[0]) { 36532001f49Smrg case '#': /* comment */ 36632001f49Smrg /* eat up rest of line */ 36732001f49Smrg fgets(buf, sizeof(buf), file); 36832001f49Smrg break; 36932001f49Smrg case 'n': /* newmtl */ 37032001f49Smrg fgets(buf, sizeof(buf), file); 37132001f49Smrg sscanf(buf, "%s %s", buf, buf); 37232001f49Smrg nummaterials++; 37332001f49Smrg model->materials[nummaterials].name = stralloc(buf); 37432001f49Smrg break; 37532001f49Smrg case 'N': 37632001f49Smrg fscanf(file, "%f", &model->materials[nummaterials].shininess); 37732001f49Smrg /* wavefront shininess is from [0, 1000], so scale for OpenGL */ 37832001f49Smrg model->materials[nummaterials].shininess /= 1000.0; 37932001f49Smrg model->materials[nummaterials].shininess *= 128.0; 38032001f49Smrg mat = &model->materials[nummaterials]; 38132001f49Smrg break; 38232001f49Smrg case 'K': 38332001f49Smrg switch(buf[1]) { 38432001f49Smrg case 'd': 38532001f49Smrg fscanf(file, "%f %f %f", 38632001f49Smrg &model->materials[nummaterials].diffuse[0], 38732001f49Smrg &model->materials[nummaterials].diffuse[1], 38832001f49Smrg &model->materials[nummaterials].diffuse[2]); 38932001f49Smrg break; 39032001f49Smrg case 's': 39132001f49Smrg fscanf(file, "%f %f %f", 39232001f49Smrg &model->materials[nummaterials].specular[0], 39332001f49Smrg &model->materials[nummaterials].specular[1], 39432001f49Smrg &model->materials[nummaterials].specular[2]); 39532001f49Smrg break; 39632001f49Smrg case 'a': 39732001f49Smrg fscanf(file, "%f %f %f", 39832001f49Smrg &model->materials[nummaterials].ambient[0], 39932001f49Smrg &model->materials[nummaterials].ambient[1], 40032001f49Smrg &model->materials[nummaterials].ambient[2]); 40132001f49Smrg break; 40232001f49Smrg default: 40332001f49Smrg /* eat up rest of line */ 40432001f49Smrg fgets(buf, sizeof(buf), file); 40532001f49Smrg break; 40632001f49Smrg } 40732001f49Smrg break; 40832001f49Smrg case 'd': /* alpha? */ 40932001f49Smrg fscanf(file, "%f", 41032001f49Smrg &model->materials[nummaterials].diffuse[3]); 41132001f49Smrg break; 41232001f49Smrg case 'm': /* texture map */ 41332001f49Smrg fscanf(file, "%s", buf2); 41432001f49Smrg /*printf("map %s\n", buf2);*/ 41532001f49Smrg mat->map_kd = strdup(buf2); 41632001f49Smrg break; 41732001f49Smrg 41832001f49Smrg default: 41932001f49Smrg /* eat up rest of line */ 42032001f49Smrg fgets(buf, sizeof(buf), file); 42132001f49Smrg break; 42232001f49Smrg } 42332001f49Smrg } 42432001f49Smrg fclose(file); 42532001f49Smrg} 42632001f49Smrg 42732001f49Smrg 42832001f49Smrg/* _glmWriteMTL: write a wavefront material library file 42932001f49Smrg * 43032001f49Smrg * model - properly initialized GLMmodel structure 43132001f49Smrg * modelpath - pathname of the model being written 43232001f49Smrg * mtllibname - name of the material library to be written 43332001f49Smrg */ 43432001f49Smrgstatic void 43532001f49Smrg_glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname) 43632001f49Smrg{ 43732001f49Smrg FILE* file; 43832001f49Smrg char* dir; 43932001f49Smrg char* filename; 44032001f49Smrg GLMmaterial* material; 44132001f49Smrg uint i; 44232001f49Smrg 44332001f49Smrg dir = _glmDirName(modelpath); 44432001f49Smrg filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(mtllibname))); 44532001f49Smrg strcpy(filename, dir); 44632001f49Smrg strcat(filename, mtllibname); 44732001f49Smrg free(dir); 44832001f49Smrg 44932001f49Smrg /* open the file */ 45032001f49Smrg file = fopen(filename, "w"); 45132001f49Smrg if (!file) { 45232001f49Smrg fprintf(stderr, "_glmWriteMTL() failed: can't open file \"%s\".\n", 45332001f49Smrg filename); 45432001f49Smrg exit(1); 45532001f49Smrg } 45632001f49Smrg free(filename); 45732001f49Smrg 45832001f49Smrg /* spit out a header */ 45932001f49Smrg fprintf(file, "# \n"); 46032001f49Smrg fprintf(file, "# Wavefront MTL generated by GLM library\n"); 46132001f49Smrg fprintf(file, "# \n"); 46232001f49Smrg fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n"); 46332001f49Smrg fprintf(file, "# email: ndr@pobox.com\n"); 46432001f49Smrg fprintf(file, "# www: http://www.pobox.com/~ndr\n"); 46532001f49Smrg fprintf(file, "# \n\n"); 46632001f49Smrg 46732001f49Smrg for (i = 0; i < model->nummaterials; i++) { 46832001f49Smrg material = &model->materials[i]; 46932001f49Smrg fprintf(file, "newmtl %s\n", material->name); 47032001f49Smrg fprintf(file, "Ka %f %f %f\n", 47132001f49Smrg material->ambient[0], material->ambient[1], material->ambient[2]); 47232001f49Smrg fprintf(file, "Kd %f %f %f\n", 47332001f49Smrg material->diffuse[0], material->diffuse[1], material->diffuse[2]); 47432001f49Smrg fprintf(file, "Ks %f %f %f\n", 47532001f49Smrg material->specular[0],material->specular[1],material->specular[2]); 47632001f49Smrg fprintf(file, "Ns %f\n", material->shininess); 47732001f49Smrg fprintf(file, "\n"); 47832001f49Smrg } 47932001f49Smrg fclose(file); 48032001f49Smrg} 48132001f49Smrg 48232001f49Smrg 48332001f49Smrg/* _glmFirstPass: first pass at a Wavefront OBJ file that gets all the 48432001f49Smrg * statistics of the model (such as #vertices, #normals, etc) 48532001f49Smrg * 48632001f49Smrg * model - properly initialized GLMmodel structure 48732001f49Smrg * file - (fopen'd) file descriptor 48832001f49Smrg */ 48932001f49Smrgstatic void 49032001f49Smrg_glmFirstPass(GLMmodel* model, FILE* file) 49132001f49Smrg{ 49232001f49Smrg uint numvertices; /* number of vertices in model */ 49332001f49Smrg uint numnormals; /* number of normals in model */ 49432001f49Smrg uint numtexcoords; /* number of texcoords in model */ 49532001f49Smrg uint numtriangles; /* number of triangles in model */ 49632001f49Smrg GLMgroup* group; /* current group */ 49732001f49Smrg unsigned v, n, t; 49832001f49Smrg char buf[128]; 49932001f49Smrg 50032001f49Smrg /* make a default group */ 50132001f49Smrg group = _glmAddGroup(model, "default"); 50232001f49Smrg 50332001f49Smrg numvertices = numnormals = numtexcoords = numtriangles = 0; 50432001f49Smrg while(fscanf(file, "%s", buf) != EOF) { 50532001f49Smrg switch(buf[0]) { 50632001f49Smrg case '#': /* comment */ 50732001f49Smrg /* eat up rest of line */ 50832001f49Smrg fgets(buf, sizeof(buf), file); 50932001f49Smrg break; 51032001f49Smrg case 'v': /* v, vn, vt */ 51132001f49Smrg switch(buf[1]) { 51232001f49Smrg case '\0': /* vertex */ 51332001f49Smrg /* eat up rest of line */ 51432001f49Smrg fgets(buf, sizeof(buf), file); 51532001f49Smrg numvertices++; 51632001f49Smrg break; 51732001f49Smrg case 'n': /* normal */ 51832001f49Smrg /* eat up rest of line */ 51932001f49Smrg fgets(buf, sizeof(buf), file); 52032001f49Smrg numnormals++; 52132001f49Smrg break; 52232001f49Smrg case 't': /* texcoord */ 52332001f49Smrg /* eat up rest of line */ 52432001f49Smrg fgets(buf, sizeof(buf), file); 52532001f49Smrg numtexcoords++; 52632001f49Smrg break; 52732001f49Smrg default: 52832001f49Smrg printf("_glmFirstPass(): Unknown token \"%s\".\n", buf); 52932001f49Smrg exit(1); 53032001f49Smrg break; 53132001f49Smrg } 53232001f49Smrg break; 53332001f49Smrg case 'm': 53432001f49Smrg fgets(buf, sizeof(buf), file); 53532001f49Smrg sscanf(buf, "%s %s", buf, buf); 53632001f49Smrg model->mtllibname = stralloc(buf); 53732001f49Smrg _glmReadMTL(model, buf); 53832001f49Smrg break; 53932001f49Smrg case 'u': 54032001f49Smrg /* eat up rest of line */ 54132001f49Smrg fgets(buf, sizeof(buf), file); 54232001f49Smrg break; 54332001f49Smrg case 'g': /* group */ 54432001f49Smrg /* eat up rest of line */ 54532001f49Smrg fgets(buf, sizeof(buf), file); 54632001f49Smrg sscanf(buf, "%s", buf); 54732001f49Smrg group = _glmAddGroup(model, buf); 54832001f49Smrg break; 54932001f49Smrg case 'f': /* face */ 55032001f49Smrg v = n = t = 0; 55132001f49Smrg fscanf(file, "%s", buf); 55232001f49Smrg /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 55332001f49Smrg if (strstr(buf, "//")) { 55432001f49Smrg /* v//n */ 55532001f49Smrg sscanf(buf, "%u//%u", &v, &n); 55632001f49Smrg fscanf(file, "%u//%u", &v, &n); 55732001f49Smrg fscanf(file, "%u//%u", &v, &n); 55832001f49Smrg numtriangles++; 55932001f49Smrg group->numtriangles++; 56032001f49Smrg while(fscanf(file, "%u//%u", &v, &n) > 0) { 56132001f49Smrg numtriangles++; 56232001f49Smrg group->numtriangles++; 56332001f49Smrg } 56432001f49Smrg } else if (sscanf(buf, "%u/%u/%u", &v, &t, &n) == 3) { 56532001f49Smrg /* v/t/n */ 56632001f49Smrg fscanf(file, "%u/%u/%u", &v, &t, &n); 56732001f49Smrg fscanf(file, "%u/%u/%u", &v, &t, &n); 56832001f49Smrg numtriangles++; 56932001f49Smrg group->numtriangles++; 57032001f49Smrg while(fscanf(file, "%u/%u/%u", &v, &t, &n) > 0) { 57132001f49Smrg numtriangles++; 57232001f49Smrg group->numtriangles++; 57332001f49Smrg } 57432001f49Smrg } else if (sscanf(buf, "%u/%u", &v, &t) == 2) { 57532001f49Smrg /* v/t */ 57632001f49Smrg fscanf(file, "%u/%u", &v, &t); 57732001f49Smrg fscanf(file, "%u/%u", &v, &t); 57832001f49Smrg numtriangles++; 57932001f49Smrg group->numtriangles++; 58032001f49Smrg while(fscanf(file, "%u/%u", &v, &t) > 0) { 58132001f49Smrg numtriangles++; 58232001f49Smrg group->numtriangles++; 58332001f49Smrg } 58432001f49Smrg } else { 58532001f49Smrg /* v */ 58632001f49Smrg fscanf(file, "%u", &v); 58732001f49Smrg fscanf(file, "%u", &v); 58832001f49Smrg numtriangles++; 58932001f49Smrg group->numtriangles++; 59032001f49Smrg while(fscanf(file, "%u", &v) > 0) { 59132001f49Smrg numtriangles++; 59232001f49Smrg group->numtriangles++; 59332001f49Smrg } 59432001f49Smrg } 59532001f49Smrg break; 59632001f49Smrg 59732001f49Smrg default: 59832001f49Smrg /* eat up rest of line */ 59932001f49Smrg fgets(buf, sizeof(buf), file); 60032001f49Smrg break; 60132001f49Smrg } 60232001f49Smrg } 60332001f49Smrg 60432001f49Smrg#if 0 60532001f49Smrg /* announce the model statistics */ 60632001f49Smrg printf(" Vertices: %d\n", numvertices); 60732001f49Smrg printf(" Normals: %d\n", numnormals); 60832001f49Smrg printf(" Texcoords: %d\n", numtexcoords); 60932001f49Smrg printf(" Triangles: %d\n", numtriangles); 61032001f49Smrg printf(" Groups: %d\n", model->numgroups); 61132001f49Smrg#endif 61232001f49Smrg 61332001f49Smrg /* set the stats in the model structure */ 61432001f49Smrg model->numvertices = numvertices; 61532001f49Smrg model->numnormals = numnormals; 61632001f49Smrg model->numtexcoords = numtexcoords; 61732001f49Smrg model->numtriangles = numtriangles; 61832001f49Smrg 61932001f49Smrg /* allocate memory for the triangles in each group */ 62032001f49Smrg group = model->groups; 62132001f49Smrg while(group) { 62232001f49Smrg group->triangles = (uint*)malloc(sizeof(uint) * group->numtriangles); 62332001f49Smrg group->numtriangles = 0; 62432001f49Smrg group = group->next; 62532001f49Smrg } 62632001f49Smrg} 62732001f49Smrg 62832001f49Smrg/* _glmSecondPass: second pass at a Wavefront OBJ file that gets all 62932001f49Smrg * the data. 63032001f49Smrg * 63132001f49Smrg * model - properly initialized GLMmodel structure 63232001f49Smrg * file - (fopen'd) file descriptor 63332001f49Smrg */ 63432001f49Smrgstatic void 63532001f49Smrg_glmSecondPass(GLMmodel* model, FILE* file) 63632001f49Smrg{ 63732001f49Smrg uint numvertices; /* number of vertices in model */ 63832001f49Smrg uint numnormals; /* number of normals in model */ 63932001f49Smrg uint numtexcoords; /* number of texcoords in model */ 64032001f49Smrg uint numtriangles; /* number of triangles in model */ 64132001f49Smrg float* vertices; /* array of vertices */ 64232001f49Smrg float* normals; /* array of normals */ 64332001f49Smrg float* texcoords; /* array of texture coordinates */ 64432001f49Smrg GLMgroup* group; /* current group pointer */ 64532001f49Smrg uint material; /* current material */ 64632001f49Smrg uint v, n, t; 64732001f49Smrg char buf[128]; 64832001f49Smrg 64932001f49Smrg /* set the pointer shortcuts */ 65032001f49Smrg vertices = model->vertices; 65132001f49Smrg normals = model->normals; 65232001f49Smrg texcoords = model->texcoords; 65332001f49Smrg group = model->groups; 65432001f49Smrg 65532001f49Smrg /* on the second pass through the file, read all the data into the 65632001f49Smrg allocated arrays */ 65732001f49Smrg numvertices = numnormals = numtexcoords = 1; 65832001f49Smrg numtriangles = 0; 65932001f49Smrg material = 0; 66032001f49Smrg while(fscanf(file, "%s", buf) != EOF) { 66132001f49Smrg switch(buf[0]) { 66232001f49Smrg case '#': /* comment */ 66332001f49Smrg /* eat up rest of line */ 66432001f49Smrg fgets(buf, sizeof(buf), file); 66532001f49Smrg break; 66632001f49Smrg case 'v': /* v, vn, vt */ 66732001f49Smrg switch(buf[1]) { 66832001f49Smrg case '\0': /* vertex */ 66932001f49Smrg fscanf(file, "%f %f %f", 67032001f49Smrg &vertices[3 * numvertices + X], 67132001f49Smrg &vertices[3 * numvertices + Y], 67232001f49Smrg &vertices[3 * numvertices + Z]); 67332001f49Smrg numvertices++; 67432001f49Smrg break; 67532001f49Smrg case 'n': /* normal */ 67632001f49Smrg fscanf(file, "%f %f %f", 67732001f49Smrg &normals[3 * numnormals + X], 67832001f49Smrg &normals[3 * numnormals + Y], 67932001f49Smrg &normals[3 * numnormals + Z]); 68032001f49Smrg numnormals++; 68132001f49Smrg break; 68232001f49Smrg case 't': /* texcoord */ 68332001f49Smrg fscanf(file, "%f %f", 68432001f49Smrg &texcoords[2 * numtexcoords + X], 68532001f49Smrg &texcoords[2 * numtexcoords + Y]); 68632001f49Smrg numtexcoords++; 68732001f49Smrg break; 68832001f49Smrg } 68932001f49Smrg break; 69032001f49Smrg case 'u': 69132001f49Smrg fgets(buf, sizeof(buf), file); 69232001f49Smrg sscanf(buf, "%s %s", buf, buf); 69332001f49Smrg material = _glmFindMaterial(model, buf); 69432001f49Smrg if (!group->material) 69532001f49Smrg group->material = material; 69632001f49Smrg /*printf("material %s = %u\n", buf, material);*/ 69732001f49Smrg break; 69832001f49Smrg case 'g': /* group */ 69932001f49Smrg /* eat up rest of line */ 70032001f49Smrg fgets(buf, sizeof(buf), file); 70132001f49Smrg sscanf(buf, "%s", buf); 70232001f49Smrg group = _glmFindGroup(model, buf); 70332001f49Smrg group->material = material; 70432001f49Smrg /*printf("GROUP %s material %u\n", buf, material);*/ 70532001f49Smrg break; 70632001f49Smrg case 'f': /* face */ 70732001f49Smrg v = n = t = 0; 70832001f49Smrg fscanf(file, "%s", buf); 70932001f49Smrg /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 71032001f49Smrg if (strstr(buf, "//")) { 71132001f49Smrg /* v//n */ 71232001f49Smrg sscanf(buf, "%u//%u", &v, &n); 71332001f49Smrg T(numtriangles).vindices[0] = v; 71432001f49Smrg T(numtriangles).nindices[0] = n; 71532001f49Smrg fscanf(file, "%u//%u", &v, &n); 71632001f49Smrg T(numtriangles).vindices[1] = v; 71732001f49Smrg T(numtriangles).nindices[1] = n; 71832001f49Smrg fscanf(file, "%u//%u", &v, &n); 71932001f49Smrg T(numtriangles).vindices[2] = v; 72032001f49Smrg T(numtriangles).nindices[2] = n; 72132001f49Smrg group->triangles[group->numtriangles++] = numtriangles; 72232001f49Smrg numtriangles++; 72332001f49Smrg while(fscanf(file, "%u//%u", &v, &n) > 0) { 72432001f49Smrg T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 72532001f49Smrg T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; 72632001f49Smrg T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 72732001f49Smrg T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; 72832001f49Smrg T(numtriangles).vindices[2] = v; 72932001f49Smrg T(numtriangles).nindices[2] = n; 73032001f49Smrg group->triangles[group->numtriangles++] = numtriangles; 73132001f49Smrg numtriangles++; 73232001f49Smrg } 73332001f49Smrg } else if (sscanf(buf, "%u/%u/%u", &v, &t, &n) == 3) { 73432001f49Smrg /* v/t/n */ 73532001f49Smrg T(numtriangles).vindices[0] = v; 73632001f49Smrg T(numtriangles).tindices[0] = t; 73732001f49Smrg T(numtriangles).nindices[0] = n; 73832001f49Smrg fscanf(file, "%u/%u/%u", &v, &t, &n); 73932001f49Smrg T(numtriangles).vindices[1] = v; 74032001f49Smrg T(numtriangles).tindices[1] = t; 74132001f49Smrg T(numtriangles).nindices[1] = n; 74232001f49Smrg fscanf(file, "%u/%u/%u", &v, &t, &n); 74332001f49Smrg T(numtriangles).vindices[2] = v; 74432001f49Smrg T(numtriangles).tindices[2] = t; 74532001f49Smrg T(numtriangles).nindices[2] = n; 74632001f49Smrg group->triangles[group->numtriangles++] = numtriangles; 74732001f49Smrg numtriangles++; 74832001f49Smrg while(fscanf(file, "%u/%u/%u", &v, &t, &n) > 0) { 74932001f49Smrg T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 75032001f49Smrg T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; 75132001f49Smrg T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; 75232001f49Smrg T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 75332001f49Smrg T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; 75432001f49Smrg T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; 75532001f49Smrg T(numtriangles).vindices[2] = v; 75632001f49Smrg T(numtriangles).tindices[2] = t; 75732001f49Smrg T(numtriangles).nindices[2] = n; 75832001f49Smrg group->triangles[group->numtriangles++] = numtriangles; 75932001f49Smrg numtriangles++; 76032001f49Smrg } 76132001f49Smrg } else if (sscanf(buf, "%u/%u", &v, &t) == 2) { 76232001f49Smrg /* v/t */ 76332001f49Smrg T(numtriangles).vindices[0] = v; 76432001f49Smrg T(numtriangles).tindices[0] = t; 76532001f49Smrg fscanf(file, "%u/%u", &v, &t); 76632001f49Smrg T(numtriangles).vindices[1] = v; 76732001f49Smrg T(numtriangles).tindices[1] = t; 76832001f49Smrg fscanf(file, "%u/%u", &v, &t); 76932001f49Smrg T(numtriangles).vindices[2] = v; 77032001f49Smrg T(numtriangles).tindices[2] = t; 77132001f49Smrg group->triangles[group->numtriangles++] = numtriangles; 77232001f49Smrg numtriangles++; 77332001f49Smrg while(fscanf(file, "%u/%u", &v, &t) > 0) { 77432001f49Smrg T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 77532001f49Smrg T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; 77632001f49Smrg T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 77732001f49Smrg T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; 77832001f49Smrg T(numtriangles).vindices[2] = v; 77932001f49Smrg T(numtriangles).tindices[2] = t; 78032001f49Smrg group->triangles[group->numtriangles++] = numtriangles; 78132001f49Smrg numtriangles++; 78232001f49Smrg } 78332001f49Smrg } else { 78432001f49Smrg /* v */ 78532001f49Smrg sscanf(buf, "%u", &v); 78632001f49Smrg T(numtriangles).vindices[0] = v; 78732001f49Smrg fscanf(file, "%u", &v); 78832001f49Smrg T(numtriangles).vindices[1] = v; 78932001f49Smrg fscanf(file, "%u", &v); 79032001f49Smrg T(numtriangles).vindices[2] = v; 79132001f49Smrg group->triangles[group->numtriangles++] = numtriangles; 79232001f49Smrg numtriangles++; 79332001f49Smrg while(fscanf(file, "%u", &v) > 0) { 79432001f49Smrg T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 79532001f49Smrg T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 79632001f49Smrg T(numtriangles).vindices[2] = v; 79732001f49Smrg group->triangles[group->numtriangles++] = numtriangles; 79832001f49Smrg numtriangles++; 79932001f49Smrg } 80032001f49Smrg } 80132001f49Smrg break; 80232001f49Smrg 80332001f49Smrg default: 80432001f49Smrg /* eat up rest of line */ 80532001f49Smrg fgets(buf, sizeof(buf), file); 80632001f49Smrg break; 80732001f49Smrg } 80832001f49Smrg } 80932001f49Smrg 81032001f49Smrg#if 0 81132001f49Smrg /* announce the memory requirements */ 81232001f49Smrg printf(" Memory: %d bytes\n", 81332001f49Smrg numvertices * 3*sizeof(float) + 81432001f49Smrg numnormals * 3*sizeof(float) * (numnormals ? 1 : 0) + 81532001f49Smrg numtexcoords * 3*sizeof(float) * (numtexcoords ? 1 : 0) + 81632001f49Smrg numtriangles * sizeof(GLMtriangle)); 81732001f49Smrg#endif 81832001f49Smrg} 81932001f49Smrg 82032001f49Smrg 82132001f49Smrg 82232001f49Smrg 82332001f49Smrg/* public functions */ 82432001f49Smrg 82532001f49Smrg/* glmUnitize: "unitize" a model by translating it to the origin and 82632001f49Smrg * scaling it to fit in a unit cube around the origin. Returns the 82732001f49Smrg * scalefactor used. 82832001f49Smrg * 82932001f49Smrg * model - properly initialized GLMmodel structure 83032001f49Smrg */ 83132001f49Smrgfloat 83232001f49SmrgglmUnitize(GLMmodel* model) 83332001f49Smrg{ 83432001f49Smrg uint i; 83532001f49Smrg float maxx, minx, maxy, miny, maxz, minz; 83632001f49Smrg float cx, cy, cz, w, h, d; 83732001f49Smrg float scale; 83832001f49Smrg 83932001f49Smrg assert(model); 84032001f49Smrg assert(model->vertices); 84132001f49Smrg 84232001f49Smrg /* get the max/mins */ 84332001f49Smrg maxx = minx = model->vertices[3 + X]; 84432001f49Smrg maxy = miny = model->vertices[3 + Y]; 84532001f49Smrg maxz = minz = model->vertices[3 + Z]; 84632001f49Smrg for (i = 1; i <= model->numvertices; i++) { 84732001f49Smrg if (maxx < model->vertices[3 * i + X]) 84832001f49Smrg maxx = model->vertices[3 * i + X]; 84932001f49Smrg if (minx > model->vertices[3 * i + X]) 85032001f49Smrg minx = model->vertices[3 * i + X]; 85132001f49Smrg 85232001f49Smrg if (maxy < model->vertices[3 * i + Y]) 85332001f49Smrg maxy = model->vertices[3 * i + Y]; 85432001f49Smrg if (miny > model->vertices[3 * i + Y]) 85532001f49Smrg miny = model->vertices[3 * i + Y]; 85632001f49Smrg 85732001f49Smrg if (maxz < model->vertices[3 * i + Z]) 85832001f49Smrg maxz = model->vertices[3 * i + Z]; 85932001f49Smrg if (minz > model->vertices[3 * i + Z]) 86032001f49Smrg minz = model->vertices[3 * i + Z]; 86132001f49Smrg } 86232001f49Smrg 86332001f49Smrg /* calculate model width, height, and depth */ 86432001f49Smrg w = _glmAbs(maxx) + _glmAbs(minx); 86532001f49Smrg h = _glmAbs(maxy) + _glmAbs(miny); 86632001f49Smrg d = _glmAbs(maxz) + _glmAbs(minz); 86732001f49Smrg 86832001f49Smrg /* calculate center of the model */ 86932001f49Smrg cx = (maxx + minx) / 2.0; 87032001f49Smrg cy = (maxy + miny) / 2.0; 87132001f49Smrg cz = (maxz + minz) / 2.0; 87232001f49Smrg 87332001f49Smrg /* calculate unitizing scale factor */ 87432001f49Smrg scale = 2.0 / _glmMax(_glmMax(w, h), d); 87532001f49Smrg 87632001f49Smrg /* translate around center then scale */ 87732001f49Smrg for (i = 1; i <= model->numvertices; i++) { 87832001f49Smrg model->vertices[3 * i + X] -= cx; 87932001f49Smrg model->vertices[3 * i + Y] -= cy; 88032001f49Smrg model->vertices[3 * i + Z] -= cz; 88132001f49Smrg model->vertices[3 * i + X] *= scale; 88232001f49Smrg model->vertices[3 * i + Y] *= scale; 88332001f49Smrg model->vertices[3 * i + Z] *= scale; 88432001f49Smrg } 88532001f49Smrg 88632001f49Smrg return scale; 88732001f49Smrg} 88832001f49Smrg 88932001f49Smrg/* glmDimensions: Calculates the dimensions (width, height, depth) of 89032001f49Smrg * a model. 89132001f49Smrg * 89232001f49Smrg * model - initialized GLMmodel structure 89332001f49Smrg * dimensions - array of 3 floats (float dimensions[3]) 89432001f49Smrg */ 89532001f49Smrgvoid 89632001f49SmrgglmDimensions(GLMmodel* model, float* dimensions) 89732001f49Smrg{ 89832001f49Smrg uint i; 89932001f49Smrg float maxx, minx, maxy, miny, maxz, minz; 90032001f49Smrg 90132001f49Smrg assert(model); 90232001f49Smrg assert(model->vertices); 90332001f49Smrg assert(dimensions); 90432001f49Smrg 90532001f49Smrg /* get the max/mins */ 90632001f49Smrg maxx = minx = model->vertices[3 + X]; 90732001f49Smrg maxy = miny = model->vertices[3 + Y]; 90832001f49Smrg maxz = minz = model->vertices[3 + Z]; 90932001f49Smrg for (i = 1; i <= model->numvertices; i++) { 91032001f49Smrg if (maxx < model->vertices[3 * i + X]) 91132001f49Smrg maxx = model->vertices[3 * i + X]; 91232001f49Smrg if (minx > model->vertices[3 * i + X]) 91332001f49Smrg minx = model->vertices[3 * i + X]; 91432001f49Smrg 91532001f49Smrg if (maxy < model->vertices[3 * i + Y]) 91632001f49Smrg maxy = model->vertices[3 * i + Y]; 91732001f49Smrg if (miny > model->vertices[3 * i + Y]) 91832001f49Smrg miny = model->vertices[3 * i + Y]; 91932001f49Smrg 92032001f49Smrg if (maxz < model->vertices[3 * i + Z]) 92132001f49Smrg maxz = model->vertices[3 * i + Z]; 92232001f49Smrg if (minz > model->vertices[3 * i + Z]) 92332001f49Smrg minz = model->vertices[3 * i + Z]; 92432001f49Smrg } 92532001f49Smrg 92632001f49Smrg /* calculate model width, height, and depth */ 92732001f49Smrg dimensions[X] = _glmAbs(maxx) + _glmAbs(minx); 92832001f49Smrg dimensions[Y] = _glmAbs(maxy) + _glmAbs(miny); 92932001f49Smrg dimensions[Z] = _glmAbs(maxz) + _glmAbs(minz); 93032001f49Smrg} 93132001f49Smrg 93232001f49Smrg/* glmScale: Scales a model by a given amount. 93332001f49Smrg * 93432001f49Smrg * model - properly initialized GLMmodel structure 93532001f49Smrg * scale - scalefactor (0.5 = half as large, 2.0 = twice as large) 93632001f49Smrg */ 93732001f49Smrgvoid 93832001f49SmrgglmScale(GLMmodel* model, float scale) 93932001f49Smrg{ 94032001f49Smrg uint i; 94132001f49Smrg 94232001f49Smrg for (i = 1; i <= model->numvertices; i++) { 94332001f49Smrg model->vertices[3 * i + X] *= scale; 94432001f49Smrg model->vertices[3 * i + Y] *= scale; 94532001f49Smrg model->vertices[3 * i + Z] *= scale; 94632001f49Smrg } 94732001f49Smrg} 94832001f49Smrg 94932001f49Smrg/* glmReverseWinding: Reverse the polygon winding for all polygons in 95032001f49Smrg * this model. Default winding is counter-clockwise. Also changes 95132001f49Smrg * the direction of the normals. 95232001f49Smrg * 95332001f49Smrg * model - properly initialized GLMmodel structure 95432001f49Smrg */ 95532001f49Smrgvoid 95632001f49SmrgglmReverseWinding(GLMmodel* model) 95732001f49Smrg{ 95832001f49Smrg uint i, swap; 95932001f49Smrg 96032001f49Smrg assert(model); 96132001f49Smrg 96232001f49Smrg for (i = 0; i < model->numtriangles; i++) { 96332001f49Smrg swap = T(i).vindices[0]; 96432001f49Smrg T(i).vindices[0] = T(i).vindices[2]; 96532001f49Smrg T(i).vindices[2] = swap; 96632001f49Smrg 96732001f49Smrg if (model->numnormals) { 96832001f49Smrg swap = T(i).nindices[0]; 96932001f49Smrg T(i).nindices[0] = T(i).nindices[2]; 97032001f49Smrg T(i).nindices[2] = swap; 97132001f49Smrg } 97232001f49Smrg 97332001f49Smrg if (model->numtexcoords) { 97432001f49Smrg swap = T(i).tindices[0]; 97532001f49Smrg T(i).tindices[0] = T(i).tindices[2]; 97632001f49Smrg T(i).tindices[2] = swap; 97732001f49Smrg } 97832001f49Smrg } 97932001f49Smrg 98032001f49Smrg /* reverse facet normals */ 98132001f49Smrg for (i = 1; i <= model->numfacetnorms; i++) { 98232001f49Smrg model->facetnorms[3 * i + X] = -model->facetnorms[3 * i + X]; 98332001f49Smrg model->facetnorms[3 * i + Y] = -model->facetnorms[3 * i + Y]; 98432001f49Smrg model->facetnorms[3 * i + Z] = -model->facetnorms[3 * i + Z]; 98532001f49Smrg } 98632001f49Smrg 98732001f49Smrg /* reverse vertex normals */ 98832001f49Smrg for (i = 1; i <= model->numnormals; i++) { 98932001f49Smrg model->normals[3 * i + X] = -model->normals[3 * i + X]; 99032001f49Smrg model->normals[3 * i + Y] = -model->normals[3 * i + Y]; 99132001f49Smrg model->normals[3 * i + Z] = -model->normals[3 * i + Z]; 99232001f49Smrg } 99332001f49Smrg} 99432001f49Smrg 99532001f49Smrg/* glmFacetNormals: Generates facet normals for a model (by taking the 99632001f49Smrg * cross product of the two vectors derived from the sides of each 99732001f49Smrg * triangle). Assumes a counter-clockwise winding. 99832001f49Smrg * 99932001f49Smrg * model - initialized GLMmodel structure 100032001f49Smrg */ 100132001f49Smrgvoid 100232001f49SmrgglmFacetNormals(GLMmodel* model) 100332001f49Smrg{ 100432001f49Smrg uint i; 100532001f49Smrg float u[3]; 100632001f49Smrg float v[3]; 100732001f49Smrg 100832001f49Smrg assert(model); 100932001f49Smrg assert(model->vertices); 101032001f49Smrg 101132001f49Smrg /* clobber any old facetnormals */ 101232001f49Smrg if (model->facetnorms) 101332001f49Smrg free(model->facetnorms); 101432001f49Smrg 101532001f49Smrg /* allocate memory for the new facet normals */ 101632001f49Smrg model->numfacetnorms = model->numtriangles; 101732001f49Smrg model->facetnorms = (float*)malloc(sizeof(float) * 101832001f49Smrg 3 * (model->numfacetnorms + 1)); 101932001f49Smrg 102032001f49Smrg for (i = 0; i < model->numtriangles; i++) { 102132001f49Smrg model->triangles[i].findex = i+1; 102232001f49Smrg 102332001f49Smrg u[X] = model->vertices[3 * T(i).vindices[1] + X] - 102432001f49Smrg model->vertices[3 * T(i).vindices[0] + X]; 102532001f49Smrg u[Y] = model->vertices[3 * T(i).vindices[1] + Y] - 102632001f49Smrg model->vertices[3 * T(i).vindices[0] + Y]; 102732001f49Smrg u[Z] = model->vertices[3 * T(i).vindices[1] + Z] - 102832001f49Smrg model->vertices[3 * T(i).vindices[0] + Z]; 102932001f49Smrg 103032001f49Smrg v[X] = model->vertices[3 * T(i).vindices[2] + X] - 103132001f49Smrg model->vertices[3 * T(i).vindices[0] + X]; 103232001f49Smrg v[Y] = model->vertices[3 * T(i).vindices[2] + Y] - 103332001f49Smrg model->vertices[3 * T(i).vindices[0] + Y]; 103432001f49Smrg v[Z] = model->vertices[3 * T(i).vindices[2] + Z] - 103532001f49Smrg model->vertices[3 * T(i).vindices[0] + Z]; 103632001f49Smrg 103732001f49Smrg _glmCross(u, v, &model->facetnorms[3 * (i+1)]); 103832001f49Smrg _glmNormalize(&model->facetnorms[3 * (i+1)]); 103932001f49Smrg } 104032001f49Smrg} 104132001f49Smrg 104232001f49Smrg/* glmVertexNormals: Generates smooth vertex normals for a model. 104332001f49Smrg * First builds a list of all the triangles each vertex is in. Then 104432001f49Smrg * loops through each vertex in the list averaging all the facet 104532001f49Smrg * normals of the triangles each vertex is in. Finally, sets the 104632001f49Smrg * normal index in the triangle for the vertex to the generated smooth 104732001f49Smrg * normal. If the dot product of a facet normal and the facet normal 104832001f49Smrg * associated with the first triangle in the list of triangles the 104932001f49Smrg * current vertex is in is greater than the cosine of the angle 105032001f49Smrg * parameter to the function, that facet normal is not added into the 105132001f49Smrg * average normal calculation and the corresponding vertex is given 105232001f49Smrg * the facet normal. This tends to preserve hard edges. The angle to 105332001f49Smrg * use depends on the model, but 90 degrees is usually a good start. 105432001f49Smrg * 105532001f49Smrg * model - initialized GLMmodel structure 105632001f49Smrg * angle - maximum angle (in degrees) to smooth across 105732001f49Smrg */ 105832001f49Smrgvoid 105932001f49SmrgglmVertexNormals(GLMmodel* model, float angle) 106032001f49Smrg{ 106132001f49Smrg GLMnode* node; 106232001f49Smrg GLMnode* tail; 106332001f49Smrg GLMnode** members; 106432001f49Smrg float* normals; 106532001f49Smrg uint numnormals; 106632001f49Smrg float average[3]; 106732001f49Smrg float dot, cos_angle; 106832001f49Smrg uint i, avg; 106932001f49Smrg 107032001f49Smrg assert(model); 107132001f49Smrg assert(model->facetnorms); 107232001f49Smrg 107332001f49Smrg /* calculate the cosine of the angle (in degrees) */ 107432001f49Smrg cos_angle = cos(angle * M_PI / 180.0); 107532001f49Smrg 107632001f49Smrg /* nuke any previous normals */ 107732001f49Smrg if (model->normals) 107832001f49Smrg free(model->normals); 107932001f49Smrg 108032001f49Smrg /* allocate space for new normals */ 108132001f49Smrg model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */ 108232001f49Smrg model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1)); 108332001f49Smrg 108432001f49Smrg /* allocate a structure that will hold a linked list of triangle 108532001f49Smrg indices for each vertex */ 108632001f49Smrg members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1)); 108732001f49Smrg for (i = 1; i <= model->numvertices; i++) 108832001f49Smrg members[i] = NULL; 108932001f49Smrg 109032001f49Smrg /* for every triangle, create a node for each vertex in it */ 109132001f49Smrg for (i = 0; i < model->numtriangles; i++) { 109232001f49Smrg node = (GLMnode*)malloc(sizeof(GLMnode)); 109332001f49Smrg node->index = i; 109432001f49Smrg node->next = members[T(i).vindices[0]]; 109532001f49Smrg members[T(i).vindices[0]] = node; 109632001f49Smrg 109732001f49Smrg node = (GLMnode*)malloc(sizeof(GLMnode)); 109832001f49Smrg node->index = i; 109932001f49Smrg node->next = members[T(i).vindices[1]]; 110032001f49Smrg members[T(i).vindices[1]] = node; 110132001f49Smrg 110232001f49Smrg node = (GLMnode*)malloc(sizeof(GLMnode)); 110332001f49Smrg node->index = i; 110432001f49Smrg node->next = members[T(i).vindices[2]]; 110532001f49Smrg members[T(i).vindices[2]] = node; 110632001f49Smrg } 110732001f49Smrg 110832001f49Smrg /* calculate the average normal for each vertex */ 110932001f49Smrg numnormals = 1; 111032001f49Smrg for (i = 1; i <= model->numvertices; i++) { 111132001f49Smrg /* calculate an average normal for this vertex by averaging the 111232001f49Smrg facet normal of every triangle this vertex is in */ 111332001f49Smrg node = members[i]; 111432001f49Smrg if (!node) 111532001f49Smrg fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n"); 111632001f49Smrg average[0] = 0.0; average[1] = 0.0; average[2] = 0.0; 111732001f49Smrg avg = 0; 111832001f49Smrg while (node) { 111932001f49Smrg /* only average if the dot product of the angle between the two 112032001f49Smrg facet normals is greater than the cosine of the threshold 112132001f49Smrg angle -- or, said another way, the angle between the two 112232001f49Smrg facet normals is less than (or equal to) the threshold angle */ 112332001f49Smrg dot = _glmDot(&model->facetnorms[3 * T(node->index).findex], 112432001f49Smrg &model->facetnorms[3 * T(members[i]->index).findex]); 112532001f49Smrg if (dot > cos_angle) { 112632001f49Smrg node->averaged = TRUE; 112732001f49Smrg average[0] += model->facetnorms[3 * T(node->index).findex + 0]; 112832001f49Smrg average[1] += model->facetnorms[3 * T(node->index).findex + 1]; 112932001f49Smrg average[2] += model->facetnorms[3 * T(node->index).findex + 2]; 113032001f49Smrg avg = 1; /* we averaged at least one normal! */ 113132001f49Smrg } else { 113232001f49Smrg node->averaged = FALSE; 113332001f49Smrg } 113432001f49Smrg node = node->next; 113532001f49Smrg } 113632001f49Smrg 113732001f49Smrg if (avg) { 113832001f49Smrg /* normalize the averaged normal */ 113932001f49Smrg _glmNormalize(average); 114032001f49Smrg 114132001f49Smrg /* add the normal to the vertex normals list */ 114232001f49Smrg model->normals[3 * numnormals + 0] = average[0]; 114332001f49Smrg model->normals[3 * numnormals + 1] = average[1]; 114432001f49Smrg model->normals[3 * numnormals + 2] = average[2]; 114532001f49Smrg avg = numnormals; 114632001f49Smrg numnormals++; 114732001f49Smrg } 114832001f49Smrg 114932001f49Smrg /* set the normal of this vertex in each triangle it is in */ 115032001f49Smrg node = members[i]; 115132001f49Smrg while (node) { 115232001f49Smrg if (node->averaged) { 115332001f49Smrg /* if this node was averaged, use the average normal */ 115432001f49Smrg if (T(node->index).vindices[0] == i) 115532001f49Smrg T(node->index).nindices[0] = avg; 115632001f49Smrg else if (T(node->index).vindices[1] == i) 115732001f49Smrg T(node->index).nindices[1] = avg; 115832001f49Smrg else if (T(node->index).vindices[2] == i) 115932001f49Smrg T(node->index).nindices[2] = avg; 116032001f49Smrg } else { 116132001f49Smrg /* if this node wasn't averaged, use the facet normal */ 116232001f49Smrg model->normals[3 * numnormals + 0] = 116332001f49Smrg model->facetnorms[3 * T(node->index).findex + 0]; 116432001f49Smrg model->normals[3 * numnormals + 1] = 116532001f49Smrg model->facetnorms[3 * T(node->index).findex + 1]; 116632001f49Smrg model->normals[3 * numnormals + 2] = 116732001f49Smrg model->facetnorms[3 * T(node->index).findex + 2]; 116832001f49Smrg if (T(node->index).vindices[0] == i) 116932001f49Smrg T(node->index).nindices[0] = numnormals; 117032001f49Smrg else if (T(node->index).vindices[1] == i) 117132001f49Smrg T(node->index).nindices[1] = numnormals; 117232001f49Smrg else if (T(node->index).vindices[2] == i) 117332001f49Smrg T(node->index).nindices[2] = numnormals; 117432001f49Smrg numnormals++; 117532001f49Smrg } 117632001f49Smrg node = node->next; 117732001f49Smrg } 117832001f49Smrg } 117932001f49Smrg 118032001f49Smrg model->numnormals = numnormals - 1; 118132001f49Smrg 118232001f49Smrg /* free the member information */ 118332001f49Smrg for (i = 1; i <= model->numvertices; i++) { 118432001f49Smrg node = members[i]; 118532001f49Smrg while (node) { 118632001f49Smrg tail = node; 118732001f49Smrg node = node->next; 118832001f49Smrg free(tail); 118932001f49Smrg } 119032001f49Smrg } 119132001f49Smrg free(members); 119232001f49Smrg 119332001f49Smrg /* pack the normals array (we previously allocated the maximum 119432001f49Smrg number of normals that could possibly be created (numtriangles * 119532001f49Smrg 3), so get rid of some of them (usually alot unless none of the 119632001f49Smrg facet normals were averaged)) */ 119732001f49Smrg normals = model->normals; 119832001f49Smrg model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1)); 119932001f49Smrg for (i = 1; i <= model->numnormals; i++) { 120032001f49Smrg model->normals[3 * i + 0] = normals[3 * i + 0]; 120132001f49Smrg model->normals[3 * i + 1] = normals[3 * i + 1]; 120232001f49Smrg model->normals[3 * i + 2] = normals[3 * i + 2]; 120332001f49Smrg } 120432001f49Smrg free(normals); 120532001f49Smrg 120632001f49Smrg printf("glmVertexNormals(): %d normals generated\n", model->numnormals); 120732001f49Smrg} 120832001f49Smrg 120932001f49Smrg 121032001f49Smrg/* glmLinearTexture: Generates texture coordinates according to a 121132001f49Smrg * linear projection of the texture map. It generates these by 121232001f49Smrg * linearly mapping the vertices onto a square. 121332001f49Smrg * 121432001f49Smrg * model - pointer to initialized GLMmodel structure 121532001f49Smrg */ 121632001f49Smrgvoid 121732001f49SmrgglmLinearTexture(GLMmodel* model) 121832001f49Smrg{ 121932001f49Smrg GLMgroup *group; 122032001f49Smrg float dimensions[3]; 122132001f49Smrg float x, y, scalefactor; 122232001f49Smrg uint i; 122332001f49Smrg 122432001f49Smrg assert(model); 122532001f49Smrg 122632001f49Smrg if (model->texcoords) 122732001f49Smrg free(model->texcoords); 122832001f49Smrg model->numtexcoords = model->numvertices; 122932001f49Smrg model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1)); 123032001f49Smrg 123132001f49Smrg glmDimensions(model, dimensions); 123232001f49Smrg scalefactor = 2.0 / 123332001f49Smrg _glmAbs(_glmMax(_glmMax(dimensions[0], dimensions[1]), dimensions[2])); 123432001f49Smrg 123532001f49Smrg /* do the calculations */ 123632001f49Smrg for(i = 1; i <= model->numvertices; i++) { 123732001f49Smrg x = model->vertices[3 * i + 0] * scalefactor; 123832001f49Smrg y = model->vertices[3 * i + 2] * scalefactor; 123932001f49Smrg model->texcoords[2 * i + 0] = (x + 1.0) / 2.0; 124032001f49Smrg model->texcoords[2 * i + 1] = (y + 1.0) / 2.0; 124132001f49Smrg } 124232001f49Smrg 124332001f49Smrg /* go through and put texture coordinate indices in all the triangles */ 124432001f49Smrg group = model->groups; 124532001f49Smrg while(group) { 124632001f49Smrg for(i = 0; i < group->numtriangles; i++) { 124732001f49Smrg T(group->triangles[i]).tindices[0] = T(group->triangles[i]).vindices[0]; 124832001f49Smrg T(group->triangles[i]).tindices[1] = T(group->triangles[i]).vindices[1]; 124932001f49Smrg T(group->triangles[i]).tindices[2] = T(group->triangles[i]).vindices[2]; 125032001f49Smrg } 125132001f49Smrg group = group->next; 125232001f49Smrg } 125332001f49Smrg 125432001f49Smrg#if 0 125532001f49Smrg printf("glmLinearTexture(): generated %d linear texture coordinates\n", 125632001f49Smrg model->numtexcoords); 125732001f49Smrg#endif 125832001f49Smrg} 125932001f49Smrg 126032001f49Smrg/* glmSpheremapTexture: Generates texture coordinates according to a 126132001f49Smrg * spherical projection of the texture map. Sometimes referred to as 126232001f49Smrg * spheremap, or reflection map texture coordinates. It generates 126332001f49Smrg * these by using the normal to calculate where that vertex would map 126432001f49Smrg * onto a sphere. Since it is impossible to map something flat 126532001f49Smrg * perfectly onto something spherical, there is distortion at the 126632001f49Smrg * poles. This particular implementation causes the poles along the X 126732001f49Smrg * axis to be distorted. 126832001f49Smrg * 126932001f49Smrg * model - pointer to initialized GLMmodel structure 127032001f49Smrg */ 127132001f49Smrgvoid 127232001f49SmrgglmSpheremapTexture(GLMmodel* model) 127332001f49Smrg{ 127432001f49Smrg GLMgroup* group; 127532001f49Smrg float theta, phi, rho, x, y, z, r; 127632001f49Smrg uint i; 127732001f49Smrg 127832001f49Smrg assert(model); 127932001f49Smrg assert(model->normals); 128032001f49Smrg 128132001f49Smrg if (model->texcoords) 128232001f49Smrg free(model->texcoords); 128332001f49Smrg model->numtexcoords = model->numnormals; 128432001f49Smrg model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1)); 128532001f49Smrg 128632001f49Smrg /* do the calculations */ 128732001f49Smrg for (i = 1; i <= model->numnormals; i++) { 128832001f49Smrg z = model->normals[3 * i + 0]; /* re-arrange for pole distortion */ 128932001f49Smrg y = model->normals[3 * i + 1]; 129032001f49Smrg x = model->normals[3 * i + 2]; 129132001f49Smrg r = sqrt((x * x) + (y * y)); 129232001f49Smrg rho = sqrt((r * r) + (z * z)); 129332001f49Smrg 129432001f49Smrg if(r == 0.0) { 129532001f49Smrg theta = 0.0; 129632001f49Smrg phi = 0.0; 129732001f49Smrg } else { 129832001f49Smrg if(z == 0.0) 129932001f49Smrg phi = M_PI / 2.0; 130032001f49Smrg else 130132001f49Smrg phi = acos(z / rho); 130232001f49Smrg 130332001f49Smrg#if WE_DONT_NEED_THIS_CODE 130432001f49Smrg if(x == 0.0) 130532001f49Smrg theta = M_PI / 2.0; /* asin(y / r); */ 130632001f49Smrg else 130732001f49Smrg theta = acos(x / r); 130832001f49Smrg#endif 130932001f49Smrg 131032001f49Smrg if(y == 0.0) 131132001f49Smrg theta = M_PI / 2.0; /* acos(x / r); */ 131232001f49Smrg else 131332001f49Smrg theta = asin(y / r) + (M_PI / 2.0); 131432001f49Smrg } 131532001f49Smrg 131632001f49Smrg model->texcoords[2 * i + 0] = theta / M_PI; 131732001f49Smrg model->texcoords[2 * i + 1] = phi / M_PI; 131832001f49Smrg } 131932001f49Smrg 132032001f49Smrg /* go through and put texcoord indices in all the triangles */ 132132001f49Smrg group = model->groups; 132232001f49Smrg while(group) { 132332001f49Smrg for (i = 0; i < group->numtriangles; i++) { 132432001f49Smrg T(group->triangles[i]).tindices[0] = T(group->triangles[i]).nindices[0]; 132532001f49Smrg T(group->triangles[i]).tindices[1] = T(group->triangles[i]).nindices[1]; 132632001f49Smrg T(group->triangles[i]).tindices[2] = T(group->triangles[i]).nindices[2]; 132732001f49Smrg } 132832001f49Smrg group = group->next; 132932001f49Smrg } 133032001f49Smrg 133132001f49Smrg#if 0 133232001f49Smrg printf("glmSpheremapTexture(): generated %d spheremap texture coordinates\n", 133332001f49Smrg model->numtexcoords); 133432001f49Smrg#endif 133532001f49Smrg} 133632001f49Smrg 133732001f49Smrg/* glmDelete: Deletes a GLMmodel structure. 133832001f49Smrg * 133932001f49Smrg * model - initialized GLMmodel structure 134032001f49Smrg */ 134132001f49Smrgvoid 134232001f49SmrgglmDelete(GLMmodel* model) 134332001f49Smrg{ 134432001f49Smrg GLMgroup* group; 134532001f49Smrg uint i; 134632001f49Smrg 134732001f49Smrg assert(model); 134832001f49Smrg 134932001f49Smrg if (model->pathname) free(model->pathname); 135032001f49Smrg if (model->mtllibname) free(model->mtllibname); 135132001f49Smrg if (model->vertices) free(model->vertices); 135232001f49Smrg if (model->normals) free(model->normals); 135332001f49Smrg if (model->texcoords) free(model->texcoords); 135432001f49Smrg if (model->facetnorms) free(model->facetnorms); 135532001f49Smrg if (model->triangles) free(model->triangles); 135632001f49Smrg if (model->materials) { 135732001f49Smrg for (i = 0; i < model->nummaterials; i++) 135832001f49Smrg free(model->materials[i].name); 135932001f49Smrg } 136032001f49Smrg free(model->materials); 136132001f49Smrg while(model->groups) { 136232001f49Smrg group = model->groups; 136332001f49Smrg model->groups = model->groups->next; 136432001f49Smrg free(group->name); 136532001f49Smrg free(group->triangles); 136632001f49Smrg free(group); 136732001f49Smrg } 136832001f49Smrg 136932001f49Smrg free(model); 137032001f49Smrg} 137132001f49Smrg 137232001f49Smrgstatic GLMmaterial * 137332001f49SmrgglmDefaultMaterial(void) 137432001f49Smrg{ 137532001f49Smrg GLMmaterial *m = (GLMmaterial *) calloc(1, sizeof(GLMmaterial)); 137632001f49Smrg 137732001f49Smrg m->diffuse[0] = 0.75; 137832001f49Smrg m->diffuse[1] = 0.75; 137932001f49Smrg m->diffuse[2] = 0.75; 138032001f49Smrg m->diffuse[3] = 1.0; 138132001f49Smrg 138232001f49Smrg m->specular[0] = 1.0; 138332001f49Smrg m->specular[1] = 1.0; 138432001f49Smrg m->specular[2] = 1.0; 138532001f49Smrg m->specular[3] = 1.0; 138632001f49Smrg 138732001f49Smrg m->shininess = 5; 138832001f49Smrg 138932001f49Smrg return m; 139032001f49Smrg} 139132001f49Smrg 139232001f49Smrg 139332001f49Smrg/* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. 139432001f49Smrg * Returns a pointer to the created object which should be free'd with 139532001f49Smrg * glmDelete(). 139632001f49Smrg * 139732001f49Smrg * filename - name of the file containing the Wavefront .OBJ format data. 139832001f49Smrg */ 139932001f49SmrgGLMmodel* 140032001f49SmrgglmReadOBJ(char* filename) 140132001f49Smrg{ 140232001f49Smrg GLMmodel* model; 140332001f49Smrg FILE* file; 140432001f49Smrg 140532001f49Smrg /* open the file */ 140632001f49Smrg file = fopen(filename, "r"); 140732001f49Smrg if (!file) { 140832001f49Smrg fprintf(stderr, "glmReadOBJ() failed: can't open data file \"%s\".\n", 140932001f49Smrg filename); 141032001f49Smrg exit(1); 141132001f49Smrg } 141232001f49Smrg 141332001f49Smrg#if 0 141432001f49Smrg /* announce the model name */ 141532001f49Smrg printf("Model: %s\n", filename); 141632001f49Smrg#endif 141732001f49Smrg 141832001f49Smrg /* allocate a new model */ 141932001f49Smrg model = (GLMmodel*)malloc(sizeof(GLMmodel)); 142032001f49Smrg model->pathname = stralloc(filename); 142132001f49Smrg model->mtllibname = NULL; 142232001f49Smrg model->numvertices = 0; 142332001f49Smrg model->vertices = NULL; 142432001f49Smrg model->numnormals = 0; 142532001f49Smrg model->normals = NULL; 142632001f49Smrg model->numtexcoords = 0; 142732001f49Smrg model->texcoords = NULL; 142832001f49Smrg model->numfacetnorms = 0; 142932001f49Smrg model->facetnorms = NULL; 143032001f49Smrg model->numtriangles = 0; 143132001f49Smrg model->triangles = NULL; 143232001f49Smrg model->nummaterials = 0; 143332001f49Smrg model->materials = NULL; 143432001f49Smrg model->numgroups = 0; 143532001f49Smrg model->groups = NULL; 143632001f49Smrg model->position[0] = 0.0; 143732001f49Smrg model->position[1] = 0.0; 143832001f49Smrg model->position[2] = 0.0; 143932001f49Smrg model->scale = 1.0; 144032001f49Smrg 144132001f49Smrg /* make a first pass through the file to get a count of the number 144232001f49Smrg of vertices, normals, texcoords & triangles */ 144332001f49Smrg _glmFirstPass(model, file); 144432001f49Smrg 144532001f49Smrg /* allocate memory */ 144632001f49Smrg model->vertices = (float*)malloc(sizeof(float) * 144732001f49Smrg 3 * (model->numvertices + 1)); 144832001f49Smrg model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) * 144932001f49Smrg model->numtriangles); 145032001f49Smrg if (model->numnormals) { 145132001f49Smrg model->normals = (float*)malloc(sizeof(float) * 145232001f49Smrg 3 * (model->numnormals + 1)); 145332001f49Smrg } 145432001f49Smrg if (model->numtexcoords) { 145532001f49Smrg model->texcoords = (float*)malloc(sizeof(float) * 145632001f49Smrg 2 * (model->numtexcoords + 1)); 145732001f49Smrg } 145832001f49Smrg 145932001f49Smrg /* rewind to beginning of file and read in the data this pass */ 146032001f49Smrg rewind(file); 146132001f49Smrg 146232001f49Smrg _glmSecondPass(model, file); 146332001f49Smrg 146432001f49Smrg /* close the file */ 146532001f49Smrg fclose(file); 146632001f49Smrg 146732001f49Smrg if (!model->materials) { 146832001f49Smrg model->materials = glmDefaultMaterial(); 146932001f49Smrg model->nummaterials = 1; 147032001f49Smrg } 147132001f49Smrg 147232001f49Smrg return model; 147332001f49Smrg} 147432001f49Smrg 147532001f49Smrg/* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to 147632001f49Smrg * a file. 147732001f49Smrg * 147832001f49Smrg * model - initialized GLMmodel structure 147932001f49Smrg * filename - name of the file to write the Wavefront .OBJ format data to 148032001f49Smrg * mode - a bitwise or of values describing what is written to the file 148132001f49Smrg * GLM_NONE - render with only vertices 148232001f49Smrg * GLM_FLAT - render with facet normals 148332001f49Smrg * GLM_SMOOTH - render with vertex normals 148432001f49Smrg * GLM_TEXTURE - render with texture coords 148532001f49Smrg * GLM_COLOR - render with colors (color material) 148632001f49Smrg * GLM_MATERIAL - render with materials 148732001f49Smrg * GLM_COLOR and GLM_MATERIAL should not both be specified. 148832001f49Smrg * GLM_FLAT and GLM_SMOOTH should not both be specified. 148932001f49Smrg */ 149032001f49Smrgvoid 149132001f49SmrgglmWriteOBJ(GLMmodel* model, char* filename, uint mode) 149232001f49Smrg{ 149332001f49Smrg uint i; 149432001f49Smrg FILE* file; 149532001f49Smrg GLMgroup* group; 149632001f49Smrg 149732001f49Smrg assert(model); 149832001f49Smrg 149932001f49Smrg /* do a bit of warning */ 150032001f49Smrg if (mode & GLM_FLAT && !model->facetnorms) { 150132001f49Smrg printf("glmWriteOBJ() warning: flat normal output requested " 150232001f49Smrg "with no facet normals defined.\n"); 150332001f49Smrg mode &= ~GLM_FLAT; 150432001f49Smrg } 150532001f49Smrg if (mode & GLM_SMOOTH && !model->normals) { 150632001f49Smrg printf("glmWriteOBJ() warning: smooth normal output requested " 150732001f49Smrg "with no normals defined.\n"); 150832001f49Smrg mode &= ~GLM_SMOOTH; 150932001f49Smrg } 151032001f49Smrg if (mode & GLM_TEXTURE && !model->texcoords) { 151132001f49Smrg printf("glmWriteOBJ() warning: texture coordinate output requested " 151232001f49Smrg "with no texture coordinates defined.\n"); 151332001f49Smrg mode &= ~GLM_TEXTURE; 151432001f49Smrg } 151532001f49Smrg if (mode & GLM_FLAT && mode & GLM_SMOOTH) { 151632001f49Smrg printf("glmWriteOBJ() warning: flat normal output requested " 151732001f49Smrg "and smooth normal output requested (using smooth).\n"); 151832001f49Smrg mode &= ~GLM_FLAT; 151932001f49Smrg } 152032001f49Smrg 152132001f49Smrg /* open the file */ 152232001f49Smrg file = fopen(filename, "w"); 152332001f49Smrg if (!file) { 152432001f49Smrg fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n", 152532001f49Smrg filename); 152632001f49Smrg exit(1); 152732001f49Smrg } 152832001f49Smrg 152932001f49Smrg /* spit out a header */ 153032001f49Smrg fprintf(file, "# \n"); 153132001f49Smrg fprintf(file, "# Wavefront OBJ generated by GLM library\n"); 153232001f49Smrg fprintf(file, "# \n"); 153332001f49Smrg fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n"); 153432001f49Smrg fprintf(file, "# email: ndr@pobox.com\n"); 153532001f49Smrg fprintf(file, "# www: http://www.pobox.com/~ndr\n"); 153632001f49Smrg fprintf(file, "# \n"); 153732001f49Smrg 153832001f49Smrg if (mode & GLM_MATERIAL && model->mtllibname) { 153932001f49Smrg fprintf(file, "\nmtllib %s\n\n", model->mtllibname); 154032001f49Smrg _glmWriteMTL(model, filename, model->mtllibname); 154132001f49Smrg } 154232001f49Smrg 154332001f49Smrg /* spit out the vertices */ 154432001f49Smrg fprintf(file, "\n"); 154532001f49Smrg fprintf(file, "# %d vertices\n", model->numvertices); 154632001f49Smrg for (i = 1; i <= model->numvertices; i++) { 154732001f49Smrg fprintf(file, "v %f %f %f\n", 154832001f49Smrg model->vertices[3 * i + 0], 154932001f49Smrg model->vertices[3 * i + 1], 155032001f49Smrg model->vertices[3 * i + 2]); 155132001f49Smrg } 155232001f49Smrg 155332001f49Smrg /* spit out the smooth/flat normals */ 155432001f49Smrg if (mode & GLM_SMOOTH) { 155532001f49Smrg fprintf(file, "\n"); 155632001f49Smrg fprintf(file, "# %d normals\n", model->numnormals); 155732001f49Smrg for (i = 1; i <= model->numnormals; i++) { 155832001f49Smrg fprintf(file, "vn %f %f %f\n", 155932001f49Smrg model->normals[3 * i + 0], 156032001f49Smrg model->normals[3 * i + 1], 156132001f49Smrg model->normals[3 * i + 2]); 156232001f49Smrg } 156332001f49Smrg } else if (mode & GLM_FLAT) { 156432001f49Smrg fprintf(file, "\n"); 156532001f49Smrg fprintf(file, "# %d normals\n", model->numfacetnorms); 156632001f49Smrg for (i = 1; i <= model->numnormals; i++) { 156732001f49Smrg fprintf(file, "vn %f %f %f\n", 156832001f49Smrg model->facetnorms[3 * i + 0], 156932001f49Smrg model->facetnorms[3 * i + 1], 157032001f49Smrg model->facetnorms[3 * i + 2]); 157132001f49Smrg } 157232001f49Smrg } 157332001f49Smrg 157432001f49Smrg /* spit out the texture coordinates */ 157532001f49Smrg if (mode & GLM_TEXTURE) { 157632001f49Smrg fprintf(file, "\n"); 157732001f49Smrg fprintf(file, "# %d texcoords\n", model->numtexcoords); 157832001f49Smrg for (i = 1; i <= model->numtexcoords; i++) { 157932001f49Smrg fprintf(file, "vt %f %f\n", 158032001f49Smrg model->texcoords[2 * i + 0], 158132001f49Smrg model->texcoords[2 * i + 1]); 158232001f49Smrg } 158332001f49Smrg } 158432001f49Smrg 158532001f49Smrg fprintf(file, "\n"); 158632001f49Smrg fprintf(file, "# %d groups\n", model->numgroups); 158732001f49Smrg fprintf(file, "# %d faces (triangles)\n", model->numtriangles); 158832001f49Smrg fprintf(file, "\n"); 158932001f49Smrg 159032001f49Smrg group = model->groups; 159132001f49Smrg while(group) { 159232001f49Smrg fprintf(file, "g %s\n", group->name); 159332001f49Smrg if (mode & GLM_MATERIAL) 159432001f49Smrg fprintf(file, "usemtl %s\n", model->materials[group->material].name); 159532001f49Smrg for (i = 0; i < group->numtriangles; i++) { 159632001f49Smrg if (mode & GLM_SMOOTH && mode & GLM_TEXTURE) { 159732001f49Smrg fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", 159832001f49Smrg T(group->triangles[i]).vindices[0], 159932001f49Smrg T(group->triangles[i]).nindices[0], 160032001f49Smrg T(group->triangles[i]).tindices[0], 160132001f49Smrg T(group->triangles[i]).vindices[1], 160232001f49Smrg T(group->triangles[i]).nindices[1], 160332001f49Smrg T(group->triangles[i]).tindices[1], 160432001f49Smrg T(group->triangles[i]).vindices[2], 160532001f49Smrg T(group->triangles[i]).nindices[2], 160632001f49Smrg T(group->triangles[i]).tindices[2]); 160732001f49Smrg } else if (mode & GLM_FLAT && mode & GLM_TEXTURE) { 160832001f49Smrg fprintf(file, "f %d/%d %d/%d %d/%d\n", 160932001f49Smrg T(group->triangles[i]).vindices[0], 161032001f49Smrg T(group->triangles[i]).findex, 161132001f49Smrg T(group->triangles[i]).vindices[1], 161232001f49Smrg T(group->triangles[i]).findex, 161332001f49Smrg T(group->triangles[i]).vindices[2], 161432001f49Smrg T(group->triangles[i]).findex); 161532001f49Smrg } else if (mode & GLM_TEXTURE) { 161632001f49Smrg fprintf(file, "f %d/%d %d/%d %d/%d\n", 161732001f49Smrg T(group->triangles[i]).vindices[0], 161832001f49Smrg T(group->triangles[i]).tindices[0], 161932001f49Smrg T(group->triangles[i]).vindices[1], 162032001f49Smrg T(group->triangles[i]).tindices[1], 162132001f49Smrg T(group->triangles[i]).vindices[2], 162232001f49Smrg T(group->triangles[i]).tindices[2]); 162332001f49Smrg } else if (mode & GLM_SMOOTH) { 162432001f49Smrg fprintf(file, "f %d//%d %d//%d %d//%d\n", 162532001f49Smrg T(group->triangles[i]).vindices[0], 162632001f49Smrg T(group->triangles[i]).nindices[0], 162732001f49Smrg T(group->triangles[i]).vindices[1], 162832001f49Smrg T(group->triangles[i]).nindices[1], 162932001f49Smrg T(group->triangles[i]).vindices[2], 163032001f49Smrg T(group->triangles[i]).nindices[2]); 163132001f49Smrg } else if (mode & GLM_FLAT) { 163232001f49Smrg fprintf(file, "f %d//%d %d//%d %d//%d\n", 163332001f49Smrg T(group->triangles[i]).vindices[0], 163432001f49Smrg T(group->triangles[i]).findex, 163532001f49Smrg T(group->triangles[i]).vindices[1], 163632001f49Smrg T(group->triangles[i]).findex, 163732001f49Smrg T(group->triangles[i]).vindices[2], 163832001f49Smrg T(group->triangles[i]).findex); 163932001f49Smrg } else { 164032001f49Smrg fprintf(file, "f %d %d %d\n", 164132001f49Smrg T(group->triangles[i]).vindices[0], 164232001f49Smrg T(group->triangles[i]).vindices[1], 164332001f49Smrg T(group->triangles[i]).vindices[2]); 164432001f49Smrg } 164532001f49Smrg } 164632001f49Smrg fprintf(file, "\n"); 164732001f49Smrg group = group->next; 164832001f49Smrg } 164932001f49Smrg 165032001f49Smrg fclose(file); 165132001f49Smrg} 165232001f49Smrg 165332001f49Smrg/* glmWeld: eliminate (weld) vectors that are within an epsilon of 165432001f49Smrg * each other. 165532001f49Smrg * 165632001f49Smrg * model - initialized GLMmodel structure 165732001f49Smrg * epsilon - maximum difference between vertices 165832001f49Smrg * ( 0.00001 is a good start for a unitized model) 165932001f49Smrg * 166032001f49Smrg */ 166132001f49Smrgvoid 166232001f49SmrgglmWeld(GLMmodel* model, float epsilon) 166332001f49Smrg{ 166432001f49Smrg float* vectors; 166532001f49Smrg float* copies; 166632001f49Smrg uint numvectors; 166732001f49Smrg uint i; 166832001f49Smrg 166932001f49Smrg /* vertices */ 167032001f49Smrg numvectors = model->numvertices; 167132001f49Smrg vectors = model->vertices; 167232001f49Smrg copies = _glmWeldVectors(vectors, &numvectors, epsilon); 167332001f49Smrg 167432001f49Smrg printf("glmWeld(): %d redundant vertices.\n", 167532001f49Smrg model->numvertices - numvectors - 1); 167632001f49Smrg 167732001f49Smrg for (i = 0; i < model->numtriangles; i++) { 167832001f49Smrg T(i).vindices[0] = (uint)vectors[3 * T(i).vindices[0] + 0]; 167932001f49Smrg T(i).vindices[1] = (uint)vectors[3 * T(i).vindices[1] + 0]; 168032001f49Smrg T(i).vindices[2] = (uint)vectors[3 * T(i).vindices[2] + 0]; 168132001f49Smrg } 168232001f49Smrg 168332001f49Smrg /* free space for old vertices */ 168432001f49Smrg free(vectors); 168532001f49Smrg 168632001f49Smrg /* allocate space for the new vertices */ 168732001f49Smrg model->numvertices = numvectors; 168832001f49Smrg model->vertices = (float*)malloc(sizeof(float) * 168932001f49Smrg 3 * (model->numvertices + 1)); 169032001f49Smrg 169132001f49Smrg /* copy the optimized vertices into the actual vertex list */ 169232001f49Smrg for (i = 1; i <= model->numvertices; i++) { 169332001f49Smrg model->vertices[3 * i + 0] = copies[3 * i + 0]; 169432001f49Smrg model->vertices[3 * i + 1] = copies[3 * i + 1]; 169532001f49Smrg model->vertices[3 * i + 2] = copies[3 * i + 2]; 169632001f49Smrg } 169732001f49Smrg 169832001f49Smrg free(copies); 169932001f49Smrg} 170032001f49Smrg 170132001f49Smrg 170232001f49Smrgvoid 170332001f49SmrgglmReIndex(GLMmodel *model) 170432001f49Smrg{ 170532001f49Smrg uint i, j, n; 170632001f49Smrg GLMgroup* group; 170732001f49Smrg float *newNormals = NULL; 170832001f49Smrg float *newTexcoords = NULL; 170932001f49Smrg const uint numv = model->numvertices; 171032001f49Smrg 171132001f49Smrg if (model->numnormals > 0) 171232001f49Smrg newNormals = (float *) malloc((numv + 1) * 3 * sizeof(float)); 171332001f49Smrg 171432001f49Smrg if (model->numtexcoords > 0) 171532001f49Smrg newTexcoords = (float *) malloc((numv + 1) * 2 * sizeof(float)); 171632001f49Smrg 171732001f49Smrg for (group = model->groups; group; group = group->next) { 171832001f49Smrg 171932001f49Smrg n = group->numtriangles; 172032001f49Smrg 172132001f49Smrg group->triIndexes = (uint *) malloc(n * 3 * sizeof(uint)); 172232001f49Smrg 172332001f49Smrg group->minIndex = 10000000; 172432001f49Smrg group->maxIndex = 0; 172532001f49Smrg 172632001f49Smrg for (i = 0; i < n; i++) { 172732001f49Smrg 172832001f49Smrg for (j = 0; j < 3; j++) { 172932001f49Smrg uint vindex = T(group->triangles[i]).vindices[j]; 173032001f49Smrg uint nindex = T(group->triangles[i]).nindices[j]; 173132001f49Smrg uint tindex = T(group->triangles[i]).tindices[j]; 173232001f49Smrg 173332001f49Smrg float *nrm = &model->normals[nindex * 3]; 173432001f49Smrg float *tex = &model->texcoords[tindex * 2]; 173532001f49Smrg 173632001f49Smrg if (newNormals) { 173732001f49Smrg assert(vindex * 3 + 2 < (numv + 1) * 3); 173832001f49Smrg newNormals[vindex * 3 + 0] = nrm[0]; 173932001f49Smrg newNormals[vindex * 3 + 1] = nrm[1]; 174032001f49Smrg newNormals[vindex * 3 + 2] = nrm[2]; 174132001f49Smrg } 174232001f49Smrg if (newTexcoords) { 174332001f49Smrg newTexcoords[vindex * 2 + 0] = tex[0]; 174432001f49Smrg newTexcoords[vindex * 2 + 1] = tex[1]; 174532001f49Smrg } 174632001f49Smrg 174732001f49Smrg T(group->triangles[i]).nindices[j] = vindex; 174832001f49Smrg T(group->triangles[i]).tindices[j] = vindex; 174932001f49Smrg 175032001f49Smrg group->triIndexes[i * 3 + j] = vindex; 175132001f49Smrg 175232001f49Smrg if (vindex > group->maxIndex) 175332001f49Smrg group->maxIndex = vindex; 175432001f49Smrg if (vindex < group->minIndex) 175532001f49Smrg group->minIndex = vindex; 175632001f49Smrg } 175732001f49Smrg } 175832001f49Smrg } 175932001f49Smrg 176032001f49Smrg if (newNormals) { 176132001f49Smrg free(model->normals); 176232001f49Smrg model->normals = newNormals; 176332001f49Smrg model->numnormals = model->numvertices; 176432001f49Smrg } 176532001f49Smrg 176632001f49Smrg if (newTexcoords) { 176732001f49Smrg free(model->texcoords); 176832001f49Smrg model->texcoords = newTexcoords; 176932001f49Smrg model->numtexcoords = model->numvertices; 177032001f49Smrg } 177132001f49Smrg} 177232001f49Smrg 177332001f49Smrg 177432001f49Smrg 177532001f49Smrgvoid 177632001f49SmrgglmPrint(const GLMmodel *model) 177732001f49Smrg{ 177832001f49Smrg uint i, j, grp, n; 177932001f49Smrg GLMgroup* group; 178032001f49Smrg uint totalTris = 0; 178132001f49Smrg 178232001f49Smrg grp = 0; 178332001f49Smrg 178432001f49Smrg printf("%u vertices\n", model->numvertices); 178532001f49Smrg printf("%u normals\n", model->numnormals); 178632001f49Smrg printf("%u texcoords\n", model->numtexcoords); 178732001f49Smrg 178832001f49Smrg for (group = model->groups; group; group = group->next, grp++) { 178932001f49Smrg printf("Group %u:\n", grp); 179032001f49Smrg printf(" Min index %u, max index %u\n", group->minIndex, group->maxIndex); 179132001f49Smrg 179232001f49Smrg#if 0 179332001f49Smrg if (mode & GLM_MATERIAL) { 179432001f49Smrg glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, 179532001f49Smrg model->materials[group->material].ambient); 179632001f49Smrg glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 179732001f49Smrg model->materials[group->material].diffuse); 179832001f49Smrg glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, 179932001f49Smrg model->materials[group->material].specular); 180032001f49Smrg glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 180132001f49Smrg model->materials[group->material].shininess); 180232001f49Smrg } 180332001f49Smrg 180432001f49Smrg if (mode & GLM_COLOR) { 180532001f49Smrg glColor3fv(model->materials[group->material].diffuse); 180632001f49Smrg } 180732001f49Smrg#endif 180832001f49Smrg totalTris += group->numtriangles; 180932001f49Smrg 181032001f49Smrg printf(" %u triangles\n", group->numtriangles); 181132001f49Smrg n = group->numtriangles; 181232001f49Smrg if (n > 10) 181332001f49Smrg n = 10; 181432001f49Smrg 181532001f49Smrg for (i = 0; i < n; i++) { 181632001f49Smrg 181732001f49Smrg printf(" %u: vert ", i); 181832001f49Smrg for (j = 0; j < 3; j++) { 181932001f49Smrg printf("%u ", T(group->triangles[i]).vindices[j]); 182032001f49Smrg } 182132001f49Smrg 182232001f49Smrg printf(" normal "); 182332001f49Smrg for (j = 0; j < 3; j++) { 182432001f49Smrg printf("%u ", T(group->triangles[i]).nindices[j]); 182532001f49Smrg } 182632001f49Smrg 182732001f49Smrg printf(" tex "); 182832001f49Smrg for (j = 0; j < 3; j++) { 182932001f49Smrg printf("%u ", T(group->triangles[i]).tindices[j]); 183032001f49Smrg } 183132001f49Smrg 183232001f49Smrg printf("\n"); 183332001f49Smrg } 183432001f49Smrg } 183532001f49Smrg printf("Total tris: %u\n", totalTris); 183632001f49Smrg} 183732001f49Smrg 183832001f49Smrg 183932001f49Smrg 184032001f49Smrg#if 0 184132001f49Smrg /* normals */ 184232001f49Smrg if (model->numnormals) { 184332001f49Smrg numvectors = model->numnormals; 184432001f49Smrg vectors = model->normals; 184532001f49Smrg copies = _glmOptimizeVectors(vectors, &numvectors); 184632001f49Smrg 184732001f49Smrg printf("glmOptimize(): %d redundant normals.\n", 184832001f49Smrg model->numnormals - numvectors); 184932001f49Smrg 185032001f49Smrg for (i = 0; i < model->numtriangles; i++) { 185132001f49Smrg T(i).nindices[0] = (uint)vectors[3 * T(i).nindices[0] + 0]; 185232001f49Smrg T(i).nindices[1] = (uint)vectors[3 * T(i).nindices[1] + 0]; 185332001f49Smrg T(i).nindices[2] = (uint)vectors[3 * T(i).nindices[2] + 0]; 185432001f49Smrg } 185532001f49Smrg 185632001f49Smrg /* free space for old normals */ 185732001f49Smrg free(vectors); 185832001f49Smrg 185932001f49Smrg /* allocate space for the new normals */ 186032001f49Smrg model->numnormals = numvectors; 186132001f49Smrg model->normals = (float*)malloc(sizeof(float) * 186232001f49Smrg 3 * (model->numnormals + 1)); 186332001f49Smrg 186432001f49Smrg /* copy the optimized vertices into the actual vertex list */ 186532001f49Smrg for (i = 1; i <= model->numnormals; i++) { 186632001f49Smrg model->normals[3 * i + 0] = copies[3 * i + 0]; 186732001f49Smrg model->normals[3 * i + 1] = copies[3 * i + 1]; 186832001f49Smrg model->normals[3 * i + 2] = copies[3 * i + 2]; 186932001f49Smrg } 187032001f49Smrg 187132001f49Smrg free(copies); 187232001f49Smrg } 187332001f49Smrg 187432001f49Smrg /* texcoords */ 187532001f49Smrg if (model->numtexcoords) { 187632001f49Smrg numvectors = model->numtexcoords; 187732001f49Smrg vectors = model->texcoords; 187832001f49Smrg copies = _glmOptimizeVectors(vectors, &numvectors); 187932001f49Smrg 188032001f49Smrg printf("glmOptimize(): %d redundant texcoords.\n", 188132001f49Smrg model->numtexcoords - numvectors); 188232001f49Smrg 188332001f49Smrg for (i = 0; i < model->numtriangles; i++) { 188432001f49Smrg for (j = 0; j < 3; j++) { 188532001f49Smrg T(i).tindices[j] = (uint)vectors[3 * T(i).tindices[j] + 0]; 188632001f49Smrg } 188732001f49Smrg } 188832001f49Smrg 188932001f49Smrg /* free space for old texcoords */ 189032001f49Smrg free(vectors); 189132001f49Smrg 189232001f49Smrg /* allocate space for the new texcoords */ 189332001f49Smrg model->numtexcoords = numvectors; 189432001f49Smrg model->texcoords = (float*)malloc(sizeof(float) * 189532001f49Smrg 2 * (model->numtexcoords + 1)); 189632001f49Smrg 189732001f49Smrg /* copy the optimized vertices into the actual vertex list */ 189832001f49Smrg for (i = 1; i <= model->numtexcoords; i++) { 189932001f49Smrg model->texcoords[2 * i + 0] = copies[2 * i + 0]; 190032001f49Smrg model->texcoords[2 * i + 1] = copies[2 * i + 1]; 190132001f49Smrg } 190232001f49Smrg 190332001f49Smrg free(copies); 190432001f49Smrg } 190532001f49Smrg#endif 190632001f49Smrg 190732001f49Smrg#if 0 190832001f49Smrg /* look for unused vertices */ 190932001f49Smrg /* look for unused normals */ 191032001f49Smrg /* look for unused texcoords */ 191132001f49Smrg for (i = 1; i <= model->numvertices; i++) { 191232001f49Smrg for (j = 0; j < model->numtriangles; i++) { 191332001f49Smrg if (T(j).vindices[0] == i || 191432001f49Smrg T(j).vindices[1] == i || 191532001f49Smrg T(j).vindices[1] == i) 191632001f49Smrg break; 191732001f49Smrg } 191832001f49Smrg } 191932001f49Smrg#endif 1920