PDA

View Full Version : [SOLVED] Help using glm and glut



snip3r8
July 15th, 2011, 09:42 PM
When using glm to load an obj file i get the following problem when compiling :

p, li { white-space: pre-wrap; } glm.cpp:291: undefined reference to `glmLoadTexture(char*, unsigned char, unsigned char, unsigned char, unsigned char, float*, float*)'




if i comment out the following line in glm.cpp


model->textures[model->numtextures-1].id = glmLoadTexture(filename, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE, &width, &height);


then the code compiles but the textures for the model dont load,does anyone know whats going on here?

Bachstelze
July 15th, 2011, 09:54 PM
Pretty self-explanatory: the linker can't find the function glmLoadTexture. Either you are not loading the necessary library, or the function does not exist in it.

snip3r8
July 15th, 2011, 09:58 PM
the function exist here



GLuint glmLoadTexture(char *filename, GLboolean alpha, GLboolean repeat, GLboolean filtering, GLboolean mipmaps, GLfloat *texcoordwidth, GLfloat *texcoordheight);



in fact heres the whole glm.cpp



/*
glm.c
Nate Robins, 1997, 2000
nate@pobox.com, http://www.pobox.com/~nate

Wavefront OBJ model file format reader/writer/manipulator.

Includes routines for generating smooth normals with
preservation of edges, welding redundant vertices & texture
coordinate generation (spheremap and planar projections) + more.

Improved version of GLM - 08.05.2008 Tudor Carean
Added support for textures and loading callbacks
*/

//#include <stdafx.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "glm.h"


//#define DebugVisibleSurfaces

#define total_textures 5

#define T(x) (model->triangles[(x)])
GLuint glmLoadTexture(char *filename, GLboolean alpha, GLboolean repeat, GLboolean filtering, GLboolean mipmaps, GLfloat *texcoordwidth, GLfloat *texcoordheight);

/* _GLMnode: general purpose node */
typedef struct _GLMnode {
GLuint index;
GLboolean averaged;
struct _GLMnode* next;
} GLMnode;


/* glmMax: returns the maximum of two floats */
static GLfloat
glmMax(GLfloat a, GLfloat b)
{
if (b > a)
return b;
return a;
}

/* 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])
*/
GLfloat glmDot(GLfloat* u, GLfloat* v)
{
assert(u); assert(v);

return u[0]*v[0] + u[1]*v[1] + u[2]*v[2];
}

/* 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);

n[0] = u[1]*v[2] - u[2]*v[1];
n[1] = u[2]*v[0] - u[0]*v[2];
n[2] = u[0]*v[1] - u[1]*v[0];
}

/* glmNormalize: normalize a vector
*
* v - array of 3 GLfloats (GLfloat v[3]) to be normalized
*/
static GLvoid
glmNormalize(GLfloat* v)
{
GLfloat l;

assert(v);

l = (GLfloat)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
v[0] /= l;
v[1] /= l;
v[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 = strdup(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;

/* XXX doing a linear search on a string key'd list is pretty lame,
but it works and is fast enough for now. */
for (i = 0; i < model->nummaterials; i++) {
if (!strcmp(model->materials[i].name, name))
goto found;
}

/* didn't find the name, so print a warning and return the default
material (0). */
printf("glmFindMaterial(): can't find material \"%s\".\n", name);
i = 0;

found:
return i;
}
/* glmDirName: return the directory given a path
*
* path - filesystem path
*
* NOTE: the return value should be free'd.
*/
static char*
glmDirName(char* path)
{
char* dir;
char* s;

dir = strdup(path);

s = strrchr(dir, '/');
if (s)
s[1] = '\0';
else
dir[0] = '\0';

return dir;
}

int glmFindOrAddTexture(GLMmodel* model, char* name,mycallback *call)
{
GLuint i;
char *dir, *filename;
float width, height;

char *numefis = name;
while (*numefis==' ') numefis++;

for (i = 0; i < model->numtextures; i++) {
if (!strcmp(model->textures[i].name, numefis))
return i;
}
char afis[180];
sprintf(afis,"Loading Textures (%s )...",name);

if (call)
{
int procent = ((float)((float)model->numtextures*30/total_textures)/100)*(call->end-call->start)+call->start;
call->loadcallback(procent,afis); // textures represent 30% from the model (just saying :))
}
if (strstr(name,":\\"))
{
filename = (char*)malloc(sizeof(char) * (strlen(name) + 1));
strcpy(filename,name);
}
else
{
dir = glmDirName(model->pathname);
filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(numefis) + 1));

strcpy(filename, dir);
//strcpy(filename, numefis);
strcat(filename, numefis);
free(dir);
}
int lung = strlen(filename);
if (filename[lung-1]<32) filename[lung-1]=0;
if (filename[lung-2]<32) filename[lung-2]=0;

model->numtextures++;
model->textures = (GLMtexture*)realloc(model->textures, sizeof(GLMtexture)*model->numtextures);
model->textures[model->numtextures-1].name = strdup(numefis);
model->textures[model->numtextures-1].id = glmLoadTexture(filename, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE, &width, &height);
model->textures[model->numtextures-1].width = width;
model->textures[model->numtextures-1].height = height;


free(filename);

return model->numtextures-1;
}




/* 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, mycallback *call)
{
FILE* file;
char* dir;
char* filename;
char* textura;
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);

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);

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 = 65.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[i].IDTextura = -1;
}
model->materials[0].name = strdup("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 = strdup(buf);
break;
case 'N':
if (buf[1]!='s') break; // 3DS pune 'i' aici pentru indici de refractie si se incurca
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;
case 'm':
// harta de texturi
filename = (char *)malloc(FILENAME_MAX);
fgets(filename, FILENAME_MAX, file);
textura = strdup(filename);
free(filename);
if(strncmp(buf, "map_Kd", 6) == 0)
{
char afis[180];
sprintf(afis,"Loading Textures (%s)...",textura);
//Divan edited code here ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
model->materials[nummaterials].IDTextura = glmFindOrAddTexture(model, textura,call);

free(textura);
} else {
//printf("map %s %s ignored",buf,t_filename);
free(textura);
//fgets(buf, sizeof(buf), file);
}
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\n");
fprintf(file, "# Nate Robins\n");
fprintf(file, "# ndr@pobox.com\n");
fprintf(file, "# 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 / 128.0 * 1000.0);
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, mycallback *call)
{
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;
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': //mtllib
fgets(buf, sizeof(buf), file);
sscanf(buf, "%s %s", buf, buf);
model->mtllibname = strdup(buf);
glmReadMTL(model, buf, call);
break;
case 'u': //usemtl
/* eat up rest of line */
fgets(buf, sizeof(buf), file);
break;
case 'g': /* group */
/* eat up rest of line */
fgets(buf, sizeof(buf), file);
#if SINGLE_STRING_GROUP_NAMES
sscanf(buf, "%s", buf);
#else
buf[strlen(buf)-1] = '\0'; /* nuke '\n' */
#endif
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, "%d//%d", &v, &n);
fscanf(file, "%d//%d", &v, &n);
fscanf(file, "%d//%d", &v, &n);
numtriangles++;
group->numtriangles++;
while(fscanf(file, "%d//%d", &v, &n) > 0) {
numtriangles++;
group->numtriangles++;
}
} else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) {
/* v/t/n */
fscanf(file, "%d/%d/%d", &v, &t, &n);
fscanf(file, "%d/%d/%d", &v, &t, &n);
numtriangles++;
group->numtriangles++;
while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) {
numtriangles++;
group->numtriangles++;
}
} else if (sscanf(buf, "%d/%d", &v, &t) == 2) {
/* v/t */
fscanf(file, "%d/%d", &v, &t);
fscanf(file, "%d/%d", &v, &t);
numtriangles++;
group->numtriangles++;
while(fscanf(file, "%d/%d", &v, &t) > 0) {
numtriangles++;
group->numtriangles++;
}
} else {
/* v */
fscanf(file, "%d", &v);
fscanf(file, "%d", &v);
numtriangles++;
group->numtriangles++;
while(fscanf(file, "%d", &v) > 0) {
numtriangles++;
group->numtriangles++;
}
}
break;

default:
/* eat up rest of line */
fgets(buf, sizeof(buf), file);
break;
}
}

/* 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 = (GLuint*)malloc(sizeof(GLuint) * 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 GLvoid glmSecondPass(GLMmodel* model, FILE* file, mycallback *call)
{
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 */
GLfloat* vertices; /* array of vertices */
GLfloat* normals; /* array of normals */
GLfloat* texcoords; /* array of texture coordinates */
GLMgroup* group; /* current group pointer */
GLuint material; /* current material */
GLuint v, n, t;
char buf[128];
char afis[80];

/* 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 + 0],
&vertices[3 * numvertices + 1],
&vertices[3 * numvertices + 2]);
numvertices++;
if (numvertices%200==0)
if (call)
{
sprintf(afis,"%s (%s )... ",call->text, group->name);
int procent = ((float)((float)numvertices*70/model->numvertices+30)/100)*(call->end-call->start)+call->start;
call->loadcallback(procent,afis); // Modelul e 70% din incarcare
}
break;
case 'n': /* normal */
fscanf(file, "%f %f %f",
&normals[3 * numnormals + 0],
&normals[3 * numnormals + 1],
&normals[3 * numnormals + 2]);
numnormals++;
break;
case 't': /* texcoord */
fscanf(file, "%f %f",
&texcoords[2 * numtexcoords + 0],
&texcoords[2 * numtexcoords + 1]);
numtexcoords++;
break;
}
break;
case 'u':
fgets(buf, sizeof(buf), file);
sscanf(buf, "%s %s", buf, buf);
group->material = material = glmFindMaterial(model, buf);
break;
case 'g': /* group */
/* eat up rest of line */
fgets(buf, sizeof(buf), file);
#if SINGLE_STRING_GROUP_NAMES
sscanf(buf, "%s", buf);
#else
buf[strlen(buf)-1] = '\0'; /* nuke '\n' */
#endif
group = glmFindGroup(model, buf);
group->material = material;
break;
case 'f': /* face */
v = n = t = 0;
T(numtriangles).findex = -1; // ???
T(numtriangles).vecini[0]=-1;
T(numtriangles).vecini[1]=-1;
T(numtriangles).vecini[2]=-1;
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, "%d//%d", &v, &n);
T(numtriangles).vindices[0] = v;
if (n== 181228)
{
printf("");
}
T(numtriangles).nindices[0] = n;
fscanf(file, "%d//%d", &v, &n);
T(numtriangles).vindices[1] = v;
T(numtriangles).nindices[1] = n;
fscanf(file, "%d//%d", &v, &n);
T(numtriangles).vindices[2] = v;
T(numtriangles).nindices[2] = n;
group->triangles[group->numtriangles++] = numtriangles;
numtriangles++;
while(fscanf(file, "%d//%d", &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, "%d/%d/%d", &v, &t, &n) == 3) {
/* v/t/n */

T(numtriangles).vindices[0] = v;
T(numtriangles).tindices[0] = t;
T(numtriangles).nindices[0] = n;
fscanf(file, "%d/%d/%d", &v, &t, &n);
T(numtriangles).vindices[1] = v;
T(numtriangles).tindices[1] = t;
T(numtriangles).nindices[1] = n;
fscanf(file, "%d/%d/%d", &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, "%d/%d/%d", &v, &t, &n) > 0) {
if (n== 181228)
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, "%d/%d", &v, &t) == 2) {
/* v/t */
T(numtriangles).vindices[0] = v;
T(numtriangles).tindices[0] = t;
fscanf(file, "%d/%d", &v, &t);
T(numtriangles).vindices[1] = v;
T(numtriangles).tindices[1] = t;
fscanf(file, "%d/%d", &v, &t);
T(numtriangles).vindices[2] = v;
T(numtriangles).tindices[2] = t;
group->triangles[group->numtriangles++] = numtriangles;
numtriangles++;
while(fscanf(file, "%d/%d", &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 */
//if (n== 181228)
sscanf(buf, "%d", &v);
T(numtriangles).vindices[0] = v;
fscanf(file, "%d", &v);
T(numtriangles).vindices[1] = v;
fscanf(file, "%d", &v);
T(numtriangles).vindices[2] = v;
group->triangles[group->numtriangles++] = numtriangles;
numtriangles++;
while(fscanf(file, "%d", &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(GLfloat) +
numnormals * 3*sizeof(GLfloat) * (numnormals ? 1 : 0) +
numtexcoords * 3*sizeof(GLfloat) * (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
*/
GLfloat
glmUnitize(GLMmodel* model)
{
GLuint i;
GLfloat maxx, minx, maxy, miny, maxz, minz;
GLfloat cx, cy, cz, w, h, d;
GLfloat scale;

assert(model);
assert(model->vertices);

/* get the max/mins */
maxx = minx = model->vertices[3 + 0];
maxy = miny = model->vertices[3 + 1];
maxz = minz = model->vertices[3 + 2];
for (i = 1; i <= model->numvertices; i++) {
if (maxx < model->vertices[3 * i + 0])
maxx = model->vertices[3 * i + 0];
if (minx > model->vertices[3 * i + 0])
minx = model->vertices[3 * i + 0];

if (maxy < model->vertices[3 * i + 1])
maxy = model->vertices[3 * i + 1];
if (miny > model->vertices[3 * i + 1])
miny = model->vertices[3 * i + 1];

if (maxz < model->vertices[3 * i + 2])
maxz = model->vertices[3 * i + 2];
if (minz > model->vertices[3 * i + 2])
minz = model->vertices[3 * i + 2];
}

/* 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 + 0] -= cx;
model->vertices[3 * i + 1] -= cy;
model->vertices[3 * i + 2] -= cz;
model->vertices[3 * i + 0] *= scale;
model->vertices[3 * i + 1] *= scale;
model->vertices[3 * i + 2] *= scale;
}

return scale;
}

/* glmDimensions: Calculates the dimensions (width, height, depth) of
* a model.
*
* model - initialized GLMmodel structure
* dimensions - array of 3 GLfloats (GLfloat dimensions[3])
*/
GLvoid
glmDimensions(GLMmodel* model, GLfloat* dimensions)
{
GLuint i;
GLfloat maxx, minx, maxy, miny, maxz, minz;

assert(model);
assert(model->vertices);
assert(dimensions);

/* get the max/mins */
maxx = minx = model->vertices[3 + 0];
maxy = miny = model->vertices[3 + 1];
maxz = minz = model->vertices[3 + 2];
for (i = 1; i <= model->numvertices; i++) {
if (maxx < model->vertices[3 * i + 0])
maxx = model->vertices[3 * i + 0];
if (minx > model->vertices[3 * i + 0])
minx = model->vertices[3 * i + 0];

if (maxy < model->vertices[3 * i + 1])
maxy = model->vertices[3 * i + 1];
if (miny > model->vertices[3 * i + 1])
miny = model->vertices[3 * i + 1];

if (maxz < model->vertices[3 * i + 2])
maxz = model->vertices[3 * i + 2];
if (minz > model->vertices[3 * i + 2])
minz = model->vertices[3 * i + 2];
}

/* calculate model width, height, and depth */
dimensions[0] = glmAbs(maxx) + glmAbs(minx);
dimensions[1] = glmAbs(maxy) + glmAbs(miny);
dimensions[2] = 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)
*/
GLvoid
glmScale(GLMmodel* model, GLfloat scale)
{
GLuint i;

for (i = 1; i <= model->numvertices; i++) {
model->vertices[3 * i + 0] *= scale;
model->vertices[3 * i + 1] *= scale;
model->vertices[3 * i + 2] *= 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
*/
GLvoid
glmReverseWinding(GLMmodel* model)
{
GLuint 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 + 0] = -model->facetnorms[3 * i + 0];
model->facetnorms[3 * i + 1] = -model->facetnorms[3 * i + 1];
model->facetnorms[3 * i + 2] = -model->facetnorms[3 * i + 2];
}

/* reverse vertex normals */
for (i = 1; i <= model->numnormals; i++) {
model->normals[3 * i + 0] = -model->normals[3 * i + 0];
model->normals[3 * i + 1] = -model->normals[3 * i + 1];
model->normals[3 * i + 2] = -model->normals[3 * i + 2];
}
}

/* 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
*/
GLvoid
glmFacetNormals(GLMmodel* model)
{
GLuint i;
GLfloat u[3];
GLfloat 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 = (GLfloat*)malloc(sizeof(GLfloat) *
3 * (model->numfacetnorms + 1));

for (i = 0; i < model->numtriangles; i++)
{
model->triangles[i].findex = i+1;

u[0] = model->vertices[3 * T(i).vindices[1] + 0] -
model->vertices[3 * T(i).vindices[0] + 0];
u[1] = model->vertices[3 * T(i).vindices[1] + 1] -
model->vertices[3 * T(i).vindices[0] + 1];
u[2] = model->vertices[3 * T(i).vindices[1] + 2] -
model->vertices[3 * T(i).vindices[0] + 2];

v[0] = model->vertices[3 * T(i).vindices[2] + 0] -
model->vertices[3 * T(i).vindices[0] + 0];
v[1] = model->vertices[3 * T(i).vindices[2] + 1] -
model->vertices[3 * T(i).vindices[0] + 1];
v[2] = model->vertices[3 * T(i).vindices[2] + 2] -
model->vertices[3 * T(i).vindices[0] + 2];

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 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
*/
GLvoid
glmVertexNormals(GLMmodel* model, GLfloat angle)
{
GLMnode* node;
GLMnode* tail;
GLMnode** members;
GLfloat* normals;
GLuint numnormals;
GLfloat average[3];
GLfloat dot, cos_angle;
GLuint 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 = (GLfloat*)malloc(sizeof(GLfloat)* 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 = GL_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 = GL_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->index==204543)
{
printf("");
}
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 = (GLfloat*)malloc(sizeof(GLfloat)* 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);
}

GLvoid
glmLinearTexture(GLMmodel* model)
{
GLMgroup *group;
GLfloat dimensions[3];
GLfloat x, y, scalefactor;
GLuint i;

assert(model);

if (model->texcoords)
free(model->texcoords);
model->numtexcoords = model->numvertices;
model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(mode l->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
*/
GLvoid
glmSpheremapTexture(GLMmodel* model)
{
GLMgroup* group;
GLfloat theta, phi, rho, x, y, z, r;
GLuint i;

assert(model);
assert(model->normals);

if (model->texcoords)
free(model->texcoords);
model->numtexcoords = model->numnormals;
model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(mode l->numtexcoords+1));

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 = 3.14159265 / 2.0;
else
phi = acos(z / rho);

if(y == 0.0)
theta = 3.141592365 / 2.0;
else
theta = asin(y / r) + (3.14159265 / 2.0);
}

model->texcoords[2 * i + 0] = theta / 3.14159265;
model->texcoords[2 * i + 1] = phi / 3.14159265;
}

/* 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;
}
}

/* glmDelete: Deletes a GLMmodel structure.
*
* model - initialized GLMmodel structure
*/
GLvoid
glmDelete(GLMmodel* model)
{
GLMgroup* group;
GLuint 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);
}
if (model->textures) {
for (i = 0; i < model->numtextures; i++) {
free(model->textures[i].name);
glDeleteTextures(1,&model->textures[i].id);
}
free(model->textures);
}

while(model->groups) {
group = model->groups;
model->groups = model->groups->next;
free(group->name);
free(group->triangles);
free(group);
}

free(model);
}

/* 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)
{
return glmReadOBJ(filename,0);
}
GLMmodel* glmReadOBJ(char* filename,mycallback *call)
{
GLMmodel* model;
FILE* file;
//if (call) call->loadcallback(0,"Loading Models...");
/* open the file */
file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "glmReadOBJ() failed: can't open data file \"%s\".\n",
filename);
exit(1);
}

/* allocate a new model */
model = (GLMmodel*)malloc(sizeof(GLMmodel));
model->pathname = strdup(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->numtextures = 0;
model->textures = NULL;
model->numgroups = 0;
model->groups = NULL;
model->position[0] = 0.0;
model->position[1] = 0.0;
model->position[2] = 0.0;

/* make a first pass through the file to get a count of the number
of vertices, normals, texcoords & triangles */
glmFirstPass(model, file, call);

/* allocate memory */
model->vertices = (GLfloat*)malloc(sizeof(GLfloat) *
3 * (model->numvertices + 1));
model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) *
model->numtriangles);
if (model->numnormals) {
model->normals = (GLfloat*)malloc(sizeof(GLfloat) *
3 * (model->numnormals + 1));
}
if (model->numtexcoords) {
model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) *
2 * (model->numtexcoords + 1));
}

/* rewind to beginning of file and read in the data this pass */
rewind(file);

glmSecondPass(model, file,call);

/* close the file */
fclose(file);

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.
*/
GLvoid
glmWriteOBJ(GLMmodel* model, char* filename, GLuint mode)
{
GLuint 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;
}
if (mode & GLM_COLOR && !model->materials) {
printf("glmWriteOBJ() warning: color output requested "
"with no colors (materials) defined.\n");
mode &= ~GLM_COLOR;
}
if (mode & GLM_MATERIAL && !model->materials) {
printf("glmWriteOBJ() warning: material output requested "
"with no materials defined.\n");
mode &= ~GLM_MATERIAL;
}
if (mode & GLM_COLOR && mode & GLM_MATERIAL) {
printf("glmWriteOBJ() warning: color and material output requested "
"outputting only materials.\n");
mode &= ~GLM_COLOR;
}


/* 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\n");
fprintf(file, "# Nate Robins\n");
fprintf(file, "# ndr@pobox.com\n");
fprintf(file, "# 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->texcoords);
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);
}

/* glmDraw: Renders the model to the current OpenGL context using the
* mode specified.
*
* model - initialized GLMmodel structure
* mode - a bitwise OR of values describing what is to be rendered.
* 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.
*/

GLvoid glmDraw(GLMmodel* model, GLuint mode)
{
glmDraw(model,mode,0);
}
GLvoid glmDraw(GLMmodel* model, GLuint mode,char *drawonly)
{
static GLuint i;
static GLMgroup* group;
static GLMtriangle* triangle;
static GLMmaterial* material;
GLuint IDTextura;

assert(model);
assert(model->vertices);

/* do a bit of warning */
if (mode & GLM_FLAT && !model->facetnorms) {
printf("glmDraw() warning: flat render mode requested "
"with no facet normals defined.\n");
mode &= ~GLM_FLAT;
}
if (mode & GLM_SMOOTH && !model->normals) {
printf("glmDraw() warning: smooth render mode requested "
"with no normals defined.\n");
mode &= ~GLM_SMOOTH;
}
if (mode & GLM_TEXTURE && !model->texcoords) {
printf("glmDraw() warning: texture render mode requested "
"with no texture coordinates defined.\n");
mode &= ~GLM_TEXTURE;
}
if (mode & GLM_FLAT && mode & GLM_SMOOTH) {
printf("glmDraw() warning: flat render mode requested "
"and smooth render mode requested (using smooth).\n");
mode &= ~GLM_FLAT;
}
if (mode & GLM_COLOR && !model->materials) {
printf("glmDraw() warning: color render mode requested "
"with no materials defined.\n");
mode &= ~GLM_COLOR;
}
if (mode & GLM_MATERIAL && !model->materials) {
printf("glmDraw() warning: material render mode requested "
"with no materials defined.\n");
mode &= ~GLM_MATERIAL;
}
if (mode & GLM_COLOR && mode & GLM_MATERIAL) {
printf("glmDraw() warning: color and material render mode requested "
"using only material mode.\n");
mode &= ~GLM_COLOR;
}
if (mode & GLM_COLOR)
glEnable(GL_COLOR_MATERIAL);
else if (mode & GLM_MATERIAL)
glDisable(GL_COLOR_MATERIAL);
if (mode & GLM_TEXTURE) {
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
/* perhaps this loop should be unrolled into material, color, flat,
smooth, etc. loops? since most cpu's have good branch prediction
schemes (and these branches will always go one way), probably
wouldn't gain too much? */

IDTextura = -1;
group = model->groups;
while (group)
{
if (drawonly)
if (strcmp(group->name,drawonly))
{
group=group->next;
continue;
}

material = &model->materials[group->material];
if (material)
IDTextura = material->IDTextura;
else IDTextura=-1;

if (mode & GLM_MATERIAL)
{
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material->specular);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material->shininess);
}

if (mode & GLM_TEXTURE)
{
if(IDTextura == -1)
glBindTexture(GL_TEXTURE_2D, 0);
else
glBindTexture(GL_TEXTURE_2D, model->textures[IDTextura].id);
}

if (mode & GLM_COLOR) {
glColor3fv(material->diffuse);
}

glBegin(GL_TRIANGLES);
for (i = 0; i < group->numtriangles; i++) {
triangle = &T(group->triangles[i]);
#ifdef DebugVisibleSurfaces
if (!triangle->visible) continue;
#endif
if (mode & GLM_FLAT)
glNormal3fv(&model->facetnorms[3 * triangle->findex]);

if (mode & GLM_SMOOTH)
glNormal3fv(&model->normals[3 * triangle->nindices[0]]);
if (mode & GLM_TEXTURE)
glTexCoord2fv(&model->texcoords[2 * triangle->tindices[0]]);
glVertex3fv(&model->vertices[3 * triangle->vindices[0]]);

if (mode & GLM_SMOOTH)
glNormal3fv(&model->normals[3 * triangle->nindices[1]]);
if (mode & GLM_TEXTURE)
{
//if (IDTextura==-1) printf("Warning: GLM_TEXTURE este on dar nu este setata nici o textura in material!");
glTexCoord2fv(&model->texcoords[2 * triangle->tindices[1]]);
}
glVertex3fv(&model->vertices[3 * triangle->vindices[1]]);

if (mode & GLM_SMOOTH)
glNormal3fv(&model->normals[3 * triangle->nindices[2]]);
if (mode & GLM_TEXTURE)
glTexCoord2fv(&model->texcoords[2 * triangle->tindices[2]]);
glVertex3fv(&model->vertices[3 * triangle->vindices[2]]);

}
glEnd();

group = group->next;
}
}

/* glmList: Generates and returns a display list for the model using
* the mode specified.
*
* model - initialized GLMmodel structure
* mode - a bitwise OR of values describing what is to be rendered.
* 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.
*/
GLuint
glmList(GLMmodel* model, GLuint mode)
{
GLuint list;

list = glGenLists(1);
glNewList(list, GL_COMPILE);
glmDraw(model, mode);
glEndList();

return list;
}

/* 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)
*
*/
GLvoid
glmWeld(GLMmodel* model, GLfloat epsilon)
{
GLfloat* vectors;
GLfloat* copies;
GLuint numvectors;
GLuint i;

/* vertices */
numvectors = model->numvertices;
vectors = model->vertices;
copies = glmWeldVectors(vectors, &numvectors, epsilon);

#if 0
printf("glmWeld(): %d redundant vertices.\n",
model->numvertices - numvectors - 1);
#endif

for (i = 0; i < model->numtriangles; i++) {
T(i).vindices[0] = (GLuint)vectors[3 * T(i).vindices[0] + 0];
T(i).vindices[1] = (GLuint)vectors[3 * T(i).vindices[1] + 0];
T(i).vindices[2] = (GLuint)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 = (GLfloat*)malloc(sizeof(GLfloat) *
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);
}

/* glmReadPPM: read a PPM raw (type P6) file. The PPM file has a header
* that should look something like:
*
* P6
* # comment
* width height max_value
* rgbrgbrgb...
*
* where "P6" is the magic cookie which identifies the file type and
* should be the only characters on the first line followed by a
* carriage return. Any line starting with a # mark will be treated
* as a comment and discarded. After the magic cookie, three integer
* values are expected: width, height of the image and the maximum
* value for a pixel (max_value must be < 256 for PPM raw files). The
* data section consists of width*height rgb triplets (one byte each)
* in binary format (i.e., such as that written with fwrite() or
* equivalent).
*
* The rgb data is returned as an array of unsigned chars (packed
* rgb). The malloc()'d memory should be free()'d by the caller. If
* an error occurs, an error message is sent to stderr and NULL is
* returned.
*
* filename - name of the .ppm file.
* width - will contain the width of the image on return.
* height - will contain the height of the image on return.
*
*/
GLubyte*
glmReadPPM(char* filename, int* width, int* height)
{
FILE* fp;
int i, w, h, d;
unsigned char* image;
char head[70]; /* max line <= 70 in PPM (per spec). */

fp = fopen(filename, "rb");
if (!fp) {
perror(filename);
return NULL;
}

/* grab first two chars of the file and make sure that it has the
correct magic cookie for a raw PPM file. */
fgets(head, 70, fp);
if (strncmp(head, "P6", 2)) {
fprintf(stderr, "%s: Not a raw PPM file\n", filename);
return NULL;
}

/* grab the three elements in the header (width, height, maxval). */
i = 0;
while(i < 3) {
fgets(head, 70, fp);
if (head[0] == '#') /* skip comments. */
continue;
if (i == 0)
i += sscanf(head, "%d %d %d", &w, &h, &d);
else if (i == 1)
i += sscanf(head, "%d %d", &h, &d);
else if (i == 2)
i += sscanf(head, "%d", &d);
}

/* grab all the image data in one fell swoop. */
image = (unsigned char*)malloc(sizeof(unsigned char)*w*h*3);
fread(image, sizeof(unsigned char), w*h*3, fp);
fclose(fp);

*width = w;
*height = h;
return image;
}

#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] = (GLuint)vectors[3 * T(i).nindices[0] + 0];
T(i).nindices[1] = (GLuint)vectors[3 * T(i).nindices[1] + 0];
T(i).nindices[2] = (GLuint)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 = (GLfloat*)malloc(sizeof(GLfloat) *
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] = (GLuint)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 = (GLfloat*)malloc(sizeof(GLfloat) *
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

Bachstelze
July 15th, 2011, 10:11 PM
It expects a GLfloat*, but you're giving it a float*. Not sure whether that's the problem, though, as I don't know C++. (But if it were, it would mean C++ is more strongly typed than C...)

Try casting your pointers like this:


model->textures[model->numtextures-1].id = glmLoadTexture(filename, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE, (GLfloat*) &width, (GLfloat*) &height);

snip3r8
July 15th, 2011, 10:17 PM
Unfortunately that didn't work

Bachstelze
July 15th, 2011, 10:23 PM
Can you please paste glm.h so that I can try to compile it? Also the comment at the top of the file says glm.c, and the file use C-stye headers. Why are you compiling it as glm.cpp?

snip3r8
July 15th, 2011, 11:04 PM
here's glm.h



/*
glm.h
Nate Robins, 1997, 2000
nate@pobox.com, http://www.pobox.com/~nate

Wavefront OBJ model file format reader/writer/manipulator.

Includes routines for generating smooth normals with
preservation of edges, welding redundant vertices & texture
coordinate generation (spheremap and planar projections) + more.

Improved version:
Tudor Carean - April 2008 - added texture support

*/


#include <GL/glut.h>


#ifndef M_PI
#define M_PI 3.14159265f
#endif

#define GLM_NONE (0) /* render with only vertices */
#define GLM_FLAT (1 << 0) /* render with facet normals */
#define GLM_SMOOTH (1 << 1) /* render with vertex normals */
#define GLM_TEXTURE (1 << 2) /* render with texture coords */
#define GLM_COLOR (1 << 3) /* render with colors */
#define GLM_MATERIAL (1 << 4) /* render with materials */


/* GLMmaterial: Structure that defines a material in a model.
*/
typedef struct _GLMmaterial
{
char* name; /* name of material */
GLfloat diffuse[4]; /* diffuse component */
GLfloat ambient[4]; /* ambient component */
GLfloat specular[4]; /* specular component */
GLfloat emmissive[4]; /* emmissive component */
GLfloat shininess; /* specular exponent */
//this is for textures
GLuint IDTextura; // ID-ul texturii difuze
} GLMmaterial;

/* GLMtriangle: Structure that defines a triangle in a model.
*/
typedef struct _GLMtriangle {
GLuint vindices[3]; /* array of triangle vertex indices */
GLuint nindices[3]; /* array of triangle normal indices */
GLuint tindices[3]; /* array of triangle texcoord indices*/
GLuint findex; /* index of triangle facet normal */
//GLuint nrvecini;
GLuint vecini[3];
bool visible;
} GLMtriangle;

//adaugat pentru suport texturi
typedef struct _GLMtexture {
char *name;
GLuint id; /* ID-ul texturii */
GLfloat width; /* width and height for texture coordinates */
GLfloat height;
} GLMtexture;

/* GLMgroup: Structure that defines a group in a model.
*/
typedef struct _GLMgroup {
char* name; /* name of this group */
GLuint numtriangles; /* number of triangles in this group */
GLuint* triangles; /* array of triangle indices */
GLuint material; /* index to material for group */
struct _GLMgroup* next; /* pointer to next group in model */
} GLMgroup;

/* GLMmodel: Structure that defines a model.
*/
typedef struct _GLMmodel {
char* pathname; /* path to this model */
char* mtllibname; /* name of the material library */

GLuint numvertices; /* number of vertices in model */
GLfloat* vertices; /* array of vertices */

GLuint numnormals; /* number of normals in model */
GLfloat* normals; /* array of normals */

GLuint numtexcoords; /* number of texcoords in model */
GLfloat* texcoords; /* array of texture coordinates */

GLuint numfacetnorms; /* number of facetnorms in model */
GLfloat* facetnorms; /* array of facetnorms */

GLuint numtriangles; /* number of triangles in model */
GLMtriangle* triangles; /* array of triangles */

GLuint nummaterials; /* number of materials in model */
GLMmaterial* materials; /* array of materials */

GLuint numgroups; /* number of groups in model */
GLMgroup* groups; /* linked list of groups */

// textures
GLuint numtextures;
GLMtexture* textures;

GLfloat position[3]; /* position of the model */

} GLMmodel;

struct mycallback
{
void (*loadcallback)(int,char *);
int start;
int end;
char *text;
};

GLvoid glmDraw(GLMmodel* model, GLuint mode,char *drawonly);

GLfloat glmDot(GLfloat* u, GLfloat* v);

/* 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
*/
GLfloat
glmUnitize(GLMmodel* model);

/* glmDimensions: Calculates the dimensions (width, height, depth) of
* a model.
*
* model - initialized GLMmodel structure
* dimensions - array of 3 GLfloats (GLfloat dimensions[3])
*/
GLvoid
glmDimensions(GLMmodel* model, GLfloat* dimensions);

/* 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)
*/
GLvoid
glmScale(GLMmodel* model, GLfloat 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
*/
GLvoid
glmReverseWinding(GLMmodel* model);

/* 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
*/
GLvoid
glmFacetNormals(GLMmodel* model);

/* 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 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
*/
GLvoid
glmVertexNormals(GLMmodel* model, GLfloat angle);

/* 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
*/
GLvoid
glmLinearTexture(GLMmodel* model);

/* 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
*/
GLvoid
glmSpheremapTexture(GLMmodel* model);

/* glmDelete: Deletes a GLMmodel structure.
*
* model - initialized GLMmodel structure
*/
GLvoid
glmDelete(GLMmodel* model);

/* 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* glmReadOBJ(char* filename);
GLMmodel* glmReadOBJ(char* filename,mycallback *call);

/* 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 - write only vertices
* GLM_FLAT - write facet normals
* GLM_SMOOTH - write vertex normals
* GLM_TEXTURE - write texture coords
* GLM_FLAT and GLM_SMOOTH should not both be specified.
*/
GLvoid
glmWriteOBJ(GLMmodel* model, char* filename, GLuint mode);

/* glmDraw: Renders the model to the current OpenGL context using the
* mode specified.
*
* model - initialized GLMmodel structure
* mode - a bitwise OR of values describing what is to be rendered.
* 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_FLAT and GLM_SMOOTH should not both be specified.
*/
GLvoid
glmDraw(GLMmodel* model, GLuint mode);

/* glmList: Generates and returns a display list for the model using
* the mode specified.
*
* model - initialized GLMmodel structure
* mode - a bitwise OR of values describing what is to be rendered.
* 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_FLAT and GLM_SMOOTH should not both be specified.
*/
GLuint
glmList(GLMmodel* model, GLuint mode);

/* 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)
*
*/
GLvoid
glmWeld(GLMmodel* model, GLfloat epsilon);

/* glmReadPPM: read a PPM raw (type P6) file. The PPM file has a header
* that should look something like:
*
* P6
* # comment
* width height max_value
* rgbrgbrgb...
*
* where "P6" is the magic cookie which identifies the file type and
* should be the only characters on the first line followed by a
* carriage return. Any line starting with a # mark will be treated
* as a comment and discarded. After the magic cookie, three integer
* values are expected: width, height of the image and the maximum
* value for a pixel (max_value must be < 256 for PPM raw files). The
* data section consists of width*height rgb triplets (one byte each)
* in binary format (i.e., such as that written with fwrite() or
* equivalent).
*
* The rgb data is returned as an array of unsigned chars (packed
* rgb). The malloc()'d memory should be free()'d by the caller. If
* an error occurs, an error message is sent to stderr and NULL is
* returned.
*
* filename - name of the .ppm file.
* width - will contain the width of the image on return.
* height - will contain the height of the image on return.
*
*/
GLubyte*
glmReadPPM(char* filename, int* width, int* height);

GLMgroup*
glmFindGroup(GLMmodel* model, char* name);



here is my nehegl_glut.cpp:



/***********************************************
* *
* Bruce's GLUT OpenGL Basecode *
* Specially made for Nehe's Gamedev Website *
* http://nehe.gamedev.net *
* April 2003 *
* *
************************************************
* Project Information:
*
* Base Author: Bruce "Sinner" Barrera
* E-mail: sinner@opengl.com.br
* Date : around April 2003 :-)
* Glut Version: 3.7.6
*
* Very special thanks to all people who
* contributed with any online tutors or
* help files. Keep coding!
*
* Edit Author: Divan Visagie
***********************************************/

#include <wchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <GL/glut.h>

#include <vector>
#include "frames.h"
#include "tga.h"
#include "primatives.h"
#include "glm.h"

#ifdef USESLEEP
#include <unistd.h>
#endif

#define ONE_SECOND 1 // one second
#define MAX_TEXTURES 5 // max textures displayed
using namespace std;
/* creates a enum type for mouse buttons */
enum {
BUTTON_LEFT = 0,
BUTTON_RIGHT,
BUTTON_LEFT_TRANSLATE,
};

/* set global variables */
int mButton = -1;
int mOldY, mOldX;

bool fullscreen = false;
bool rotate = false;
bool lighting = true;
bool showHud = true;
bool clearBuffer = true;
bool showDebugInfo = true;
bool consoleOpen = true;

/*Lighting settings*/
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f };

Primatives *prim = new Primatives();


/* vectors that makes the rotation and translation of the cube */
float eye[3] = {0.0f, 0.0f, 7.0f};
float rot[3] = {0.0f, 0.0f, 0.0f};

const int ESC = 27;

int wireframe = 0;

/* windows size and position constants */
const int GL_WIN_WIDTH = 800;
const int GL_WIN_HEIGHT = 600;
const int GL_WIN_INITIAL_X = 0;
const int GL_WIN_INITIAL_Y = 0;

/* array to hold texture handles */
GLuint g_TexturesArray[MAX_TEXTURES];

//glm stuff
GLMmodel* pmodel1 = NULL;

void drawmodel_box(void)
{
// Load the model only if it hasn't been loaded before
// If it's been loaded then pmodel1 should be a pointer to the model geometry data...otherwise it's null
if (!pmodel1)
{
// this is the call that actualy reads the OBJ and creates the model object
pmodel1 = glmReadOBJ("blend.obj");

if (!pmodel1) exit(0);
// This will rescale the object to fit into the unity matrix
// Depending on your project you might want to keep the original size and positions you had in 3DS Max or GMAX so you may have to comment this.
glmUnitize(pmodel1);
// These 2 functions calculate triangle and vertex normals from the geometry data.
// To be honest I had some problem with very complex models that didn't look to good because of how vertex normals were calculated
// So if you can export these directly from you modeling tool do it and comment these line
// 3DS Max can calculate these for you and GLM is perfectly capable of loading them
glmFacetNormals(pmodel1);
glmVertexNormals(pmodel1, 90.0);
}
// This is the call that will actualy draw the model
// Don't forget to tell it if you want textures or not :))
glmDraw(pmodel1, GLM_SMOOTH | GLM_TEXTURE | GLM_MATERIAL);

}

void toggleLighting()
{
if(lighting){
glDisable(GL_LIGHTING);
lighting = false;}
else{
glEnable(GL_LIGHTING);
lighting = true;
}
}
void drawTexturedQuadPrism(float width,float length,float height,float Xpos,float Ypos,float Zpos,int texture)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, g_TexturesArray[texture]);
prim->drawCube(width,length,height,Xpos,Ypos,Zpos);
}

void drawScreenText(char *str, void *font, GLclampf r, GLclampf g, GLclampf b,
GLfloat x, GLfloat y);

/*------------------------------------------------------------------------
// Calculates the current frame rate
------------------------------------------------------------------------*/

void CalculateFrameRate()
{


static float framesPerSecond = 0.0f; // This will store our fps
static long lastTime = 0; // This will hold the time from the last frame
static char strFrameRate[50] = {0}; // We will store the string here for the window title

static char strPlus[50] = {'0'};
static char strEye[50] = {'0'};
static char strRot[50] = {'0'};

// struct for the time value
struct timeval currentTime;
currentTime.tv_sec = 0;
currentTime.tv_usec = 0;

// gets the microseconds passed since app started
gettimeofday(&currentTime, NULL);

// Increase the frame counter
++framesPerSecond;

if( currentTime.tv_sec - lastTime >= ONE_SECOND )
{
lastTime = currentTime.tv_sec;

// Copy the frames per second into a string to display in the window
sprintf(strFrameRate, "FPS: %d", int(framesPerSecond));
// Reset the frames per second
framesPerSecond = 0;

}
sprintf(strPlus, "[+]");
sprintf(strEye, "Location 0: %f 1: %f 2: %f", float(eye[0]) , float(eye[1]) , float(eye[2]));
sprintf(strRot, "Rotation 0: %f 1: %f 2: %f" ,float(rot[0]) , float(rot[1]) , float(rot[2]));

// draw frame rate on screen
if (showDebugInfo){
drawScreenText(strFrameRate, GLUT_BITMAP_HELVETICA_10, 1.0f, 1.0f, 1.0f, 0.03, 0.95 );
drawScreenText(strEye, GLUT_BITMAP_HELVETICA_10, 1.0f, 1.0f, 1.0f, 0.03, 0.93 );
drawScreenText(strRot, GLUT_BITMAP_HELVETICA_10, 1.0f, 1.0f, 1.0f, 0.03, 0.91 );}
//draw crosshair on screen
if(showHud)
drawScreenText(strPlus, GLUT_BITMAP_TIMES_ROMAN_24, 1.0f, 1.0f, 1.0f, 0.5, 0.5 );

}

//------------------------------------------------------------------------
// Draws the current frame rate on screen
//------------------------------------------------------------------------

void drawScreenText(char *str, void *font, GLclampf r, GLclampf g, GLclampf b,
GLfloat x, GLfloat y) {
/* font: font to use, e.g., GLUT_BITMAP_HELVETICA_10
r, g, b: text colour
x, y: text position in window: range [0,0] (bottom left of window)
to [1,1] (top right of window). */

char *ch;
GLint matrixMode;
GLboolean lightingOn;

lightingOn= glIsEnabled(GL_LIGHTING); /* lighting on? */
if (lightingOn) glDisable(GL_LIGHTING);

glGetIntegerv(GL_MATRIX_MODE, &matrixMode); /* matrix mode? */

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0.0, 1.0, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glPushAttrib(GL_COLOR_BUFFER_BIT); /* save current colour */
glColor3f(r, g, b);
glRasterPos3f(x, y, 0.0);
for(ch= str; *ch; ch++) {
glutBitmapCharacter(font, (int)*ch);
}
glPopAttrib();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(matrixMode);
if (lightingOn) glEnable(GL_LIGHTING);
}

//------------------------------------------------------------------------
// Window resize function
//------------------------------------------------------------------------
void glutResize(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/* modify this line to change perspective values */
gluPerspective(45.0, (float)width/(float)height, 1.0, 300.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

//------------------------------------------------------------------------
// Function that handles keyboard inputs
//------------------------------------------------------------------------
void glutKeyboard(unsigned char key, int x, int y)
{
switch (key)
{
case ESC:
exit(0);
case 'W':
case 'w':
eye[2] = eye[2] - 0.1f;
return;

case 'S':
case 's':
eye[2] = eye[2] + 0.1f;
return;
case 'D':
case 'd':
eye[0] = eye[0] + 0.1f;
return;

case 'A':
case 'a':
eye[0] = eye[0] - 0.1f;
return;
case '~':
case '`':
//implementation
return;


}
}

//------------------------------------------------------------------------
// If rotation angle is greater of 360 or lesser than -360,
// resets it back to zero.
//------------------------------------------------------------------------
void clamp(float *v)
{
int i;

for (i = 0; i < 3; i ++)
if (v[i] > 360 || v[i] < -360)
v[i] = 0;
}

//------------------------------------------------------------------------
// Moves the screen based on mouse pressed button
//------------------------------------------------------------------------
void glutMotion(int x, int y)
{
if (mButton == BUTTON_LEFT)
{
/* rotates screen */
rot[0] -= (mOldY - y);
rot[1] -= (mOldX - x);
clamp (rot);
}
else if (mButton == BUTTON_RIGHT)
{
/*
translate the screen, z axis
gives the idea of zooming in and out
*/
eye[2] -= (mOldY - y) * 0.05f; // here I multiply by a 0.2 factor to
// slow down the zoom
clamp (rot);
}
else if (mButton == BUTTON_LEFT_TRANSLATE)
{
eye[0] += (mOldX - x) * 0.01f;
eye[1] -= (mOldY - y) * 0.01f;
clamp (rot);
}

mOldX = x;
mOldY = y;
}

//------------------------------------------------------------------------
// Function that handles mouse input
//------------------------------------------------------------------------
void glutMouse(int button, int state, int x, int y)
{
if(state == GLUT_DOWN)
{
mOldX = x;
mOldY = y;
switch(button)
{
case GLUT_LEFT_BUTTON:
if (glutGetModifiers() == GLUT_ACTIVE_CTRL)
{
mButton = BUTTON_LEFT_TRANSLATE;
break;
} else
{
mButton = BUTTON_LEFT;
break;
}
case GLUT_RIGHT_BUTTON:
mButton = BUTTON_RIGHT;
break;
}
} else if (state == GLUT_UP)
mButton = -1;
}

//------------------------------------------------------------------------
// The glut's menu callback function. Called every time an option is selected
//------------------------------------------------------------------------

void glutMenu(int value)
{
switch (value)
{
case 1:
glutFullScreen();
return;
case 2:
rotate = !rotate;
return;
case 3:
wireframe = !wireframe;
return;
case 4:
toggleLighting();
return;
case 5:
showHud = !showHud;
return;
case 6:
clearBuffer = !clearBuffer;
return;
case 7:
showDebugInfo = !showDebugInfo;
return;
case 0:
exit(0);
return;
}
}

//------------------------------------------------------------------------
// Function that handles special keyboards input (SHIFT, CTRL, ALT)
//------------------------------------------------------------------------
void glutSpecial(int value, int x, int y)
{
switch (value)
{
case GLUT_KEY_F11:
glutFullScreen();
return;
case GLUT_KEY_UP:
rot[0] = rot[0]--;
eye[1] = eye[1] + 0.07f;
eye[3] = eye[3] - 0.09f;
return;
case GLUT_KEY_DOWN:
rot[0] = rot[0]++;
eye[1] = eye[1] - 0.07f;
eye[3] = eye[3] + 0.09f;
return;
case GLUT_KEY_LEFT:
rot[1] = rot[1]--;
eye[3] = eye[3] + 0.1f;
return;
case GLUT_KEY_RIGHT:
rot[1] = rot[1]++;
eye[3] = eye[3] - 0.1f;
return;


}
}

