Obj loader problems

Moderator
Posts: 102
Joined: 2003.07
Post: #1
I am writing an obj loader / camera control demo and I am having a major problem with it crashing, it says in the debugger that it can't access memory at 0x7...
here is all of the relevant code:
Code:
- (void) loadObject: (NSString*) name Texture: (NSString*) texture Scale: (float) scale NormalType: (int) normalType
{
    FILE    *objFile;
    float x,y,z;
    float t1, t2, t3;
    int iV1, iV2, iV3, iV4, iN1, iN2, iN3, iN4, iT1, iT2, iT3, iT4;
    
    objFile = fopen([name UTF8String], "rt");
        if (objFile == nil) NSLog(@" there is no file to load ");
        
        int numParts = -1;
        int h = -1;
        
        NSString* fileString = [NSString stringWithContentsOfFile: name];
        NSArray*  fileArray     = [fileString componentsSeparatedByString: @"\n"];
        
        //NSLog(@"Loading .obj model: %@", name);
        //NSLog([fileArray description]);
        
        unsigned int i;
        for (i = 0; i < [fileArray count]; i++)
        {
            const char *oneline = [[fileArray objectAtIndex:i] UTF8String];
            printf("%s\n", oneline);
            char materialNameString[50];
            if (sscanf(oneline, "mtllib %s", materialNameString) == 1)
            {
                //printf("%s\n", materialNameString);
                numParts++;
                h++;
                printf("%d\n", h);
                theObject[h] = (OBJECT*)malloc(sizeof(OBJECT));
                theObject[h]->numVerticies = theObject[h]->startVerticies = theObject[h-1]->numVerticies;
                theObject[h]->numTextures = theObject[h]->startTextures = theObject[h-1]->numTextures;
                theObject[h]->numNormals = theObject[h]->startNormals = theObject[h-1]->numNormals;
                theObject[h]->numTriangles = theObject[h]->startTriangles = theObject[h-1]->numTriangles;
                theObject[h]->numQuads = theObject[h]->startQuads = theObject[h-1]->numQuads;
                
                theObject[h]->maxVerticies.x = theObject[h]->maxVerticies.y = theObject[h]->maxVerticies.z = 0;
                theObject[h]->minVerticies.x = theObject[h]->minVerticies.y = theObject[h]->minVerticies.z = 0;
                
                theObject[h]->hasTextures = NO;
                theObject[h]->hasNormals = NO;
            }
            else if (sscanf(oneline, "v %f %f %f", &x, &y, &z) == 3)
            {
                x *= scale/100.0;
                y *= scale/100.0;
                z *= scale/100.0;
                
                theObject[h]->objVerts[theObject[h]->numVerticies].x = x;
                theObject[h]->objVerts[theObject[h]->numVerticies].y = y;
                theObject[h]->objVerts[theObject[h]->numVerticies].z = z;
            
                theObject[h]->origin.x += x;
                theObject[h]->origin.y += y;
                theObject[h]->origin.z += z;
            
                theObject[h]->numVerticies++;
                
                if (x > theObject[h]->maxVerticies.x)
                    theObject[h]->maxVerticies.x = x;
                if (y > theObject[h]->maxVerticies.y)
                    theObject[h]->maxVerticies.y = y;
                if (z > theObject[h]->maxVerticies.z)
                    theObject[h]->maxVerticies.z = z;
                if (x < theObject[h]->minVerticies.x)
                    theObject[h]->minVerticies.x = x;
                if (y < theObject[h]->minVerticies.y)
                    theObject[h]->minVerticies.y = y;
                if (z < theObject[h]->minVerticies.z)
                    theObject[h]->minVerticies.z = z;
                    
                NSLog(@"Loaded Vertex: %f %f %f", x, y, z);
            }
            else if (sscanf(oneline, "vt %f %f %f", &t1, &t2, &t3) == 3)
            {
                theObject[h]->objTexts[theObject[h]->numTextures].u = t1;
                theObject[h]->objTexts[theObject[h]->numTextures].v = t2;
                theObject[h]->objTexts[theObject[h]->numTextures].w = t3;
                theObject[h]->numTextures++;
                theObject[h]->hasTextures = true;
            }
            else if (sscanf(oneline, "vt %f %f", &t1, &t2) == 2)
            {
                theObject[h]->objTexts[theObject[h]->numTextures].u = t1;
                theObject[h]->objTexts[theObject[h]->numTextures].v = t2;
                theObject[h]->objTexts[theObject[h]->numTextures].w = 0.0;
                theObject[h]->numTextures++;
                theObject[h]->hasTextures = true;
            }
            else if (sscanf(oneline, "vn %f %f %f", &x, &y, &z) == 3)
            {
                theObject[h]->objNorms[theObject[h]->numNormals].x = x;
                theObject[h]->objNorms[theObject[h]->numNormals].y = y;
                theObject[h]->objNorms[theObject[h]->numNormals].z = z;
                theObject[h]->numNormals++;
                theObject[h]->hasNormals = true;
                NSLog(@"Loaded Normal: %f %f %f", x, y, z);
            }
            else if (sscanf(oneline, "f %d//%d %d//%d %d//%d %d//%d", &iV1, &iN1, &iV2, iN2, &iV3, &iN3, &iV4, &iN4) == 8)
            {
                NSLog(@"Loading Face: %d, %d, %d, %d", iV1, iV2, iV3, iV4);
                NSLog(@"%d", theObject[h]->numQuads);
                theObject[h]->objQuads[theObject[h]->numQuads].v1 = iV1;
                theObject[h]->objQuads[theObject[h]->numQuads].v2 = iV2;
                theObject[h]->objQuads[theObject[h]->numQuads].v3 = iV3;
                theObject[h]->objQuads[theObject[h]->numQuads].v4 = iV4;
                theObject[h]->objQuads[theObject[h]->numQuads].t1 = -1;
                theObject[h]->objQuads[theObject[h]->numQuads].t2 = -1;
                theObject[h]->objQuads[theObject[h]->numQuads].t3 = -1;
                theObject[h]->objQuads[theObject[h]->numQuads].t4 = -1;
                theObject[h]->objQuads[theObject[h]->numQuads].n1 = iN1;
                theObject[h]->objQuads[theObject[h]->numQuads].n2 = iN2;
                theObject[h]->objQuads[theObject[h]->numQuads].n3 = iN3;
                theObject[h]->objQuads[theObject[h]->numQuads].n4 = iN4;
                theObject[h]->numQuads++;
                NSLog(@"Finished Loading Face");
            }
            else if (sscanf(oneline, "f %d//%d %d//%d %d//%d", &iV1, &iN1, &iV2, &iN2, iV3, iN3) == 6)
            {
                theObject[h]->objTngls[theObject[h]->numTriangles].v1 = iV1;
                theObject[h]->objTngls[theObject[h]->numTriangles].v2 = iV2;
                theObject[h]->objTngls[theObject[h]->numTriangles].v3 = iV3;
                theObject[h]->objTngls[theObject[h]->numTriangles].t1 = -1;
                theObject[h]->objTngls[theObject[h]->numTriangles].t2 = -1;
                theObject[h]->objTngls[theObject[h]->numTriangles].t3 = -1;
                theObject[h]->objTngls[theObject[h]->numTriangles].n1 = iN1;
                theObject[h]->objTngls[theObject[h]->numTriangles].n2 = iN2;
                theObject[h]->objTngls[theObject[h]->numTriangles].n3 = iN3;
                theObject[h]->numTriangles++;
            }
    }
    fclose(objFile);
}


and here is the header with the object struct in it

Code:
typedef struct _VERTEX
{    GLfloat x,y,z; } VERTEX;

typedef struct _TEXCOORD
{    GLfloat u,v,w; } TEXCOORD;

typedef struct _FACE
{    
    int v1, v2, v3, v4;
    int t1, t2, t3, t4;
    int n1, n2, n3, n4;
} FACE;

typedef struct _OBJECT
{
    TEXCOORD    objTexts[MAX_VERTICIES];
    VERTEX        objNorms[2 * MAX_FACES];
    VERTEX        objVerts[MAX_VERTICIES];
    FACE        objTngls[MAX_FACES];
    FACE        objQuads[MAX_FACES];
    
    VERTEX        origin;
    
    int numVerticies;
    int numTextures;
    int numNormals;
    int numTriangles;
    int numQuads;
    
    int startVerticies;
    int startTextures;
    int startNormals;
    int startTriangles;
    int startQuads;
    
    bool hasTextures;
    bool hasNormals;
    
    float radius;
    
    VERTEX maxVerticies;
    VERTEX minVerticies;
} OBJECT;

I can't for the life of me figure out why it is crashing, it finishes loading all of the faces of my cube and then crashes, I can't really pinpoint where it crashes either, the debugger doesn't give me any hints... Please help me!

-CarbonX
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #2
Have you tried bracketing places of your code with NSLogs or printf's to find out where it crashes?

...code...
printf( "Made it to here 1" );
...code...
printf( "Made it to here 2" );

And so on? What you're showing is a lot of code to parse through for bugs, it would help to get a more localized area of malfunction. printf's are a great way to do that.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #3
Never mind. I just noticed you have a lot of that in there already.

I ran your code on my machine and it appears to have loaded a cube just fine without crashing. Hmm...
Quote this message in a reply
Moderator
Posts: 102
Joined: 2003.07
Post: #4
yeah, it only kinda seems to be a problem with the loader, but I suspect the loader more than anything because it only crashes when the face loading code is in there, if I comment that out it doesn't crash anymore... very strange

but... when the face loading code is in there it finishes loading all of the faces when it crashes.

it may be a side effect of another problem I have uncovered, the first item in the OBJECT struct is "corrupt" or causes a crash when it is written to... I can't figure out why that would happen either.

here is a link to the entire source file and it's header so you can run it on your machine: Source

-CarbonX
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #5
Wow. There is definitely something seriously wrong with your program. I don't get a crash but the GL context doesn't draw and the program is barely responding after any GL calls in the drawing loop! I've been messing around with it for a bit now and it's not readily apparent as to what is causing all the havoc but I'll keep looking for a while. I'm pretty sure this is a GL problem but I could be wrong.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #6
Well, I'm still mystified as to why this is all happening but I think I may have found your crash. I commented the lines with the problems and the fix notes are below the code snippet.
Code:
else if (sscanf(oneline, "f %d//%d %d//%d %d//%d %d//%d", &iV1, &iN1, &iV2, iN2, &iV3, &iN3, &iV4, &iN4) == 8) // prob here
{
    NSLog(@"Loading Face: %d, %d, %d, %d", iV1, iV2, iV3, iV4);
    NSLog(@"%d", theObject[h]->numQuads);
    theObject[h]->objQuads[theObject[h]->numQuads].v1 = iV1;
    theObject[h]->objQuads[theObject[h]->numQuads].v2 = iV2;
    theObject[h]->objQuads[theObject[h]->numQuads].v3 = iV3;
    theObject[h]->objQuads[theObject[h]->numQuads].v4 = iV4;
    theObject[h]->objQuads[theObject[h]->numQuads].t1 = -1;
    theObject[h]->objQuads[theObject[h]->numQuads].t2 = -1;
    theObject[h]->objQuads[theObject[h]->numQuads].t3 = -1;
    theObject[h]->objQuads[theObject[h]->numQuads].t4 = -1;
    theObject[h]->objQuads[theObject[h]->numQuads].n1 = iN1;
    theObject[h]->objQuads[theObject[h]->numQuads].n2 = iN2;
    theObject[h]->objQuads[theObject[h]->numQuads].n3 = iN3;
    theObject[h]->objQuads[theObject[h]->numQuads].n4 = iN4;
    theObject[h]->numQuads++;
    NSLog(@"Finished Loading Face");
}
else if (sscanf(oneline, "f %d//%d %d//%d %d//%d", &iV1, &iN1, &iV2, &iN2, iV3, iN3) == 6) // prob here
sscanf(oneline, "f %d//%d %d//%d %d//%d %d//%d", &iV1, &iN1, &iV2, iN2, &iV3, &iN3, &iV4, &iN4)
iN2 should be &iN2

sscanf(oneline, "f %d//%d %d//%d %d//%d", &iV1, &iN1, &iV2, &iN2, iV3, iN3)
iV3 and iN3 should be &iV3 and &iN3

Now, as for the response problem I was having earlier: I don't know why but initWithFrame: (NSRect) frameRect was not getting called. But reshape was, go figure. I set the custom class correctly in the nib file so I have no idea wtf this is all about. I finally copied everything into a known working project I had laying around and everything worked fine.

But get this: The pointer syntax errors on those two lines above did not and still do not show up in the warnings in the original project after a build. I don't understand why it did not crash on me too, as those are definitely problems. I don't understand why they showed up only after I copied them into the known working project. Build settings are apparently the same too. Weirdo maaan...
Quote this message in a reply
kberg
Unregistered
 
Post: #7
Are you planning to group multiple OBJ meshes into a single file? Many obj files I've run into don't have or specify any mtllib file, and you're not doing any check to see whether or not a material file is specified before loading data into an object in your array... this could be the cause of your problems (if h = -1)?

Just a simplification comment... If you're not planning to do anything but display filled polygons (no wireframes), then there is no need to keep separate quad data structures around. In fact, by keeping an array of triangles, you can load polygons with arbitrary numbers of vertices from an obj file. Here's some c++ code to do so:

Code:
char* obj_readline(char *line, int len, FILE *in_file)
{
   char *temp = line;
   int   val, nxt;
   int   tok = -1;

   if (--len < 0)
      return NULL;

   if (len)
   {
      do
      {
         val = getc(in_file);
         if (tok == -1)
            tok = (val == 'f' || val == 'v') ? 0 : 1;
         nxt = getc(in_file);
         ungetc(nxt, in_file);

         if (val == EOF)
         {
            if (feof(in_file) && temp != line)
               break;
            else
            {
               line = NULL;
               return NULL;
            }
         }
         *temp++ = val;
      } while ((val != '\r' && val != '\n' && --len) && (tok || (nxt != 'o' && nxt != 'g' && nxt != 's' && nxt != 'f' && nxt != 'v')));
   }
   *temp = '\0';

   return line;
}


Code:
bool ParseFce(MT_Model *tDispObj, char *oneline, int &currGroup)
{
   char *currPtr;
   int   v, t, n;
   int   iV1 = 0, iV2 = 0, iV3 = 0;
   int   iT1 = 0, iT2 = 0, iT3 = 0;
   int   iN1 = 0, iN2 = 0, iN3 = 0;
   bool  fReady = false;

   currPtr = strtok(oneline, " ");
   while (currPtr != NULL)
   {
      if (sscanf(currPtr, "%d/%d/%d", &v, &t, &n) == 3)
      {
         if (iV1 == 0)
         {
            iV1 = v;
            iT1 = t;
            iN1 = n;
         }
         else if (iV2 == 0)
         {
            iV2 = v;
            iT2 = t;
            iN2 = n;
         }
         else
         {
            iV3 = v;
            iT3 = t;
            iN3 = n;
            fReady = true;
         }
      }
      else if (sscanf(currPtr, "%d//%d", &v, &n) == 2)
      {
         if (iV1 == 0)
         {
            iV1 = v;
            iT1 = 0;
            iN1 = n;
         }
         else if (iV2 == 0)
         {
            iV2 = v;
            iT2 = 0;
            iN2 = n;
         }
         else
         {
            iV3 = v;
            iT3 = 0;
            iN3 = n;
            fReady = true;
         }
      }
      else if (sscanf(currPtr, "%d/%d", &v, &t) == 2)
      {
         if (iV1 == 0)
         {
            iV1 = v;
            iT1 = t;
            iN1 = 0;
         }
         else if (iV2 == 0)
         {
            iV2 = v;
            iT2 = t;
            iN2 = 0;
         }
         else
         {
            iV3 = v;
            iT3 = t;
            iN3 = 0;
            fReady = true;
         }
      }
      else if (sscanf(currPtr, "%d", &v) == 1)
      {
         if (iV1 == 0)
         {
            iV1 = v;
            iT1 = 0;
            iN1 = 0;
         }
         else if (iV2 == 0)
         {
            iV2 = v;
            iT2 = 0;
            iN2 = 0;
         }
         else
         {
            iV3 = v;
            iT3 = 0;
            iN3 = 0;
            fReady = true;
         }
      }
      
      if (fReady)
      {
         tDispObj->polyCnt++;
         MT_Face *newFace = (MT_Face*)malloc(sizeof(MT_Face));
         newFace->next = NULL;

         newFace->v1 = (iV1 < 0) ? (tDispObj->vertCnt + iV1) : iV1 - 1;
         newFace->v2 = (iV2 < 0) ? (tDispObj->vertCnt + iV2) : iV2 - 1;
         newFace->v3 = (iV3 < 0) ? (tDispObj->vertCnt + iV3) : iV3 - 1;

         newFace->t1 = (iT1 < 0) ? (tDispObj->textCnt + iT1) : iT1 - 1;
         newFace->t2 = (iT2 < 0) ? (tDispObj->textCnt + iT2) : iT2 - 1;
         newFace->t3 = (iT3 < 0) ? (tDispObj->textCnt + iT3) : iT3 - 1;

         newFace->n1 = (iN1 < 0) ? (tDispObj->normCnt + iN1) : iN1 - 1;
         newFace->n2 = (iN2 < 0) ? (tDispObj->normCnt + iN2) : iN2 - 1;
         newFace->n3 = (iN3 < 0) ? (tDispObj->normCnt + iN3) : iN3 - 1;

         if (newFace->n1 == -1)
            newFace->NormType = 0;
         else
            newFace->NormType = 1;

         if (currGroup == -1)
            currGroup = tDispObj->numObjects;
         Insert_Face(&tDispObj->grp[currGroup], newFace);

         iV2 = iV3; iV3 = 0;
         iT2 = iT3; iT3 = 0;
         iN2 = iN3; iN3 = 0;

         fReady = false;
      }

      currPtr = strtok(NULL, " \n");
   }

   return true;
}


