scanf/fscanf problem with an OBJ reader

Member
Posts: 281
Joined: 2009.04
Post: #1
I'm writing a model loader for my 3D OpenGL written in C, but I can't get it to work.

The OBJ is listed as

Code:
# comment
v 1.0345 2.434 0.342
v 0.4435 0.234 1.240
Here's the code:
Code:
if ( fscanf(objfile,"%s %f %f" , &fchar) != 1 )


After I run, I get the gdb. It tells me this line is faulty, but I can't see why. scanf (and fscanf) return integers (1), the number of strings matching the layout in the format string, this way I can tell if the line is a comment (just a string) or a proper line (char, then three decimals (floats?). )

Thanks

Huh

~ Bring a Pen ~
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #2
You need to pass a corresponding pointer in the fscanf parameter list for each conversion specified in your format string. In your case, you're matching char *, float *, float *, but only providing one of those. If you compile with -Wall in your compiler warning flags, it'll tell you about these errors at compile time.
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #3
Ohh, so I have to supply more parameters...

Is this right?
Code:
if ( fscanf(objfile,"%s %f %f %f" , &fchar, &xvar, &yvar , &zvar) != 1 )

?

~ Bring a Pen ~
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #4
mikey Wrote:Ohh, so I have to supply more parameters...

Is this right?
Code:
if ( fscanf(objfile,"%s %f %f %f" , &fchar, &xvar, &yvar , &zvar) != 1 )

?

You can double check against the manual page. Open Terminal.app and type man scanf

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #5
So, that's a ... yes?

~ Bring a Pen ~
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #6
No, wait...

It still doesn't work. I can't see why not!?!
(I am not using OBJ-style commenting, so I felt it'd be proper to give the model it's own file format.)

Code:
    FILE * objfile;
    
    objfile = fopen("Laser Carbine.eobj" , "r");

    while ( fscanf(objfile," %s ", &line  ) != EOF) { // while we've not reached End of File

        float xc; // x vertex coordinate (I'm going to put all 3 (x,y,z) in an array?
        float yc; // y vertex coordinate
        float zc; // z vertex coordinate
        
        if ( fscanf(objfile,"%s %f %f" , &fchar, &xc, &yc, &zc ) != 1 ) // if the line follows a pattern of string decimal decimal decimal (It's not a comment )
        {
        
            printf("( %s )", &fchar); // prints the 'thing' , whether it's a '#' or a 'v' or a 'f'.
            }
    
    }

This code doesn't return comments, but only returns the first (x) coordinate in each line.
Please help.

~ Bring a Pen ~
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #7
how about: while(!feof(objfile))

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #8
OK thanks unknown, I've got that part of the OBJ Loader working, so how do I actuallly draw the vertices? Should I (or could I) store them as 3 arrays:

Code:
int x[];
int y[];
int z[];


...Then? Wouldn't 3 arrays of 1000+ be overkill? Is there an easier way? Huh

EDIT: Could I use one 3*dynamic array for the whole model?

~ Bring a Pen ~
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #9
You can use malloc to create the arrays and read the vertices into them, then make a display list by drawing the triangles with opengl and then free the arrays (so the memory can be reused for something else).

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #10
What's a display list? Because I need to redraw the model every frame, I'd need to store the arrays somehow?

~ Bring a Pen ~
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #11
You *can* use display lists, but I wouldn't recommend it since VBOs are preferred now, and display lists will be going away in future versions of OpenGL. Instead, what you should do is learn how to use glDrawArrays first. Once you learn how to use glDrawArrays it'll be much easier to see how you need to organize the data you're loading from your obj file. Don't try to learn glDrawArrays at the same time as figuring out how to load .obj though, since that'll just complicate matters.
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #12
mikey Wrote:What's a display list? Because I need to redraw the model every frame, I'd need to store the arrays somehow?

opengl.org has various infos, http://www.opengl.org/resources/faq/tech...aylist.htm

AnotherJake Wrote:display lists will be going away in future versions

Yikes! That sucks.

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #13
OK then, I won't use display lists, I'll use glDrawArrays. How would I do this?

I think I've mastered file I/O for now.

PS. I'm using GLUT.

~ Bring a Pen ~
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #14
You really should read the Red Book or some other authoritative source for learning how to use glDrawArrays. Getting answers only from forum folks such as us isn't ideal Wink

That said, here are the "Cliff's Notes" on how to use glDrawArrays:

To set up your data, you just need some arrays, like here are two arrays initialized on the spot, one for texture coordinates and one for vertices. There are enough in each to make up a quad:

Code:
GLushort    myTexCoords[] = {  0,  0,
      1,  0,
      0,  1,
      1,  1 };
GLfloat        myVerts[] = {    -0.5f,  -0.5f,
     0.5f,  -0.5f,
     -0.5f,  0.5f,
      0.5f,  0.5f };

You could just as well make up your arrays by loading them from a file.

To actually make use of them, you must first enable all the required client states you will be using to draw your object. You will always want to use vertices, and you might want to use normals, texture coordinates, or even vertex colors. So always call:

glEnableClientState(GL_VERTEX_ARRAY);

Then you might also want to call these, depending on your needs:

glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

Then you need to set the pointer for each type of array, like so:

glVertexPointer(3, GL_FLOAT, 0, myVerts);

and also others as needed:

glNormalPointer(GL_FLOAT, 0, myNormals);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, myColors);
glTexCoordPointer(2, GL_SHORT, 0, myTexCoords);

Then, when you're ready to draw you simply call glDrawArrays, perhaps like so for the equivalent of a quad using a triangle strip instead of GL_QUADS:

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);


For an actual example this in use, see that old example I gave you for drawing a cube a while back: here's the post
Quote this message in a reply
Member
Posts: 281
Joined: 2009.04
Post: #15
OK, does it matter if I call
Code:
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
and don't use them all?

And I should call everything bar drawArrays in init()? (Once in a program)?

Thanks much.

PS.
Quote:Cliff's Notes
. Don't remind me of that time my english teacher caught me out... BlushRasp

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