//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvv
//vvvvvvvvvvvvvvvvvvvvvv ATTENTION HERE!!! vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//************************************************** **********************
// The draw function. Replaces code listed here for your own drawing code.
// For demo of the framework i drew i simple cube that can be freely
// rotated with mouse buttons.
//************************************************** **********************
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvv
void glutDisplay(void)
{

if (clearBuffer)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

if (wireframe)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

glColor3f(1.0f, 1.0f, 1.0f);
glPushMatrix();

/* translate camera to the coordinates provided by eye array */
glTranslatef (-eye[0], -eye[1], -eye[2]);

/* rotates the screen by the angles provided by rot array */
glRotatef(rot[0], 1.0f, 0.0f, 0.0f);
glRotatef(rot[1], 0.0f, 1.0f, 0.0f);
glRotatef(rot[2], 0.0f, 0.0f, 1.0f);

//things to draw
// drawTexturedQuadPrism(1.0f,1.0f,2.0f,0.0f,0.0f,0.0 f,0);


drawmodel_box();

glPopMatrix();

glColor3f(1.0f, 1.0f, 1.0f);
CalculateFrameRate();

glFlush();
glutSwapBuffers();

// here I increment y-axis value to give a rotating animation to the cube
// greater values here gives more speed to the animation

if (rotate)
rot[1] += 0.5;
#ifdef USESLEEP
usleep(1000000/50);
#endif
}

///vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvv
/// The code here can be freely altered too. It's mainly designed to set
/// OpenGl's initial value and configuration.
///vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvv
void InitializeOGL()
{

glShadeModel(GL_SMOOTH);

glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background
glClearDepth(1.0f);

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
// enable texture and binds a texture to the first element of the array
//glEnable(GL_TEXTURE_2D);
CreateTexture(g_TexturesArray,"logo.tga",0);
CreateTexture(g_TexturesArray,"Crate.tga",1);
CreateTexture(g_TexturesArray, "skyBox.tga",2);

//lighting code
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);

glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light
if (lighting)
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT1);


return;
}

/*------------------------------------------------------------------------
* It's the main application function. Note the clean code you can
* obtain using he GLUT library. No calls to dark windows API
* functions with many obscure parameters list. =)
*-----------------------------------------------------------------------*/
int main(int argc, char** argv)
{
/*
Glut's initialization code. Set window's size and type of display.
Window size is put half the 800x600 resolution as defined by above
constants. The windows is positioned at the top leftmost area of
the screen.
*/


glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA | GLUT_MULTISAMPLE);
glutInitWindowPosition( GL_WIN_INITIAL_X, GL_WIN_INITIAL_Y );
glutInitWindowSize( GL_WIN_WIDTH, GL_WIN_HEIGHT );
glutInit( &argc, argv );

glutCreateWindow("GL Window");

/*
The function below are called when the respective event
is triggered. Very simple, isn't it?
*/
glutReshapeFunc(glutResize); // called every time the screen is resized
glutDisplayFunc(glutDisplay); // called when window needs to be redisplayed
glutIdleFunc(glutDisplay); // called whenever the application is idle
glutKeyboardFunc(glutKeyboard); // called when the application receives a input from the keyboard
glutMouseFunc(glutMouse); // called when the application receives a input from the mouse
glutMotionFunc(glutMotion); // called when the mouse moves over the screen with one of this button pressed
glutSpecialFunc(glutSpecial); // called when a special key is pressed like SHIFT

/*
Do any lighting, material, alpha, etc initialization or
configuration here.
*/
InitializeOGL();

/*
Creates a menu attached to the mouses middle button
the menu here consists in two options, one to toggle
fullscreen mode and another for exiting the application.
*/
glutCreateMenu(glutMenu);
glutAddMenuEntry("Full Screen", 1);
glutAddMenuEntry("Rotation", 2);
glutAddMenuEntry("Wireframe",3);
glutAddMenuEntry("Lighting" , 4);
glutAddMenuEntry("HUD",5);
glutAddMenuEntry("Buffer" , 6);
glutAddMenuEntry("Debug" , 7);

glutAddMenuEntry("Exit", 0);
glutAttachMenu(GLUT_MIDDLE_BUTTON);

/*
Application's main loop. All the above functions
are called whe the respective events are triggered
*/
glutMainLoop();

return 0;
}



you may be able to compile that if you remove some useless stuff,like references to the other files

snip3r8
July 15th, 2011, 11:15 PM
the glm.cpp and glm.h are not written by me ,i got them off the net
you include

glm.h

and then create the following function in your main



void drawmodel_box(void)
{
// Load the model only if it hasn't been loaded before
// If it's been loaded then pmodel1 should be a pointer to the model geometry data...otherwise it's null
if (!pmodel1)
{
// this is the call that actualy reads the OBJ and creates the model object
pmodel1 = glmReadOBJ("blend.obj");

if (!pmodel1) exit(0);
// This will rescale the object to fit into the unity matrix
// Depending on your project you might want to keep the original size and positions you had in 3DS Max or GMAX so you may have to comment this.
glmUnitize(pmodel1);
// These 2 functions calculate triangle and vertex normals from the geometry data.
// To be honest I had some problem with very complex models that didn't look to good because of how vertex normals were calculated
// So if you can export these directly from you modeling tool do it and comment these line
// 3DS Max can calculate these for you and GLM is perfectly capable of loading them
glmFacetNormals(pmodel1);
glmVertexNormals(pmodel1, 90.0);
}
// This is the call that will actualy draw the model
// Don't forget to tell it if you want textures or not :))
glmDraw(pmodel1, GLM_SMOOTH | GLM_TEXTURE | GLM_MATERIAL);

}


then you are just supposed to use


drawmodel_box();

in your drawing code and everything should just work

Bachstelze
July 15th, 2011, 11:43 PM
After renaming glm.c to glm.cpp (Why does the comment says glm.c then and why doe sit include C headers? C and C++ are not the same thing!), I can compile it more or less fine (it gives two warnings, but no errors), so you will have to tell me more precisely when the error occurs (i.e. give the exact command you are running that causes the error).

snip3r8
July 15th, 2011, 11:51 PM
void drawmodel_box(void)
{
// Load the model only if it hasn't been loaded before
// If it's been loaded then pmodel1 should be a pointer to the model geometry data...otherwise it's null
if (!pmodel1)
{
// this is the call that actualy reads the OBJ and creates the model object
pmodel1 = glmReadOBJ("blend.obj");

if (!pmodel1) exit(0);
// This will rescale the object to fit into the unity matrix
// Depending on your project you might want to keep the original size and positions you had in 3DS Max or GMAX so you may have to comment this.
glmUnitize(pmodel1);
// These 2 functions calculate triangle and vertex normals from the geometry data.
// To be honest I had some problem with very complex models that didn't look to good because of how vertex normals were calculated
// So if you can export these directly from you modeling tool do it and comment these line
// 3DS Max can calculate these for you and GLM is perfectly capable of loading them
glmFacetNormals(pmodel1);
glmVertexNormals(pmodel1, 90.0);
}
// This is the call that will actualy draw the model
// Don't forget to tell it if you want textures or not :))
glmDraw(pmodel1, GLM_SMOOTH | GLM_TEXTURE | GLM_MATERIAL);

}

is the problem

Bachstelze
July 15th, 2011, 11:55 PM
so you will have to tell me more precisely when the error occurs (i.e. give the exact command you are running that causes the error).

Code is only part of the story. How you compile it is also important. ;)

snip3r8
July 15th, 2011, 11:59 PM
Ok nevermind,it seems that it just doesnt like glm ,as soon as you include glm it throws an error

Bachstelze
July 16th, 2011, 12:09 AM
Ok nevermind,it seems that it just doesnt like glm ,as soon as you include glm it throws an error

The drawmodel_box function compiles fine here. You're probably just making a small mistake in the command you run, but since you don't seem to want to show it, nothing I can do...

snip3r8
July 19th, 2011, 06:29 PM
Solved!...I was missing a function.