scanf/fscanf problem with an OBJ reader

Moderator
Posts: 3,573
Joined: 2003.06
Post: #16
Don't enable client states that you aren't using; doing so is a pretty good way to produce a crash. I don't know the specific details for sure, but presumably if the GL is expecting a pointer to be set for a given array and that pointer is invalid then obviously something is likely to go terribly wrong.

That said, if you're using glDrawArrays, then you'll at least need to have the vertex pointer set, so that one can be left on at init. Likewise, if you know for a fact that all of your geometry throughout the entire program will be using texture coordinates then you can leave that on at init too (same for the other client states). However, it is unlikely you'll use normals for everything in any given program.

In a situation where you will be drawing an object with normals and then another without you would first glEnableClientState(GL_NORMAL_ARRAY); for that object using normals, then turn it off after you've drawn it by calling glDisableClientState(GL_NORMAL_ARRAY); ... Again, same for other client states -- switch them on and off as needed. Obviously fewer calls help performance, but I would say that it's usually better to be safe than sorry, especially when in doubt.
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #17
EDIT: Nope, still nothing.

Code:
GLushort laserCarbineVertices[100000000];

int numbervertices;

Code:
void     drawPlayer(void)
{
    
    //glLoadIdentity();
    glPushMatrix();
    
    //glLoadIdentity();
    //glTranslatef( xp,5.0f,zp+5);
    
    
    //glRotatef(-pitch,1.0f,0.0f,0.0f);
    
    if (firing == 1)
    {
        
        
        // player model changes when firing //  
        
        
    }


    
        //glTranslatef(2.0f,-1.0f,0.0f );
    
    
    //glRotatef(-heading,0.0f,1.0f,0.0f);
    //glRotatef(pitch,0.0f ,0.0f,1.0f);
    
    // WE"LL REPLACE THIS WITH AN .OBJ LOADER.
    
    
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 100000 );

    glPopMatrix();

    
}

Code:
// main()
glEnableClientState(GL_VERTEX_ARRAY);
    


    
    glVertexPointer(3, GL_FLOAT, 0, laserCarbineVertices);
    
    
    // m0dels
    FILE * objfile;
    
    objfile = fopen("Laser Carbine.obj" , "r");
    numbervertices = 0;
    
    while(!feof(objfile)) {
    
    
        float xc;
        float yc;
        float zc;
        
        if ( fscanf(objfile,"%s %f %f" , &fchar, &xc, &yc, &zc ) != 1 )
        {
            
        
            if (strcmp( &fchar,"v"))
            {
                laserCarbineVertices[numbervertices] = xc;
                laserCarbineVertices[numbervertices+1] = yc;
                laserCarbineVertices[numbervertices+2] = zc;
            }
        // printf("| %s |",&line);
        
         numbervertices += 3;

            //printf(" %s " , &line);
    
        }    
    }

~ Bring a Pen ~
Quote this message in a reply
Moderator
Posts: 3,573
Joined: 2003.06
Post: #18
Code:
GLushort laserCarbineVertices[100000000];
Blink That's like 200 MB!!!

mikey Wrote:EDIT: Nope, still nothing.

Of course not. Unfortunately, loading obj isn't anywhere near as simplistic as you think. You can't just load the data directly into an array and expect things to work.

When I say "line" in what follows, I mean a line of text as loaded from the obj file: The obj file has vertex lines, normal lines, texture coordinate lines, and face lines, and some other stuff too (the other stuff can usually be ignored). At the very least, you will need to load all the vertex lines into memory first. Then you can read all the face lines and construct your real array of vertices from the vertex lines indicated by those faces. The face lines are indices into the verts, normals, and tex coords, and are all mixed up so as to reuse data in the file to save space. You have to essentially "unpack" the obj file to actually use it, which is why it isn't as easy as just loading the file straight into memory and letting it rock.

Learning how to load an obj file is going to be quite a challenge for you. Probably worth the adventure though, and it makes OpenGL much more useful when you can load 3D models. However, I should point out that even many experienced developers choke on trying to load an obj file, so it's really not a no-brainer. To make matters worse, the files are rarely consistent coming from different programs.

Best thing to do is start off by reading about obj files.
Quote this message in a reply
Moderator
Posts: 3,573
Joined: 2003.06
Post: #19
I would also suggest starting by loading a simple obj first. Here's a cube for you to work with (in case you don't have an editor handy):
Code:
# WaveFront *.obj file (generated by Cheetah3D)

mtllib cube.mtl

g Box
v -0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v 0.500000 -0.500000 0.500000
v 0.500000 -0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000

vt 0.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000
vt 1.000000 0.000000

vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 -1.000000
vn -1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 -1.000000 0.000000

usemtl Material
f 4/4/1 3/3/1 2/2/1 1/1/1
f 8/4/2 7/3/2 6/2/2 5/1/2
f 1/4/3 2/3/3 7/2/3 8/1/3
f 5/4/4 6/3/4 3/2/4 4/1/4
f 3/4/5 6/3/5 7/2/5 2/1/5
f 5/4/6 4/3/6 1/2/6 8/1/6

