   Need some help fixing an wavefront object file phraser and displayer for opengl.
  So, for my new game I want to be able to display the models my team would give me, I made a model loader to start off with, but soon realized that the objects were being displayed wrong. After trying to fix it, it went from bad to worse, and he's my code, perhaps someone here can help me fix it or link me to an already completed wavefront object file phraser and displayer.Here's the code:struct vec3{    float x,y,z;};struct face{    vec3 pos[4];};class globjfaces{    public:    int verts,fv,shapes;    vec3  vectors[10001];    face  facevector[10001];    int numberofvectors[10001];    void  show(int x,int y,int z);    void  readin(char *filenam);    globjfaces(){verts = 1;fv = 0;shapes = 0;};};void  globjfaces::readin(char *filename){    std::string line;    ifstream infile(filename);    bool llwf = false;    while(!infile.eof())    {  getline(infile,line);  if(numwords(line) > 1)  { if(getword(line,0) == "v") { vec3 tmp; tmp.x = atof(getword(line,1).c_str()); tmp.y = atof(getword(line,2).c_str()); tmp.z = atof(getword(line,3).c_str()); vectors[verts] = tmp; verts++; } if(getword(line,0) == "f") { numberofvectors[fv] = numwords(line)-1; for(int i = 1; i<numwords(line); i++) {facevector[fv].pos = vectors[sideofslash(getword(line,i),true)]; } fv++; llwf = true; }  }    }}void globjfaces::show(int x,int y,int z){   for(int i = 0; i<fv; i++)   {  if(numberofvectors == 3)  { glBegin(GL_TRIANGLES); glVertex3f(x+facevector.pos[0].x, y+facevector.pos[0].y,  z+facevector.pos[0].z); glVertex3f(x+facevector.pos[1].x, y+facevector.pos[1].y,  z+facevector.pos[1].z); glVertex3f(x+facevector.pos[2].x, y+facevector.pos[2].y,  z+facevector.pos[2].z); glEnd();  }  else if(numberofvectors == 4)  { glBegin(GL_QUADS); glVertex3f(x+facevector.pos[0].x, y+facevector.pos[0].y,  z+facevector.pos[0].z); glVertex3f(x+facevector.pos[1].x, y+facevector.pos[1].y,  z+facevector.pos[1].z); glVertex3f(x+facevector.pos[2].x, y+facevector.pos[2].y,  z+facevector.pos[2].z); glVertex3f(x+facevector.pos[3].x, y+facevector.pos[3].y,  z+facevector.pos[3].z); glEnd();  }   }}A few functions to deal with strings that are used aren't included, but it shouldn't be too hard to figure out what they do, though if needed I will post them also.EDIT: What's this, the frequently asked questions section seems to have awnsered a frequently asked question, I'll go see if I can get the phraser mentioned there to work for me, I just hope it includes something to display models.[Edited by - DrenDran on October 6, 2010 8:30:30 AM]
  It would be nice to see those string functions.I've been making the same stuff since yesterday (openGL, .obj) and it works/displays fine, so the thing is fresh.So: what is the problem with it?"displays wrong" says absolutely nothing.A few things: you don't seem to calculate any normals anywhere. So you can't use lighting, so it is definitely inside the category of "displays wrong".Apart from that, it can be anything. We don't even know, if the display or the PARSER code is broken.Another thing: I would drop the polygon thing (triangle vs quads) and I would convert everything to triangles (at least for the display).Another thing: your parser is only able to parse ONE object (mine too). So you have to export to .obj as ONE object.Another thing: indexing in .obj starts with 1 (one), not 0 (zero). So you have do subtract one from the read values.Another thing: why "verts" starts with 1 (one)?///////The way I did it:I started with the display, you need to see what you are doing. With a simple probe: a cube. I hard coded it, including normals. Got the lighting working (it took ridiculously long: beware of *float to *double conversion!!).Wrote the face normal calculation code. Fixed that.After that:*Parsing vertices only: display: GL_POINTS.*Parsing face data too: only the first 3 params. calculated face normals then displayed with flat shading.*Parsing all face data (3,4,more if the obj exporter supports), converting to triangles on the spot as a triangle fan: display*calculating vertex normals by averaging the face normals around the vertex: display*calculated weighed average for better normals: display(*optional: made the edge list for selection and display: inside edges flagged as inside: this shows the triangulation of the polygons but only the edges of the faces can be selected: so I can work with the nice edge flow modeled in the external editor)Every steps are debugged to be perfect.   ;  Another thing: Is it safe to check only for the occurrence of "v" and "f"?What happens if it's somewhere else in the file, in a comment? Maybe it's not a big issue, but it can fail in corner cases. It would be good to see those string functions you use.EDIT: forget it. Commented lines start with '#', so your code is fine (if your string functions are fine)This line is suspicious:facevector[fv].pos = vectors[sideofslash(getword(line,i),true)]; Where do you convert the string to an integer? And you have to subtract 1 (one) from that integer.And another thing: if you use C++, wouldn't it me simpler/more elegant to use cin functions?;Quote:Original post by szecsIt would be nice to see those string functions.Well, numwords returns the number of words in a sentence.Getword returns the particular word. If the second arugmnet is 0, it gets the first word, if it's 1 it returns the second, and so on.And sideofslash takes a string that contains a slash character and if the second argument is true it returns what is before the slash, if not, what is after the slash.I can't access my code atm, but I will post source later.Quote:Original post by szecsI've been making the same stuff since yesterday (openGL, .obj) and it works/displays fine, so the thing is fresh.I might as well ask, can I see that code?Quote:Original post by szecsSo: what is the problem with it?"displays wrong" says absolutely nothing.I would post pictures of the model and what it comes out of in my displayer in game, but I can't atm.Quote:Original post by szecsA few things: you don't seem to calculate any normals anywhere. So you can't use lighting, so it is definitely inside the category of "displays wrong".I'm not using lighting, I don't believe.Quote:Original post by szecsApart from that, it can be anything. We don't even know, if the display or the PARSER code is broken.When I can access the code, I'll run some tests, but I belive it's how I'm displaying it, or both.Quote:Original post by szecsAnother thing: I would drop the polygon thing (triangle vs quads) and I would convert everything to triangles (at least for the display).I will try this later.Quote:Original post by szecsAnother thing: your parser is only able to parse ONE object (mine too). So you have to export to .obj as ONE object.I origionally had it detect and move over to a new shape if the line after a face was a vector, but it just made things more complicated.Quote:Original post by szecsAnother thing: indexing in .obj starts with 1 (one), not 0 (zero). So you have do subtract one from the read values.Will do.Quote:Original post by szecsAnother thing: why "verts" starts with 1 (one)?I'll have read though my code and see.EDIT: see OP edit   ;  Issues with MY code:*It's C.*It can handle only one object (note, even if you don't care, your parser WILL BE broken, if the .obj contains more objects)*no texture coordinates and normals, no nothing*If the texture coordinates and the normals are stored too: my code breaks because it cannot parse the "10//511" or "10/11/10" things yet.*The parser code is messy, I've been working on it for only a day.*It's slowvoid LoadObj(double *vertex_list, int *triangle_list, double *vertex_norm, edge_type *edge_list,    int *vert_count, int *tri_count, int *edge_count){    char buffer[1000];    float v1,v2,v3;    int f1,f2,f3,f_n;    int offset,n;    FILE *stream;    *tri_count = 0;    *vert_count = 0;    stream = fopen("fotel_05_low.obj","rt");    //stream = fopen("henger.obj","rt");    if( !stream )   return;    while( fgets(buffer,998,stream) )    {  if( sscanf(buffer,"v %f %f %f",&v1,&v2,&v3) == 3 )   { vertex_list[ (*vert_count)*3 + 0 ] = (double)v1;  vertex_list[ (*vert_count)*3 + 1 ] = (double)v2;  vertex_list[ (*vert_count)*3 + 2 ] = (double)v3;  (*vert_count)++;   }   else if( sscanf(buffer,"f %d %d %d %n",&f1,&f2,&f3, &n) == 3 )   {  triangle_list[ (*tri_count)*3 + 0 ] = f1-1;  triangle_list[ (*tri_count)*3 + 1 ] = f2-1;  triangle_list[ (*tri_count)*3 + 2 ] = f3-1;  AddPolyEgde(edge_list, TRUE, edge_count, f1-1, f2-1);//not interesting  AddPolyEgde(edge_list, TRUE, edge_count, f2-1, f3-1);//not interesting  (*tri_count)++;  for (offset=n; sscanf(buffer+offset, "%d %n", &f_n, &n)==1; offset += n)  { triangle_list[ (*tri_count)*3 + 0 ] = f1-1; triangle_list[ (*tri_count)*3 + 1 ] = f3-1; triangle_list[ (*tri_count)*3 + 2 ] = f_n-1; AddPolyEgde(edge_list, TRUE, edge_count, f3-1, f_n-1);//not interesting AddPolyEgde(edge_list, FALSE, edge_count, f1-1, f3-1);//not interesting (*tri_count)++; f3 = f_n;  }  AddPolyEgde(edge_list, TRUE, edge_count, f3-1, f1-1);//not interesting   }    }    fclose(stream);    CalcVertexNormals(vertex_list,triangle_list,vertex_norm,*tri_count,*vert_count);}Anyway: I strongly suggest you to debug it in a way I posted.   ;Quote:Original post by szecsIssues with MY code:*It's C.*It can handle only one object (note, even if you don't care, your parser WILL BE broken, if the .obj contains more objects)*no texture coordinates and normals, no nothing*If the texture coordinates and the normals are stored too: my code breaks because it cannot parse the "10//511" or "10/11/10" things yet.*The parser code is messy, I've been working on it for only a day.*It's slow*** Source Snippet Removed ***Anyway: I strongly suggest you to debug it in a way I posted.Hmm, I've never seen "AddPolyEdge" or "CalcVertexNormals" before, and a google search of "AddPolyEdge" dosn't really bring up anything. Are these functions you made?   ;  They are mine.But AddPolyEdge is not your concern ATM, and it's messy, and maybe it will be dropped (edge data is for editing the mesh).CalcVertexNormals is also messy, it will be refractored I guess.   ;  Ok, this might be like the wrong answer and completely over the top, but here is my implementation, of my new defunct project:http://libqgl.svn.sourceforge.net/viewvc/libqgl/trunk/obj2qgl/src/It's obviously over the top because it uses the parser construction tools bison and flex... Even if you think it is overkill, I would suggest that you write a lexer / parser with a more standard approach:char stream -> lexer -> token stream -> parser -> objectsYou have a lexer (aka. tokenizer) that determines the type of token and the associated value. The you write something like a recursive decent parser that will trigger on the "keywords" (o, g, n, f...) read a batch of values. You detect errors when you get a token that is not of proper type.You should look over your code. It's awful, for C++ code. But I can't see any obvious flaw.   ;  Well, I would be grateful to have a parser in C. Mine works but I want to make a software which I want to release, so "works" is not enough.I'll look into it myself too of course.   ;  Here is my old code that I am now using, which can show a sphere or cube model fine:#ifndef __MAIN_H__#define __MAIN_H__#include <sstream>#include <iostream>#include <fstream>#include <SDL_opengl.h>using namespace std;struct vec3{    float x,y,z;};class globjfaces{    public:    int verts,fv,shapes;    vec3  vectors[10001];    vec3  facevector[10001];    void  show(int x,int y,int z);    void  readin(char *filenam);    globjfaces(){verts = 1;fv = 0;};};struct chalen{    unsigned char* data;    int length;    bool used;    void  allocspace(int space);};void chalen::allocspace(int space){    length = space;    data = new unsigned char[space];    for(int i = 0; i<space; i++)   data = 0xFD;}chalen  cutdat(chalen in,int amount){    chalen ret;    ret.allocspace(in.length-amount);    for(int i = amount; i<in.length; i++)   ret.data[i-amount] = in.data;    return ret;}chalen  readarg(chalen &in){    chalen ret;    int off = 0;    for(int i = 0; i<in.length; i++)    {   if(in.data == 0xFE || in.data == 0xFF)  break;   ret.allocspace(i+1);   for(int a = 0; a<i+1; a++)  ret.data[a] = in.data[a];   off = i;    }    in = cutdat(in,off+2);    return ret;}string  istr(int in){    std::stringstream bob;    bob<<in;    return bob.str();}std::string  fstr(float in){    std::stringstream bob;    bob<<in;    return bob.str();}std::string  v3str(vec3 in){    std::string ret = "";    ret+=fstr(in.x);    ret+=" ";    ret+=fstr(in.y);    ret+=" ";    ret+=fstr(in.z);    return ret;}int  numwords(std::string in){    int count = 0;    int offset = 0;    bool goon = true;    while(goon)    {   int pos = in.find(" ",offset);   if((unsigned)pos != std::string::npos)   {  count++;  offset = pos+1;   }   else  break;    }    return count+1;}string sbws(string in){    for(int i = 0; i<(int)in.length()-1; i++)    {    if(in.substr(0,1) == " ")    in = in.substr(1,in.length()-1);    else    break;    }    return in;}std::string getword(std::string in,int word){    int count = 0;    int offset = 0;    int begw = 0,endw = 0;    bool goon = true;    while(goon)    {   int pos = in.find(" ",offset);   if((unsigned)pos != std::string::npos)   {  offset = pos+1;  if(count == word-1)  { begw = offset-1;  }  if(count == word)  { endw = offset-1; break;  }  count++;   }   else  break;    }    return sbws(in.substr(begw,endw-begw));}int sideofslash(string in,bool side){    int spos = in.find("/");    if(spos == (int)string::npos)    return atoi(in.c_str());    int length = in.length();    string side1 = in.substr(0,spos);    string side2 = in.substr(spos,length-spos);    if(side)   return atoi(side1.c_str());    else   return atoi(side2.c_str());}void  globjfaces::readin(char *filename){    std::string line;    ifstream infile(filename);    while(!infile.eof())    {  getline(infile,line);  if(numwords(line) > 1)  { if(getword(line,0) == "v") { vec3 tmp; tmp.x = atof(getword(line,1).c_str()); tmp.y = atof(getword(line,2).c_str()); tmp.z = atof(getword(line,3).c_str()); vectors[verts] = tmp; verts++; } if(getword(line,0) == "f") { for(int i = 1; i<numwords(line); i++) {facevector[fv] = vectors[sideofslash(getword(line,i),true)];fv++; } }  }    }}void globjfaces::show(int x,int y,int z){   glBegin(GL_POLYGON);   for(int i = 0; i<fv; i++)   {  glVertex3f(x+facevector.x, y+facevector.y,  z+facevector.z);   }   glEnd();}#endif // __MAIN_H__Now, here is a picture of a corn stalk model shown in blender, and in game, for an understanding on how badly it messes certain things up but not others: