Thread: OpenGL VBO

  1. #1
    Registered User Frobozz's Avatar
    Join Date
    Dec 2002
    Posts
    546

    OpenGL VBO

    I've been working on a Mesh class that loads and renders Wavefront Studio OBJ files. And I've gotten it to correctly load the data and seemingly correctly insert it into a VBO. But I can't get it to render correctly. Everytime it calls glDrawArrays(), the window closes and the program crashes.

    After a few hours of fiddling around and rewriting it different ways, I thought I'd upload it here and see what stupid thing I'm doing wrong.

    Code:
    /*
     * Mesh class
     */
    #include <GL/glew.h>
    #include <GL/gl.h>
    #include <GL/glu.h>
    #include "SDL.h"
    #include "types.h"
    
    #ifndef __MESH_HEADER__
    #define __MESH_HEADER__
    
    class Mesh {
      public:
        Mesh();
        ~Mesh();
        
        int LoadOBJ(const char *filename);
        void Render();
        
      private:
        GLuint bufferID;
        GLuint bufferSize;
        GLuint normalOffset;
        GLuint textureOffset;
    };
    
    #endif
    Code:
    /*
     * Mesh class
     */
    #include <stdio.h>
    #include <vector>
    #include <GL/glew.h>
    #include <GL/gl.h>
    #include <GL/glu.h>
    #include "SDL.h"
    #include "mesh.h"
    #include "types.h"
    using namespace std;
    
    #define BUFFER_OFFSET(i) (((char *)NULL + (i)))
    
    // Determines the type of face being loaded from an OBJ file
    int GetFaceType(const char *buffer) {
      int count = 0;
      
      for (int index = 0; index < strlen(buffer); index++) {
        if (buffer[index] == '/') {
          if (buffer[index + 1] == '/')
            return VERTEX_NORMAL;
          else
            count++;
        }
      }
      
      switch (count) {
        case 3:
          return VERTEX_TEXTURE;
        
        case 6:
          return VERTEX_NORMAL_TEXTURE;
      }
      
      return VERTEX_ONLY;
    };
    
    Mesh::Mesh() {
      // Enable vertex arrays
      glEnableClientState(GL_VERTEX_ARRAY);
      glEnableClientState(GL_NORMAL_ARRAY);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    };
    
    Mesh::~Mesh() {
      // Delete the VBOs, if needed
      if (bufferID) glDeleteBuffers(1, &bufferID);
    };
    
    int Mesh::LoadOBJ(const char *filename) {
      // Create vector buffers to hold vertex, normal, and texture data
      vector <Float3> vertexBuffer;
      vector <Float3> normalBuffer;
      vector <Float3> textureBuffer;
      vector <Face>   faceBuffer;
      
      // Try opening the desired file
      FILE *OBJFile = fopen(filename, "r");
      if (!OBJFile) {
        fprintf(stderr, "[MESH] Unable to load mesh named %s.\n", filename);
        return 1;
      }
      
      // Read in the object file
      char   buffer[255];
      int    facetype;
      Float3 tempFloat;
      Face   tempFace;
      
      while (fgets(buffer, 255, OBJFile) != NULL) {
        switch (buffer[0]) {
          case 'v':
            switch (buffer[1]) {
              case 'n': // Vertex normal
                sscanf(buffer, "vn  %f %f %f", &tempFloat.X, &tempFloat.Y, &tempFloat.Z);
                normalBuffer.push_back(tempFloat);
                break;
              case 't': // Vertex texture
                sscanf(buffer, "vt  %f %f %f", &tempFloat.X, &tempFloat.Y, &tempFloat.Z);
                textureBuffer.push_back(tempFloat);
                break;
              default: // Vertex
                sscanf(buffer, "v  %f %f %f", &tempFloat.X, &tempFloat.Y, &tempFloat.Z);
                vertexBuffer.push_back(tempFloat);
                break;
            }
            break;
          
          case 'f': // Face
            facetype = GetFaceType(buffer);
            switch (facetype) {
              case VERTEX_ONLY:
                sscanf(buffer, "f %d %d %d", &tempFace.Vertex.X, &tempFace.Vertex.Y, &tempFace.Vertex.Z);
                tempFace.FaceType = facetype;
                faceBuffer.push_back(tempFace);
                break;
              
              case VERTEX_NORMAL:
                sscanf(buffer, "f %d//%d %d//%d %d//%d", &tempFace.Vertex.X, &tempFace.Normal.X,
                                                         &tempFace.Vertex.Y, &tempFace.Normal.Y,
                                                         &tempFace.Vertex.Z, &tempFace.Normal.Z);
                tempFace.FaceType = facetype;
                faceBuffer.push_back(tempFace);
                break;
              
              case VERTEX_TEXTURE:
                sscanf(buffer, "f %d/%d %d/%d %d/%d", &tempFace.Vertex.X, &tempFace.Texture.X,
                                                      &tempFace.Vertex.Y, &tempFace.Texture.Y,
                                                      &tempFace.Vertex.Z, &tempFace.Texture.Z);
                tempFace.FaceType = facetype;
                faceBuffer.push_back(tempFace);
                break;
              
              case VERTEX_NORMAL_TEXTURE:
                sscanf(buffer, "f %d/%d/%d %d/%d/%d %d/%d/%d", &tempFace.Vertex.X, &tempFace.Texture.X, &tempFace.Normal.X,
                                                               &tempFace.Vertex.Y, &tempFace.Texture.Y, &tempFace.Normal.Y,
                                                               &tempFace.Vertex.Z, &tempFace.Texture.Z, &tempFace.Normal.Z);
                tempFace.FaceType = facetype;
                faceBuffer.push_back(tempFace);
                break;
              
              default:
                break;
            }
            break;
          
          default:
            break;
        }
      }
      
      // Close the file
      fclose(OBJFile);
      
      // Process the data into arrays
      GLuint  vertexArraySize = 0;
      GLuint  normalArraySize = 0;
      GLuint  textureArraySize = 0;
      GLfloat vertexArray[faceBuffer.size() * 3];
      GLfloat normalArray[faceBuffer.size() * 3];
      GLfloat textureArray[faceBuffer.size() * 3];
      
      for (int index = 0; index < faceBuffer.size(); index++) {
        vertexArray[index]     = faceBuffer.at(index).Vertex.X;
        vertexArray[index + 1] = faceBuffer.at(index).Vertex.Y;
        vertexArray[index + 2] = faceBuffer.at(index).Vertex.Z;
        vertexArraySize++;
        
        switch (faceBuffer.at(index).FaceType) {
          case VERTEX_NORMAL:
            normalArray[index]     = faceBuffer.at(index).Normal.X;
            normalArray[index + 1] = faceBuffer.at(index).Normal.Y;
            normalArray[index + 2] = faceBuffer.at(index).Normal.Z;
            normalArraySize++;
            break;
          
          case VERTEX_TEXTURE:
            textureArray[index]     = faceBuffer.at(index).Texture.X;
            textureArray[index + 1] = faceBuffer.at(index).Texture.Y;
            textureArray[index + 2] = faceBuffer.at(index).Texture.Z;
            textureArraySize++;
            break;
          
          case VERTEX_NORMAL_TEXTURE:
            normalArray[index]      = faceBuffer.at(index).Normal.X;
            normalArray[index + 1]  = faceBuffer.at(index).Normal.Y;
            normalArray[index + 2]  = faceBuffer.at(index).Normal.Z;
            textureArray[index]     = faceBuffer.at(index).Texture.X;
            textureArray[index + 1] = faceBuffer.at(index).Texture.Y;
            textureArray[index + 2] = faceBuffer.at(index).Texture.Z;
            normalArraySize++;
            textureArraySize++;
            break;
        }
      }
      
      bufferSize    = faceBuffer.size();
      normalOffset  = vertexArraySize;
      textureOffset = vertexArraySize + normalArraySize;
      
      // Generate and feed the data into the VBO
      glGenBuffers(1, &bufferID);
      glBindBuffer(GL_ARRAY_BUFFER, bufferID);
      glBufferData(GL_ARRAY_BUFFER, bufferSize * sizeof(GLfloat) * 3, NULL, GL_STATIC_DRAW);
      
      glBufferSubData(GL_ARRAY_BUFFER, 0, vertexArraySize * sizeof(GLfloat), vertexArray);
      glBufferSubData(GL_ARRAY_BUFFER, normalOffset, normalArraySize * sizeof(GLfloat), normalArray);
      glBufferSubData(GL_ARRAY_BUFFER, textureOffset, textureArraySize * sizeof(GLfloat), textureArray);
    };
    
    void Mesh::Render() {
      // Render the contents of the VBO
      glBindBufferARB(GL_ARRAY_BUFFER, bufferID);
        glVertexPointer(3, GL_FLOAT, 0, 0);
        glNormalPointer(GL_FLOAT, normalOffset, 0);
        glTexCoordPointer(3, GL_FLOAT, textureOffset, 0);
      glDrawArrays(GL_TRIANGLES, 0, bufferSize);
    };

  2. #2
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Vertex arrays and VBO's seem to be my bane as well, sorry I can't provide much help.

    But the problem you've described sounds like your accessing a null pointer, make sure in debug mode you're filling your VBO's properly and whatnot.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  3. #3
    Registered User Frobozz's Avatar
    Join Date
    Dec 2002
    Posts
    546
    Yeah that sounds like the culprit. Its code like this that really makes me want to purchase a premade engine.

  4. #4
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Tell me about it, 3d programming is rough.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  5. #5
    Registered User Frobozz's Avatar
    Join Date
    Dec 2002
    Posts
    546
    I think I'm going to rewrite what little my engine consists of from scratch - have the mesh class consist of just the parts that handle storing, rendering, and maybe animating of meshes. Then spread out other functions to other classes. Like a MeshLoader class.
    Last edited by Frobozz; 06-17-2006 at 10:47 PM.

  6. #6
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    To handle your loading try a resource manager, I can help you in creating one if you wish, and I'm sure Bubba will throw in his ideas as well, two different ideas but both perfectly valid.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Linking OpenGL in Dev-C++
    By linkofazeroth in forum Game Programming
    Replies: 4
    Last Post: 09-13-2005, 10:17 AM
  2. OpenGL Window
    By Morgul in forum Game Programming
    Replies: 1
    Last Post: 05-15-2005, 12:34 PM
  3. OpenGL .dll vs video card dll
    By Silvercord in forum Game Programming
    Replies: 14
    Last Post: 02-12-2003, 07:57 PM
  4. OpenGL and Windows
    By sean345 in forum Game Programming
    Replies: 5
    Last Post: 06-24-2002, 10:14 PM
  5. opengl code not working
    By Unregistered in forum Windows Programming
    Replies: 4
    Last Post: 02-14-2002, 10:01 PM