usemtl default
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #20
Quote:That's like 200 MB!!!
I know, I couldn't count the number of 'v''s (v's?) in the OBJ. I still don't see the connection between the faces and the vertices?

Is it worth creating my own file format that just contains vertices? would that work?

~ Bring a Pen ~
Quote this message in a reply
Moderator
Posts: 3,573
Joined: 2003.06
Post: #21
mikey Wrote:I know, I couldn't count the number of 'v''s (v's?) in the OBJ. I still don't see the connection between the faces and the vertices?
Right. You'll have to figure out how the faces and vertices connect before you can do that too. That's why I suggest reading up on obj files before going any further with them for now.

mikey Wrote:Is it worth creating my own file format that just contains vertices? would that work?
Sure! Nothing wrong with that. The only problem is that you'll obviously have to make the file by hand by specifying the verts yourself, but otherwise it'll work just fine. Besides, it can be fun, although tedious, to create your own models that way.
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #22
Hmmm. How about this:

I create my own file format, then write an applescript/C miniprogram that converts OBJ to it. That should (?) work, and if that works, I could include that miniprogram in my game?

~ Bring a Pen ~
Quote this message in a reply
Moderator
Posts: 3,573
Joined: 2003.06
Post: #23
Converting obj to your own file format is sensible, but it would still require you to understand the obj file format to create a script to convert it to your own model format.
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #24
I highly recommend making your own model format, that you can just load in as a vertex array.

Loading .objs is fine for prototyping, but why would you waste disk space or CPU time parsing text files when your customers launch your app? After your models are finalized, convert them to a simple binary format that you load directly into a VBO.

Even better is to procedurally generate your geometric data, so you don't spend any time loading from disk. Of course that's only easy for fairly simple geometric shapes.
Quote this message in a reply
Moderator
Posts: 3,573
Joined: 2003.06
Post: #25
Using your own file format that you can load directly into an array is definitely the best thing to do, but the problem here is that one needs to know where to get the model data from in the first place. You can't expect any 3D editor out there to know how to export to your own model format, so you'll either have to write an exporter for it (via script if available or API if available), or you'll have to convert from an existing format such as .obj. OR you'll have to write your model data by hand, which is not practical for anything but the simplest of models.

One exception to this is that Cheetah3D has a .h export which would allow you to compile the model right into your program in a format which is already compatible with glDrawElements. The drawback being that that's all it does, and lacks flexibility like specifying what texture(s) to use, etc.

So practically speaking, learning how to either load or convert .obj is a good place to start.
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #26
Oh dear... I stupidly lost my code and it won't work. Something about this line, i think:
Code:
if ( fscanf(objfile,"%s %f %f" , &fchar, &xc, &yc, &zc ) != 1 )

***

Anyway, so, what would be the next step in loading my OBJ, the faces? How would I do that?

~ Bring a Pen ~
Quote this message in a reply
Member
Posts: 59
Joined: 2007.12
Post: #27
The OBJ file format is just fine. You're pretty close to getting it to work. Having your own file format can be a bit tedious because you have to convert all the models first even when making slight changes.

I recommend you putting the vertices in std:vectors. This way the array scales automatically, and if you later want to switch to glDrawArrays, they are continuous in memory, too. I'd say that it will be a lot simpler to get the model to draw with OpenGL immediate mode (unless you're developing for the iPhone). You can still later switch to faster drawing methods.

edit: you can put the faces in std:vectors, too. The loading is just the same. The drawing can then go something like this:
Code:
for all faces:
    if this is a triangle, draw a triangle, else draw a quad.
    for all vertices that correspond to this face:
        draw vertex at x, y, z.
    next
next
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #28
Thanks, but is std:vectors C++ only? Did I forget to mention I'm using C?

~ Bring a Pen ~
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #29
mikey Wrote:Thanks, but is std:vectors C++ only?

Yes. You can create a dynamically-sized array in C by keeping track of its allocated size, adjusting it as necessary when you want to add an item to the array (I like to start with one element and double the size each time I go over, but there may be more optimal approaches for your particular situation), and call realloc() to resize the array. For example:

Code:
GLfloat * myArray = NULL;
size_t myArraySize = 1;
size_t myArrayCount = 0;

// Create array
myArray = malloc(sizeof(GLfloat) * myArraySize);

// Add item to array
if (myArrayCount >= myArraySize) {
  myArraySize *= 2;
  myArray = realloc(myArray, sizeof(GLfloat) * myArraySize);
}
myArray[myArrayCount++] = item;
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #30
OK thanks, I think I get it, but I get errors:

Code:
            if (myArrayCount >= myArraySize) {
                    myArraySize *= 2;
                    laserCarbineVertices = realloc(laserCarbineVertices, sizeof(GLfloat) * myArraySize);
// ERROR: Passing argument 1 of realloc makes pointer form integer without a cast
                }
                
                
                
                laserCarbineVertices[myArrayCount] = xc;
// ERROR : Subscripted value is neither array nor pointer

                laserCarbineVertices[myArrayCount+1] = yc;
// ERROR : Subscripted value is neither array nor pointer
                laserCarbineVertices[myArrayCount+2] = zc;
// ERROR : Subscripted value is neither array nor pointer

...and...
Code:
GLfloat * laserCarbineVertices = NULL;



size_t myArraySize = 1;
size_t myArrayCount = 0;

laserCarbineVertices = malloc(sizeof(GLfloat) * myArraySize);
// Conflicting types for laserCarbineVertices
// initilizer element is not constant.

~ Bring a Pen ~
Quote this message in a reply
Post Reply