Thread: OpenGL VBO's

  1. #1
    Supermassive black hole cboard_member's Avatar
    Join Date
    Jul 2005
    Posts
    1,709

    OpenGL VBO's

    Ok, I'm reading and "following along" with the OpenGL SuperBible (4th), and I've hit VBO's. After a good 3 hours of going over it with a fine toothed (and very frustrated) comb, what I've got just doesn't work.

    I'm trying to render a single textured quad. Note that if I stop using a VBO and uncomment the immediate mode stuff, it all works fine.

    This is kinda big, please ignore the messiness, it's just a fiddle after all. Please refrain from ..........ing / commenting on code other than the VBO-related stuff, I'm seriously not in the mood to care (I might feel different in the morning, though, so go nuts if you really can't help yourself).

    Some of this code (gltLoadTGA, the M3D<whatever>) is from the book, just noting.

    Code:
    #include "Common.h"
    #include "math3d.h"
    #include <vector>
    #include <string>
    
    const double PI = 3.14159265358979323846;
    const double PI_2 = PI * 2;
    const double PI_OVER_180 = PI / 180.0;
    
    //GLfloat vOrigin[] = {0.0f, 0.0f, 0.0f};
    //GLfloat vAmbientLight[] = {0.3f, 0.3f, 0.3f, 1.0f};
    //GLfloat vDiffuseLight[] = {0.7f, 0.7f, 0.7f, 1.0f};
    //GLfloat vSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f};
    //GLfloat vGrey[] = {0.75f, 0.75f, 0.75f, 1.0f};
    //
    //GLfloat xRot = 0.0f;
    //GLfloat yRot = 0.0f;
    //GLfloat zRot = 0.0f;
    //GLdouble dFov = 60.0;
    //GLfloat zTrans = -100.0f;
    //int specShininess = 128;
    //bool smoothShading = true;
    //bool depthTesting = true;
    //bool cullFace = true;
    //bool wireframe = false;
    //bool light0 = true;
    
    GLfloat red = 1.0f;
    GLfloat green = 1.0f;
    GLfloat blue = 1.0f;
    GLint filtering = GL_LINEAR;
    const int TEXTURE_COUNT = 1;
    GLuint textures[TEXTURE_COUNT];
    std::string resident("UNKNOWN");
    GLboolean residences[TEXTURE_COUNT];
    
    template <typename T> inline void SafeDelete(T*& ptr)
    {
        if (ptr)
        {
            delete ptr;
            ptr = NULL;
        }
    }
    
    template <typename T> inline void SafeDeleteArray(T*& ptr)
    {
        if (ptr)
        {
            delete[] ptr;
            ptr = NULL;
        }
    }
    
    class VBO
    {
        GLfloat* m_vVerts;
        GLfloat* m_vTexCoords;
        GLushort* m_Indices;
        GLuint m_BufferObjects[3];
        int m_NumVerts;
    
    public:
        VBO()
            : m_vVerts(NULL),
              m_vTexCoords(NULL),
              m_Indices(NULL),
              m_NumVerts(0)
        {
        }
    
        ~VBO()
        {
            Cleanup();
        }
    
        void BeginMesh(GLuint requiredVerts)
        {
            Cleanup();
            
            std::cout << "Allocating " << requiredVerts * 2 << " bytes for vertices and tex coords\n";
            std::cout << "Allocating " << requiredVerts << " bytes for indices\n";
            
            m_vVerts = new GLfloat[requiredVerts * 2];
            m_vTexCoords = new GLfloat[requiredVerts * 2];
            m_Indices = new GLushort[requiredVerts];
        }
    
        void AddVertex(M3DVector2f vert, M3DVector2f vTexCoord)
        {
            memcpy(m_vVerts + (m_NumVerts * 2), vert, sizeof(M3DVector2f));
            memcpy(m_vTexCoords + (m_NumVerts * 2), vTexCoord, sizeof(M3DVector2f));
            m_Indices[m_NumVerts] = (GLushort) m_NumVerts;
            
            m_NumVerts++;
        }
    
        void EndMesh()
        {
            if (!m_NumVerts)
            {
                std::cout << "VBO::EndMesh(): No verts specified\n";
                return;
            }
    
            glGenBuffers(3, m_BufferObjects);
    
            // Copy data to vid mem
            glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjects[0]);
            glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * m_NumVerts * 2, m_vVerts, GL_STATIC_DRAW);
    
            glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjects[1]);
            glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * m_NumVerts * 2, m_vTexCoords, GL_STATIC_DRAW);
            
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_BufferObjects[2]);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * m_NumVerts, m_Indices, GL_STATIC_DRAW);
            
            // Can safely free the vert memory now since GL copies
            Cleanup();
        }
        
        void Draw()
        {
            glEnableClientState(GL_VERTEX_ARRAY);
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    
            // Verts
            glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjects[0]);
            glVertexPointer(2, GL_FLOAT, 0, 0);
    
            // Tex coords
            glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjects[1]);
            glTexCoordPointer(2, GL_FLOAT, 0, 0);
    
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_BufferObjects[2]);
            glDrawElements(GL_QUADS, 4, GL_UNSIGNED_SHORT, 0);
        
            glDisableClientState(GL_VERTEX_ARRAY);
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
            
            //GLenum err = glGetError();
            //if (err != GL_NO_ERROR)
            //    std::cout << "........\n";
        }
        
        void DumpVerts()
        {
            int i = 0;
    
            std::cout << "\n" << m_NumVerts << " vertices\n";
            for ( ; i < m_NumVerts*2; i++)
            {
                std::cout << m_vVerts[i];
                if (!(i % 2))
                    std::cout << ",";
                else
                    std::cout << "\n";
            }
            
            for (i = 0; i < m_NumVerts * 2; i++)
            {
                std::cout << m_vTexCoords[i];
                if (!(i % 2))
                    std::cout << ",";
                else
                    std::cout << "\n";
            }
    
            for (i = 0; i < m_NumVerts; i++)
                std::cout << m_Indices[i] << "\n";
        }
    
    private:
        void Cleanup()
        {
            SafeDeleteArray(m_vVerts);
            SafeDeleteArray(m_vTexCoords);
            SafeDeleteArray(m_Indices);
            m_NumVerts = 0;
    
            glDeleteBuffers(3, m_BufferObjects);
        }
    };
    
    VBO vbo;
    GLfloat mIdentity[] = { 1.0f, 0.0f, 0.0f, 0.0f,        // X column
                            0.0f, 1.0f, 0.0f, 0.0f,        // Y column
                            0.0f, 0.0f, 1.0f, 0.0f,        // Z column
                            0.0f, 0.0f, 0.0f, 1.0f };    // Translation
    
    // Define targa header. This is only used locally.
    #pragma pack(1)
    typedef struct
    {
        GLbyte    identsize;              // Size of ID field that follows header (0)
        GLbyte    colorMapType;           // 0 = None, 1 = paletted
        GLbyte    imageType;              // 0 = none, 1 = indexed, 2 = rgb, 3 = grey, +8=rle
        unsigned short    colorMapStart;          // First colour map entry
        unsigned short    colorMapLength;         // Number of colors
        unsigned char     colorMapBits;   // bits per palette entry
        unsigned short    xstart;                 // image x origin
        unsigned short    ystart;                 // image y origin
        unsigned short    width;                  // width in pixels
        unsigned short    height;                 // height in pixels
        GLbyte    bits;                   // bits per pixel (8 16, 24, 32)
        GLbyte    descriptor;             // image descriptor
    } TGAHEADER;
    #pragma pack(8)
    
    GLbyte *gltLoadTGA(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat)
        {
        FILE *pFile;            // File pointer
        TGAHEADER tgaHeader;        // TGA file header
        unsigned long lImageSize;        // Size in bytes of image
        short sDepth;            // Pixel depth;
        GLbyte    *pBits = NULL;          // Pointer to bits
        
        // Default/Failed values
        *iWidth = 0;
        *iHeight = 0;
        *eFormat = GL_BGR_EXT;
        *iComponents = GL_RGB8;
        
        // Attempt to open the fil
        pFile = fopen(szFileName, "rb");
        if(pFile == NULL)
            return NULL;
        
        // Read in header (binary)
        fread(&tgaHeader, 18/* sizeof(TGAHEADER)*/, 1, pFile);
        
        // Do byte swap for big vs little endian
    #ifdef __APPLE__
        LITTLE_ENDIAN_WORD(&tgaHeader.colorMapStart);
        LITTLE_ENDIAN_WORD(&tgaHeader.colorMapLength);
        LITTLE_ENDIAN_WORD(&tgaHeader.xstart);
        LITTLE_ENDIAN_WORD(&tgaHeader.ystart);
        LITTLE_ENDIAN_WORD(&tgaHeader.width);
        LITTLE_ENDIAN_WORD(&tgaHeader.height);
    #endif
        
        
        // Get width, height, and depth of texture
        *iWidth = tgaHeader.width;
        *iHeight = tgaHeader.height;
        sDepth = tgaHeader.bits / 8;
        
        // Put some validity checks here. Very simply, I only understand
        // or care about 8, 24, or 32 bit targa's.
        if(tgaHeader.bits != 8 && tgaHeader.bits != 24 && tgaHeader.bits != 32)
            return NULL;
        
        // Calculate size of image buffer
        lImageSize = tgaHeader.width * tgaHeader.height * sDepth;
        
        // Allocate memory and check for success
        pBits = (GLbyte*)malloc(lImageSize * sizeof(GLbyte));
        if(pBits == NULL)
            return NULL;
        
        // Read in the bits
        // Check for read error. This should catch RLE or other 
        // weird formats that I don't want to recognize
        if(fread(pBits, lImageSize, 1, pFile) != 1)
            {
            free(pBits);
            return NULL;
            }
        
        // Set OpenGL format expected
        switch(sDepth)
            {
            case 3:     // Most likely case
                *eFormat = GL_BGR_EXT;
                *iComponents = GL_RGB8;
                break;
            case 4:
                *eFormat = GL_BGRA_EXT;
                *iComponents = GL_RGBA8;
                break;
            case 1:
                *eFormat = GL_LUMINANCE;
                *iComponents = GL_LUMINANCE8;
                break;
            };
        
        
        // Done with File
        fclose(pFile);
        
        // Return pointer to image data
        return pBits;
        }
    
    
    template <typename T> inline T Clamp(T value, T min, T max)
    {
        if (value < min)
            value = min;
        
        if (value > max)
            value = max;
        
        return value;
    }
    
    template <typename T> inline T ClampInPlace(T& value, T min, T max)
    {
        if (value < min)
            value = min;
        
        if (value > max)
            value = max;
        
        return value;
    }
    
    void ChangeSize(GLsizei width, GLsizei height);
    
    inline double DegToRad(double degrees)
    {
        return degrees * PI_OVER_180;
    }
    
    inline double RadToDeg(double radians)
    {
        return 180.0 * (PI / radians);
    }
    
    const char* VPrintf(const char* format, ...)
    {
        static char buffers[3][1024];
        static int index = 0;
        va_list args;
        char* destBuff = buffers[index++ & 1];
        
        va_start(args, format);
        vsprintf(destBuff, format, args);
        va_end(args);
        
        return destBuff;
    }
    
    void RenderScene()
    {
        glClear(GL_COLOR_BUFFER_BIT);
    
        //glutSetWindowTitle(VPrintf("xRot: %f - yRot: %f - zRot: %f - zTrans: %f - FOV: %f - Spec: %d",
        //                           xRot, yRot, zRot, zTrans, dFov, specShininess));
        
        //if (smoothShading)
        //    glShadeModel(GL_SMOOTH);
        //else
        //    glShadeModel(GL_FLAT);
        //
        //if (depthTesting)
        //    glEnable(GL_DEPTH_TEST);
        //else
        //    glDisable(GL_DEPTH_TEST);
        //
        //if (cullFace)
        //    glEnable(GL_CULL_FACE);
        //else
        //    glDisable(GL_CULL_FACE);
        //
        //if (wireframe)
        //{
        //    glPolygonMode(GL_BACK, GL_LINE);
        //    glPolygonMode(GL_FRONT, GL_LINE);
        //}
        //else
        //{
        //    glPolygonMode(GL_BACK, GL_FILL);
        //    glPolygonMode(GL_FRONT, GL_FILL);
        //}
        //
        //if (light0)
        //    glEnable(GL_LIGHT0);
        //else
        //    glDisable(GL_LIGHT0);
    
        // Pull back along the Z
        //glTranslatef(0.0f, 0.0f, zTrans);
        //M3DMatrix44f mTransZ;
        //m3dTranslationMatrix44(mTransZ, 0.0f, 0.0f, zTrans);
        //glMultMatrixf(mTransZ);
    
        glAreTexturesResident(TEXTURE_COUNT, textures, residences);
    
        if (residences[0])
            resident = "RESIDENT";
        else
            resident = "NOT RESIDENT";
    
        glutSetWindowTitle(VPrintf("R: %f - G: %f - B: %f - %s", red, green, blue, resident.c_str()));
    
    
    
        glBindTexture(GL_TEXTURE_2D, textures[0]);
    
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
    
        glColor3f(ClampInPlace(red, 0.0f, 1.0f), ClampInPlace(green, 0.0f, 1.0f), ClampInPlace(blue, 0.0f, 1.0f));
        vbo.Draw();
    
        //glBegin(GL_QUADS);
        //    glTexCoord2i(0, 0);
        //    glVertex2i(100, 200);
        //    
        //    glTexCoord2i(1, 0);
        //    glVertex2i(200, 200);
        //    
        //    glTexCoord2i(1, 1);
        //    glVertex2i(200, 100);
        //    
        //    glTexCoord2i(0, 1);
        //    glVertex2i(100, 100);
        //glEnd();
    
        glutSwapBuffers();
    }
    
    void SpecialKeys(int key, int x, int y)
    {
        //switch (key)
        //{
        //case GLUT_KEY_LEFT:
        //    yRot -= 5.0f;
        //    break;
        //case GLUT_KEY_RIGHT:
        //    yRot += 5.0f;
        //    break;
        //case GLUT_KEY_UP:
        //    xRot -= 5.0f;
        //    break;
        //case GLUT_KEY_DOWN:
        //    xRot += 5.0f;
        //    break;
        //case GLUT_KEY_PAGE_UP:
        //    zRot += 5.0f;
        //    break;
        //case GLUT_KEY_PAGE_DOWN:
        //    zRot -= 5.0f;
        //    break;
        //case GLUT_KEY_HOME:
        //    zTrans += 10.0f;
        //    break;
        //case GLUT_KEY_END:
        //    zTrans -= 10.0f;
        //    break;
        //case GLUT_KEY_F1:
        //    smoothShading = !smoothShading;
        //    break;
        //case GLUT_KEY_F2:
        //    depthTesting = !depthTesting;
        //    break;
        //case GLUT_KEY_F3:
        //    cullFace = !cullFace;
        //    break;
        //case GLUT_KEY_F4:
        //    wireframe = !wireframe;
        //    break;
        //case GLUT_KEY_F5:
        //    dFov += 10.0;
        //    ChangeSize(800, 600);
        //    break;
        //case GLUT_KEY_F6:
        //    dFov -= 10.0;
        //    ChangeSize(800, 600);
        //    break;
        //case GLUT_KEY_F7:
        //    light0 = !light0;
        //    break;
        //case GLUT_KEY_F8:
        //    specShininess += 1;
        //    break;
        //case GLUT_KEY_F9:
        //    specShininess -= 1;
        //    break;
        //}
        
        switch (key)
        {
        case GLUT_KEY_F1:
            red += 0.1f;
            break;
        case GLUT_KEY_F2:
            red -= 0.1f;
            break;
        
        case GLUT_KEY_F3:
            green += 0.1f;
            break;
        case GLUT_KEY_F4:
            green -= 0.1f;
            break;
        
        case GLUT_KEY_F5:
            blue += 0.1f;
            break;
        case GLUT_KEY_F6:
            blue -= 0.1f;
            break;
            
        case GLUT_KEY_F11:
            filtering = GL_LINEAR;
            break;
        case GLUT_KEY_F12:
            filtering = GL_NEAREST;
            break;
        }
    
        glutPostRedisplay();
    }
    
    void TimerFunction(int value)
    {
    
        glutPostRedisplay();
        glutTimerFunc(33, TimerFunction, 1);
    }
    
    void SetupRC()
    {
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        
        GLbyte* bytes;
        GLint width, height, comp;
        GLenum fmt;
    
        glGenTextures(TEXTURE_COUNT, textures);
        glBindTexture(GL_TEXTURE_2D, textures[0]);
    
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        bytes = gltLoadTGA("AILogo.tga", &width, &height, &comp, &fmt);
    
        glTexImage2D(GL_TEXTURE_2D, 0, comp, width, height, 0, fmt, GL_UNSIGNED_BYTE, bytes);
        free(bytes);
        glAreTexturesResident(TEXTURE_COUNT, textures, residences);
    
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
        
        //glBegin(GL_QUADS);
        //    glTexCoord2i(0, 0);
        //    glVertex2i(100, 200);
        //    
        //    glTexCoord2i(1, 0);
        //    glVertex2i(200, 200);
        //    
        //    glTexCoord2i(1, 1);
        //    glVertex2i(200, 100);
        //    
        //    glTexCoord2i(0, 1);
        //    glVertex2i(100, 100);
        //glEnd();
    
        M3DVector2f lowerLeft = {100, 200};
        M3DVector2f lowerLeftT = {0, 0};
        M3DVector2f lowerRight = {200, 200};
        M3DVector2f lowerRightT = {1, 0};
        M3DVector2f upperRight = {200, 100};
        M3DVector2f upperRightT = {1, 1};
        M3DVector2f upperLeft = {100, 100};
        M3DVector2f upperLeftT = {0, 1};
    
        vbo.BeginMesh(4);
            vbo.AddVertex(lowerLeft, lowerLeftT);
            vbo.AddVertex(lowerRight, lowerRightT);
            vbo.AddVertex(upperRight, upperRightT);
            vbo.AddVertex(upperLeft, upperLeftT);
        vbo.DumpVerts();
        vbo.EndMesh();
        
        /*
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        
        If you want to simply replace the color of the underlying geometry, you can specify
        GL_REPLACE for the environment mode. Doing so replaces fragment colors from the geom-
        etry directly with the texel colors. Making this change eliminates any effect on the texture
        from the underlying geometry. If the texture has an alpha channel, you can enable blend-
        ing (or use the alpha test), and you can use this mode to create transparent geometry
        patterned after the alpha channel in the texture map.
        
        */
        
        glEnable(GL_TEXTURE_2D);
    
        //glShadeModel(GL_SMOOTH);
        //glEnable(GL_DEPTH_TEST);
        //glEnable(GL_STENCIL_TEST);
        
        //glEnable(GL_LIGHTING);
        //glEnable(GL_COLOR_MATERIAL);
        //glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vAmbientLight);
        //glLightfv(GL_LIGHT0, GL_AMBIENT, vAmbientLight);
        //glLightfv(GL_LIGHT0, GL_DIFFUSE, vDiffuseLight);
        //glLightfv(GL_LIGHT0, GL_SPECULAR, vSpecular);
        
        //glDisable(GL_BLEND);
    
        //std::cout << "OpenGL Setup\n\n";
    
        //int stackDepth;
        //glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &stackDepth);
        //std::cout << "Modelview matrix stack depth: " << stackDepth << "\n";
    }
    
    void ShutdownRC()
    {
        glDeleteTextures(TEXTURE_COUNT, textures);
    }
    
    void ChangeSize(GLsizei width, GLsizei height)
    {
        if (height == 0)
            height = 1;
        
        glViewport(0, 0, width, height);
        glMatrixMode(GL_PROJECTION);
        glLoadMatrixf(mIdentity);
    
        //GLfloat aspectRatio = (GLfloat) width / (GLfloat) height;
        //gluPerspective(dFov, aspectRatio, 1.0, -1.0);
        glOrtho(0, width, height, 0, -1.0, 1.0);
        
        glMatrixMode(GL_MODELVIEW);
        glLoadMatrixf(mIdentity);
    }
    
    
    int main(int argc, char* argv[])
    {
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
        glutInitWindowSize(800, 600);
        glutCreateWindow("OpenGL Fiddle");
        
        glutDisplayFunc(RenderScene);
        glutReshapeFunc(ChangeSize);
        glutSpecialFunc(SpecialKeys);
        //glutTimerFunc(33, TimerFunction, 1);
    
        SetupRC();
        glutMainLoop();
        ShutdownRC();
        
    
        return 0;
    }
    Last edited by cboard_member; 03-25-2009 at 03:42 PM.
    Good class architecture is not like a Swiss Army Knife; it should be more like a well balanced throwing knife.

    - Mike McShaffry

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