📄 glm.c
字号:
/* * 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"/* 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 { GLuint index; GLboolean 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 GLfloat_glmMax(GLfloat a, GLfloat b) { if (a > b) return a; return b;}/* _glmAbs: returns the absolute value of a float */static GLfloat_glmAbs(GLfloat f){ if (f < 0) return -f; return f;}/* _glmDot: compute the dot product of two vectors * * u - array of 3 GLfloats (GLfloat u[3]) * v - array of 3 GLfloats (GLfloat v[3]) */static GLfloat_glmDot(GLfloat* u, GLfloat* 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 GLfloats (GLfloat u[3]) * v - array of 3 GLfloats (GLfloat v[3]) * n - array of 3 GLfloats (GLfloat n[3]) to return the cross product in */static GLvoid_glmCross(GLfloat* u, GLfloat* v, GLfloat* 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 GLfloats (GLfloat n[3]) to be normalized */static GLvoid_glmNormalize(GLfloat* n){ GLfloat l; assert(n); /* normalize */ l = (GLfloat)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 GL_TRUE if they are * equal (within a certain threshold) or GL_FALSE if not. An epsilon * that works fairly well is 0.000001. * * u - array of 3 GLfloats (GLfloat u[3]) * v - array of 3 GLfloats (GLfloat v[3]) */static GLboolean_glmEqual(GLfloat* u, GLfloat* v, GLfloat epsilon){ if (_glmAbs(u[0] - v[0]) < epsilon && _glmAbs(u[1] - v[1]) < epsilon && _glmAbs(u[2] - v[2]) < epsilon) { return GL_TRUE; } return GL_FALSE;}/* _glmWeldVectors: eliminate (weld) vectors that are within an * epsilon of each other. * * vectors - array of GLfloat[3]'s to be welded * numvectors - number of GLfloat[3]'s in vectors * epsilon - maximum difference between vectors * */GLfloat*_glmWeldVectors(GLfloat* vectors, GLuint* numvectors, GLfloat epsilon){ GLfloat* copies; GLuint copied; GLuint i, j; copies = (GLfloat*)malloc(sizeof(GLfloat) * 3 * (*numvectors + 1)); memcpy(copies, vectors, (sizeof(GLfloat) * 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] = (GLfloat)j; } *numvectors = copied-1; return copies;}/* _glmFindGroup: Find a group in the model */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 */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 */GLuint_glmFindMaterial(GLMmodel* model, char* name){ GLuint 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 GLvoid_glmReadMTL(GLMmodel* model, char* name){ FILE* file; char* dir; char* filename; char buf[128]; GLuint nummaterials, i; 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*)malloc(sizeof(GLMmaterial) * nummaterials); 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] = 1.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] = 1.0; } model->materials[0].name = stralloc("default"); /* now, read in the data */ nummaterials = 0; 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; 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; default: /* eat up rest of line */ fgets(buf, sizeof(buf), file); break; } }}/* _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 GLvoid_glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname){ FILE* file; char* dir; char* filename; GLMmaterial* material; GLuint 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"); }}/* _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 GLvoid_glmFirstPass(GLMmodel* model, FILE* file) { GLuint numvertices; /* number of vertices in model */ GLuint numnormals; /* number of normals in model */ GLuint numtexcoords; /* number of texcoords in model */ GLuint numtriangles; /* number of triangles in model */ GLMgroup* group; /* current group */ unsigned v, n, t;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -