OBJ Model Texturing Problem

For some reason the texturing coordinates don’t seem to be working with my obj class code. Does anybody see why? Thanks

Here’s the cpp file:

#include <stdio.h> // Header File For Input/Output
#include <string.h> // Header for working with strings
#include <stdarg.h>
#include <iostream.h> // Header for C++ console input/output
#include <fstream.h> // Header for C++ file I/O
#include <math.h> // Header for sine and cosine
#include <gl/glfw.h> // Header for GLFW, OpenGL and GLU
#include <gl/gl.h> // Header file for OpenGL
#include <gl/glaux.h> // Header file for GLaux
#include <gl/glu.h> // Header file for glu
#include <gl/glut.h> // Header file for glut
#include “objLoader.h” // Header file for the OBJ variables/class
#include “loadTexture.h”

void OBJ::displayModel() {
for(int i = 0; i cout << texcordx[ faces.texCords[0] ] << texcordy[ faces[i].texCords[0] ] << endl;
cout << texcordx[ faces[i].texCords[1] ] << texcordy[ faces[i].texCords[1] ] << endl;
cout << texcordx[ faces[i].texCords[2] ] << texcordy[ faces[i].texCords[2] ] << endl;
}
}

void OBJ::readstr(FILE *f,char *string) // Reads A String From File (f)
{
do // Do This
{
fgets(string, 255, f); // Gets A String Of 255 Chars Max From f (File)
} while ((string[0] == ‘/’) | | (string[0] == ’
')); // Until End Of Line Is Reached
return; // Return
}

void OBJ::drawOBJ(int mode) {
if(mode==0) {
glColor4f(1, 1, 1, 1);
for(int i = 0; i if(faces[i].status==0 | | 4) {
glBegin( GL_TRIANGLES );
glVertex3f(vertx[faces[i].vertices[0]-1], verty[faces[i].vertices[0]-1], vertz[faces[i].vertices[0]-1]);
glVertex3f(vertx[faces[i].vertices[1]-1], verty[faces[i].vertices[1]-1], vertz[faces[i].vertices[1]-1]);
glVertex3f(vertx[faces[i].vertices[2]-1], verty[faces[i].vertices[2]-1], vertz[faces[i].vertices[2]-1]);
glEnd();
}
else if(faces[i].status==1 | | 5) {
glBegin( GL_QUADS );
glVertex3f(vertx[faces[i].vertices[0]-1], verty[faces[i].vertices[0]-1], vertz[faces[i].vertices[0]-1]);
glVertex3f(vertx[faces[i].vertices[1]-1], verty[faces[i].vertices[1]-1], vertz[faces[i].vertices[1]-1]);
glVertex3f(vertx[faces[i].vertices[2]-1], verty[faces[i].vertices[2]-1], vertz[faces[i].vertices[2]-1]);
glVertex3f(vertx[faces[i].vertices[3]-1], verty[faces[i].vertices[3]-1], vertz[faces[i].vertices[3]-1]);
glEnd();
}
else if(faces[i].status==2 | | 6) {
glBegin( GL_TRIANGLES );

glTexCoord2f(texcordx[faces[i].texCords[0]-1], texcordy[faces[i].texCords[0]-1]);
glVertex3f(vertx[faces[i].vertices[0]-1], verty[faces[i].vertices[0]-1], vertz[faces[i].vertices[0]-1]);

glTexCoord2f(texcordx[faces[i].texCords[1]-1], texcordy[faces[i].texCords[1]-1]);
glVertex3f(vertx[faces[i].vertices[1]-1], verty[faces[i].vertices[1]-1], vertz[faces[i].vertices[1]-1]);

glTexCoord2f(texcordx[faces[i].texCords[2]-1], texcordy[faces[i].texCords[2]-1]);
glVertex3f(vertx[faces[i].vertices[2]-1], verty[faces[i].vertices[2]-1], vertz[faces[i].vertices[2]-1]);

glEnd();
}
else if(faces[i].status==3 | | 7) {
glBegin( GL_QUADS );

glTexCoord2f(texcordx[faces[i].texCords[0]-1], texcordy[faces[i].texCords[0]-1]);
glVertex3f(vertx[faces[i].vertices[0]-1], verty[faces[i].vertices[0]-1], vertz[faces[i].vertices[0]-1]);

glTexCoord2f(texcordx[faces[i].texCords[1]-1], texcordy[faces[i].texCords[1]-1]);
glVertex3f(vertx[faces[i].vertices[1]-1], verty[faces[i].vertices[1]-1], vertz[faces[i].vertices[1]-1]);

glTexCoord2f(texcordx[faces[i].texCords[2]-1], texcordy[faces[i].texCords[2]-1]);
glVertex3f(vertx[faces[i].vertices[2]-1], verty[faces[i].vertices[2]-1], vertz[faces[i].vertices[2]-1]);

glTexCoord2f(texcordx[faces[i].texCords[3]-1], texcordy[faces[i].texCords[3]-1]);
glVertex3f(vertx[faces[i].vertices[3]-1], verty[faces[i].vertices[3]-1], vertz[faces[i].vertices[3]-1]);

glEnd();
}
}
}
}

int OBJ::loadOBJ(const char *filename) {

char strLine[255] = { 0 };
// Check to make sure the extension is obj
int length;

char c; // a simple buffer
char b; // another buffer
char d; // yet another buffer

int howmuch; // For parsing the f lines
char type[10]; // What type is the current line
int values[12]; // The ints being read in (f)
float valuesf[3]; // The floats being read in (v, vt, & vn)
int counter[4] = { 0, 0, 0, 0 }; // A counter for which line we are on
char charbuffer[255];
int percentRight = 0; // The percentage of values successfully matched

length = strlen(filename);
if( length < 5) {
cout << “Filename given to loadOBJ is too short to be complete. Aborting” << endl;
exit(-1);
}
if(FILE *inputfile = fopen(filename, “r”)) {
// Our first task will be to allocate all of the appropriate space for the vertices, texture cords, and lighting normals
while(feof(inputfile)==0) {
c = fgetc(inputfile);
if(c==‘v’) {
b = fgetc(inputfile);
if(b==’ ') { // Its a vertex
verts++;
}
else if(b==‘t’) { // Its a texture cordinate
cords++;
}
else if(b==‘n’){ // If its niether then its a lighting normal
normals++;
}
}
if(c==‘f’) { // The actual polygon faces that are to be drawn
facesn++;
} // That should do it, we are done parsing the f lines and counting them up
if(c==‘g’) {
groups++;
}
}
// Now establish memory for storing all of them

vertx = new float [verts];
verty = new float [verts];
vertz = new float [verts];

texcordx = new float [cords];
texcordy = new float [cords];

lightingx = new float [normals];
lightingy = new float [normals];
lightingz = new float [normals];

faces = new polyface [facesn]; // Declare room for each polyface

// Now read in all of the values to the memory after going back to the beginning for the second pass
fseek(inputfile,0,SEEK_SET); // Reset to the beginning of the file
while(feof(inputfile)==0) {
linenumber++;
readstr(inputfile, charbuffer);
sscanf(charbuffer, “%s %f %f %f”, &type, &valuesf[0], &valuesf[1], &valuesf[2]);

// Its a vertex or a normal
if(strcmp(type, “v”)==0) {
vertx[counter[0]] = valuesf[0];
verty[counter[0]] = valuesf[1];
vertz[counter[0]] = valuesf[2];
counter[0]++;
}
else if(strcmp(type, “vn”)==0) {
lightingx[counter[1]] = valuesf[0];
lightingy[counter[1]] = valuesf[1];
lightingz[counter[1]] = valuesf[2];
counter[1]++;
}
else if(strcmp(type, “vt”)==0) {
texcordx[counter[2]] = valuesf[0];
texcordy[counter[2]] = valuesf[1];
counter[2]++;
}
else if(strcmp(type, “f”)==0) {
// if its a polygon face then we must parse it as follows
howmuch = sscanf(charbuffer, “f %d %d %d %d”, &values[0], &values[1], &values[2], &values[3]);
if(howmuch==3) {
// They are drawing a polygon face with no vertex cordinates or lighting normals but its a triangle
faces[counter[3]].status = 0;
faces[counter[3]].vertices[0] = values[0];
faces[counter[3]].vertices[1] = values[1];
faces[counter[3]].vertices[2] = values[2];
counter[3]++;
}
else if(howmuch==4) {
// They are drawing a polygon face with no vertex cordinates or lighting normals but its a quad
faces[counter[3]].status = 1;
faces[counter[3]].vertices[0] = values[0];
faces[counter[3]].vertices[1] = values[1];
faces[counter[3]].vertices[2] = values[2];
faces[counter[3]].vertices[3] = values[3];
counter[3]++;
}
else if(howmuch<3) {
// In this situation the polygon face contains lighting normals and texture cordinates
howmuch = sscanf(charbuffer, “f %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d”,
&values[0], &values[1], &values[2],
&values[3], &values[4], &values[5],
&values[6], &values[7], &values[8],
&values[9], &values[10], &values[11]);
if(howmuch==12) {
// Here we verify that the format of the f line is as displayed in the sscanf above
// It would be a quad with 4 vertices, lighting normals, and texture cords
faces[counter[3]].status = 5;

// Assign vertices to memory
faces[counter[3]].vertices[0] = values[0];
faces[counter[3]].vertices[1] = values[3];
faces[counter[3]].vertices[2] = values[6];
faces[counter[3]].vertices[3] = values[9];

// Assign texture coordinates to memory
faces[counter[3]].texCords[0] = values[1];
faces[counter[3]].texCords[1] = values[4];
faces[counter[3]].texCords[2] = values[7];
faces[counter[3]].texCords[3] = values[10];

// Assign lighting normals to memory
faces[counter[3]].uvNormals[0] = values[2];
faces[counter[3]].uvNormals[1] = values[5];
faces[counter[3]].uvNormals[2] = values[8];
faces[counter[3]].uvNormals[3] = values[11];

counter[3]++;
}
else if(howmuch==9) {
// Here we verify that the format of the f line is as displayed in the sscanf above
// It would be a triangle with 3 vertices, texture cords, and lighting normals
faces[counter[3]].status = 4;

// Assign vertices to memory
faces[counter[3]].vertices[0] = values[0];
faces[counter[3]].vertices[1] = values[3];
faces[counter[3]].vertices[2] = values[6];

// Assign texture coordinates to memory
faces[counter[3]].texCords[0] = values[1];
faces[counter[3]].texCords[1] = values[4];
faces[counter[3]].texCords[2] = values[7];

// Assign lighting normals to memory
faces[counter[3]].uvNormals[0] = values[2];
faces[counter[3]].uvNormals[1] = values[5];
faces[counter[3]].uvNormals[2] = values[8];

counter[3]++;
}
else if(howmuch==1) {
/*
This is run if the format above does not apply.
In this case the f line is PROBABLY in the format
f v//vn v//vn v//vn v//vn etc
As you can see the texture coordinates are being left out.
While this isn’t present in personwithgun.obj or foot.obj, we will
add it in to help comply with the obj specification.
*/
howmuch = sscanf(charbuffer, “f %d//%d %d//%d %d//%d %d//%d”,
&values[0], &values[1],
&values[2], &values[3],
&values[4], &values[5],
&values[6], &values[7]);
if(howmuch==8) {
faces[counter[3]].status = 7;

faces[counter[3]].vertices[0] = values[0];
faces[counter[3]].vertices[1] = values[2];
faces[counter[3]].vertices[2] = values[4];
faces[counter[3]].vertices[3] = values[6];

faces[counter[3]].uvNormals[0] = values[1];
faces[counter[3]].uvNormals[1] = values[3];
faces[counter[3]].uvNormals[2] = values[5];
faces[counter[3]].uvNormals[3] = values[7];

counter[3]++;
}
else if(howmuch==6) {
faces[counter[3]].status = 6;

faces[counter[3]].vertices[0] = values[0];
faces[counter[3]].vertices[1] = values[2];
faces[counter[3]].vertices[2] = values[4];

faces[counter[3]].uvNormals[0] = values[1];
faces[counter[3]].uvNormals[1] = values[3];
faces[counter[3]].uvNormals[2] = values[5];

counter[3]++;
}
else if(howmuch==1) {
howmuch = sscanf(charbuffer, “f %d/%d %d/%d %d/%d %d/%d”,
values[0], values[1],
values[2], values[3],
values[4], values[5],
values[6], values[7]);
if(howmuch==6) {
// If this is the case the f line is a triangle with
// no lighting normals.
faces[counter[3]].status = 2;

faces[counter[3]].vertices[0] = values[0];
faces[counter[3]].vertices[1] = values[2];
faces[counter[3]].vertices[2] = values[4];

faces[counter[3]].texCords[0] = values[1];
faces[counter[3]].texCords[1] = values[3];
faces[counter[3]].texCords[2] = values[5];

counter[3]++;
}
else if(howmuch==8) {
// For this condition the f line is a quad with no
// lighting normals
faces[counter[3]].status = 3;

faces[counter[3]].vertices[0] = values[0];
faces[counter[3]].vertices[1] = values[2];
faces[counter[3]].vertices[2] = values[4];
faces[counter[3]].vertices[3] = values[6];

faces[counter[3]].texCords[0] = values[1];
faces[counter[3]].texCords[1] = values[3];
faces[counter[3]].texCords[2] = values[5];
faces[counter[3]].texCords[3] = values[7];

counter[3]++;
} // else if
} // else if
} // else if
} // else if
} // if
else {
cout << “skipped line” << endl;
} // else
} // while

cout << verts << " " << cords << " " << normals << " " << groups << endl;
fclose(inputfile);
return true;
}
else {
return false;
}
}

And the header file:

#ifndef OBJLOADER_H
#define OBJLOADER_H

#include <stdio.h> // Header File For Input/Output
#include <string.h> // Header for working with strings
#include <stdarg.h>
#include <iostream.h> // Header for C++ console input/output
#include <fstream.h> // Header for C++ file I/O

class OBJ {
public:
void displayModel();
void readstr(FILE *f,char *string);
void drawOBJ(int mode);
int loadOBJ(const char filename);
private:
int linenumber;
struct polyface {
int vertices[4];
int texCords[4];
int uvNormals[4];
int status;
};
/

In reference to the status variable, if it is 0 it means its a triangle with 3 vertices, no tex
cords, and no lighting normals. If it is 1 then it means that its a quad with 4 vertices, no
tex cords, and no lighting normals. If it is 2 then it means that its a triangle with 3
vertices, 3 texture cordinates, and no lighting normals. If it is a 3 then it means its a quad
with 4 vertices, 4 tex cords, and no lighting normals. If it is a 4 then it means that its a
triangle with 3 tex cords, vertices, and lighting normals. If its a 5 then it means its a quad
with 4 tex cords, vertices, and lighting normals. If its a 6 then it means its a
triangle with 3 vertices and 3 lighting normals but if its a 7 its a quad. Sounds simple eh?
*/

/*
Here’s all the memory used for storing the obj data. Please note the data is shared
between loadOBJ and drawOBJ. Obviously this program needs a more object oriented structure
however for now this gets the job done
*/
// Vertice memory
float *vertx;
float *verty;
float *vertz;

// Texture Coordinate memory
float *texcordx;
float *texcordy;

// Lighting normal memory
float *lightingx;
float *lightingy;
float *lightingz;

int verts; // how many vertices
int cords; // how many texture coordinates
int normals; // how many normals
int groups; // how many groups
int facesn; // how many face lines

// Pointer for f lines
polyface *faces;

};

#endif

1.) “for(int i = 0; i if(faces[i].status==0 | | 4) {”

Does your code compile?

2.) “if(faces[i].status==0 | | 4)”

Evaluates always to TRUE because of the “| | 4”, and will never touch the else-if?

For performance and readability you should try to put vertx, verty, vertz into float vert[][3] arrays and call glVertex3fv(vert[faces[i].vertices[0]-1]);

Whoa you were right! I assumed that the | | operator was smarter than that but I guess not. I made your first suggested changes and now it draws it perfectly! However it still doesn’t texture. Very strange…

Did you call glEnable(GL_TEXTURE_2D) somewhere?
(Read the RedBook and have a look at switch-case statements in C.)

I’m pretty sure its enabled correctly. It looks as though the model is textured with only one texture coordinate as the model changes colors. I have the color as glColor3f(1, 1, 1) but the color is NOT white. Any ideas?