And then parsing faces in your main loop simplifies to:
Code:
while (!feof(in_file))
   {
      if (obj_readline(oneline, MT_StrSze, in_file) == NULL)
         break;

      if (strncmp(oneline, "mtllib", 6) == 0) {}
      if (strncmp(oneline, "usemtl", 6) == 0) {}
      //handle vertices, texture coords, normals, etc..
      else if (sscanf(oneline, "f %d", &v) == 1)
         ParseFce(tDispObj, oneline, currGroup);
   }

I've got a new object loader in the works that handles all this as well as static .3ds files. It's still under development, but I can link up complete source code if you want.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #8
AnotherJake Wrote:Now, as for the response problem I was having earlier: I don't know why but initWithFrame: (NSRect) frameRect was not getting called. But reshape was, go figure. I set the custom class correctly in the nib file so I have no idea wtf this is all about.
I'm a dummy, I forgot that the custom class must be set on an NSView, not an NSOpenGLView in IB.

Anyway, I should stress again that I haven't had ANY crashes with this code. It all seems to be working fine.

The warnings not showing up appears to be Xcode related. The older existing project that I pasted them into was a Project Builder project. I don't know why those warnings are not reported in Xcode. The Project Builder version also shows some unused variables. If anyone could shed some light on why there are differences in the warning reports I'd be interested.
Quote this message in a reply
Moderator
Posts: 102
Joined: 2003.07
Post: #9
kberg: I was just using that mtllib as a starting point because it's the first line in the file, I am going to change that as soon as I fix the problem...

anotherJake: I didn't even see that, thanks for pointing it out, I'll post again if that's what was causing the crash.

Thanks for the input everybody Smile

-CarbonX
Quote this message in a reply
Moderator
Posts: 916
Joined: 2002.10
Post: #10
post a screenshot of your amazingly awesome object you loaded!
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #11
CarbonX Wrote:anotherJake: I didn't even see that...
Neither did I until I accidentally pasted it into that old pbproj I was talking about. The pbproj build brought up the warnings, not me. I didn't get those in the Xcode build. This brings up a very interesting topic to me. Why in the pbproj and not in Xcode? Those were good warnings even if they weren't the bug.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Display Lists and Obj. File Loader Problems merrill541 0 1,982 Oct 17, 2008 06:42 PM
Last Post: merrill541