Thread: Texture Binding with OpenGL

  1. #1
    Registered User
    Join Date
    Mar 2007
    Posts
    416

    Texture Binding with OpenGL

    I am trying to bind two different textures (BMP pictures really) to two different cubes. I went by NeHe's tutorial on binding/loading bitmaps and found the glaux.lib is not recommended, and a long time ago (year or so) I found a snippet for loading bitmaps that worked well without needing extra libraries/files. Now my problem is binding more than one texture, to more than one area. I can do it, but it is essentially loading the bitmap everytime it scans the screen, and this causes it to run very very very slow (like half a frame per second). I would like to know if there is a better, more efficient way to bind textures to more than one surface.

    EDIT: If I load the bitmaps before I begin the glBegin(QUADS) it will load the correct texture to the correct cube, however that is what causes the screen to run extremely slow. I have also searched around in numerous places and I keep coming up with "don't use glaux.lib" stuff, and nothing useful.

    Code:
    //BITMAP LOADER
    
    bool CustomLoadBitmap(char *filename, GLuint &num_texture)
    {
        int i, j=0; //Index variables
        FILE *l_file; //File pointer
        unsigned char *l_texture; //The pointer to the memory zone in which we will load the texture
    
        // windows.h gives us these types to work with the Bitmap files
        BITMAPFILEHEADER fileheader;
        BITMAPINFOHEADER infoheader;
        RGBTRIPLE rgb;
    
        num_texture++; // The counter of the current texture is increased
    
        if((l_file = fopen(filename, "rb"))==NULL) return (-1); // Open the file for reading
    
        fread(&fileheader, sizeof(fileheader), 1, l_file); // Read the fileheader
    
        fseek(l_file, sizeof(fileheader), SEEK_SET); // Jump the fileheader
        fread(&infoheader, sizeof(infoheader), 1, l_file); // and read the infoheader
    
        // Now we need to allocate the memory for our image (width * height * color deep)
        l_texture = (byte *) malloc(infoheader.biWidth * infoheader.biHeight * 4);
        // And fill it with zeros
        memset(l_texture, 0, infoheader.biWidth * infoheader.biHeight * 4);
    
        // At this point we can read every pixel of the image
        for (i=0; i < infoheader.biWidth*infoheader.biHeight; i++)
        {
            // We load an RGB value from the file
            fread(&rgb, sizeof(rgb), 1, l_file);
    
            // And store it
            l_texture[j+0] = rgb.rgbtRed; // Red component
            l_texture[j+1] = rgb.rgbtGreen; // Green component
            l_texture[j+2] = rgb.rgbtBlue; // Blue component
            l_texture[j+3] = 255; // Alpha value
            j += 4; // Go to the next position
        }
    
        fclose(l_file); // Closes the file stream
    
        glBindTexture(GL_TEXTURE_2D, num_texture); // Bind the ID texture specified by the 2nd parameter
    
        // The next commands sets the texture parameters
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // If the u,v coordinates overflow the range 0,1 the image is repeated
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // The magnification function ("linear" produces better results)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); //The minifying function
    
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // We don't combine the color with the original surface color, use only the texture map.
    
        // Finally we define the 2d texture
        glTexImage2D(GL_TEXTURE_2D, 0, 4, infoheader.biWidth, infoheader.biHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, l_texture);
    
        // And create 2d mipmaps for the minifying function
        gluBuild2DMipmaps(GL_TEXTURE_2D, 4, infoheader.biWidth, infoheader.biHeight, GL_RGBA, GL_UNSIGNED_BYTE, l_texture);
    
        free(l_texture); // Free the memory we used to load the texture
    
        //return (num_texture); // Returns the current texture OpenGL ID
    }
    
    //WHERE THE BITMAP IS LOADED, IF ONE IS LOADED THE SCREEN RUNS FINE WITH NO
    //SIGNS OF SLOWING DOWN. IF TWO ARE LOADED IT WILL ONLY DISPLAY THE LAST ONE.
    
    int InitGL(GLvoid)										// All Setup For OpenGL Goes Here
    {
        if(!CustomLoadBitmap("data/guitar.bmp",texture[0])){
            return false;
        }
        if(!CustomLoadBitmap("data/Crate.bmp",texture[1])){
            return false;
        }
    
    	glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
    	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				// Black Background
    	glClearDepth(1.0f);									// Depth Buffer Setup
    	glEnable(GL_TEXTURE_2D);
    	glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
    	glDepthFunc(GL_LEQUAL);								// The Type Of Depth Testing To Do
    	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations
        glEnable(GL_LIGHT1);
        //SetCursorPos(mid_x, mid_y);
    
    	return TRUE;										// Initialization Went OK
    }
    
    //THE DRAWING PORTION
    
    int DrawGLScene(GLvoid)									// Here's Where We Do All The Drawing
    {
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer
    	glLoadIdentity();
    
    	heading = 360.0f - lookdir;									// Reset The Current Modelview Matrix
    
        glRotatef(heading,0,1.0f,0);
    	glTranslatef(xpos,jump,zpos); //moves the starting position
    
        DrawCrateNear(); //this is in a header file so the .cpp file stays cleaner
        DrawCrateFar(); //same here
    
        xrot = xspeed;
        yrot = yspeed;
    
        return TRUE; // Everything Went OK
    }

  2. #2
    Registered User
    Join Date
    Feb 2008
    Location
    Rochester, NY
    Posts
    27
    Load the BMP files as you are doing before the render loop. In the render loop you are going to have to bind the texture for use before drawing the specific shape.

    Essentially you'll do:
    Code:
    InitGL()
    Render()
    {
         glBindTexture(GL_TEXTURE_2D, texture1);
         DrawCube();
         glBindTexture(GL_TEXTURE_2D, texture2);
         DrawCube();
    }

  3. #3
    Registered User
    Join Date
    Mar 2007
    Posts
    416
    I tried that and it still behaves the same as before. I even switched the glBindTexture() to have the same array variable which was not the last one loaded (the crate.bmp). Does this have something to do with the glBindTexture() being inside the CustomLoadBitmap() ?

  4. #4
    Registered User
    Join Date
    Feb 2008
    Location
    Rochester, NY
    Posts
    27
    Code:
    //THE DRAWING PORTION
    
    int DrawGLScene(GLvoid)									// Here's Where We Do All The Drawing
    {
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer
    	glLoadIdentity();
    
    	heading = 360.0f - lookdir;									// Reset The Current Modelview Matrix
    
        glRotatef(heading,0,1.0f,0);
        glTranslatef(xpos,jump,zpos); //moves the starting position
    
        glBindTexture(GL_TEXTURE_2D, texture[0]);
        DrawCrateNear(); //this is in a header file so the .cpp file stays cleaner
        glBindTexture(GL_TEXTURE_2D, texture[1]);
        DrawCrateFar(); //same here
    
        xrot = xspeed;
        yrot = yspeed;
    
        return TRUE; // Everything Went OK
    }
    I'm almost positive this is how your code should look. Other than that everything else should be fine. I'm not sure what code you have in the two DrawCrate functions. There might be something which messes up textures at that point.

  5. #5
    Registered User
    Join Date
    Mar 2007
    Posts
    416
    I moved the glBindTexture() inside the DrawCrate functions and it will still only show the last of the loaded textures put in the InitGL(). The DrawCrate functions are simply just coordinates for how the boxes should be drawn. Here is one of the functions (these are in header files by the way).

    EDIT: if this helps any, i changed the texture[] array number from 0 and 1 to 1 and 2 where it gets binded to the box i want, and the second box shows up white without texture. I think it has something to do with the way the bitmap is loaded in the loading function.

    Code:
    bool DrawCrateNear(void){
    
        glBindTexture(GL_TEXTURE_2D,texture[0]);
    
        glBegin(GL_QUADS);
    //-----FRONT------------
            //glColor3f(1.0f,0.0f,0.0f);
            glTexCoord2f(1.0f,1.0f); glVertex3f(1.0,1.0,0.0);
    
            //glColor3f(0.0f,1.0f,0.0f);
            glTexCoord2f(1.0f,0.0f); glVertex3f(1.0,-1.0,0.0);
    
            //glColor3f(1.0f,0.0f,0.0f);
            glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0,-1.0,0.0);
    
            //glColor3f(0.0f,1.0f,0.0f);
            glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0,1.0,0.0);
    
    //..... after a ton of coords....
    
    //-----BOTTOM-----------------
            glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0,-1.0,-2.0);
    
            //glColor3f(0.0f,1.0f,0.0f);
            glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0,-1.0,0.0);
    
            //glColor3f(1.0f,0.0f,0.0f);
            glTexCoord2f(0.0f,0.0f); glVertex3f(1.0,-1.0,0.0);
    
            //glColor3f(0.0f,1.0f,0.0f);
            glTexCoord2f(0.0f,1.0f); glVertex3f(1.0,-1.0,-2.0);
        glEnd();
    
        return true;
    }
    EDIT 2: I figured it out! The CustomLoadBitmap() was not generating the textures with glGenTextures() like it should have. The final loader for the bitmaps is the following code.

    Code:
    bool CustomLoadBitmap(char *filename, GLuint &num_texture)
    {
        int i, j=0,count=0; //Index variables
        FILE *l_file; //File pointer
        unsigned char *l_texture; //The pointer to the memory zone in which we will load the texture
    
        // windows.h gives us these types to work with the Bitmap files
        BITMAPFILEHEADER fileheader;
        BITMAPINFOHEADER infoheader;
        RGBTRIPLE rgb;
    
        if((l_file = fopen(filename, "rb"))==NULL) return (-1); // Open the file for reading
    
        fread(&fileheader, sizeof(fileheader), 1, l_file); // Read the fileheader
    
        fseek(l_file, sizeof(fileheader), SEEK_SET); // Jump the fileheader
        fread(&infoheader, sizeof(infoheader), 1, l_file); // and read the infoheader
    
        num_texture++; // The counter of the current texture is increased
    
        // Now we need to allocate the memory for our image (width * height * color deep)
        l_texture = (byte *) malloc(infoheader.biWidth * infoheader.biHeight * 4);
        // And fill it with zeros
        memset(l_texture, 0, infoheader.biWidth * infoheader.biHeight * 4);
    
        // At this point we can read every pixel of the image
        for (i=0; i < infoheader.biWidth*infoheader.biHeight; i++)
        {
            // We load an RGB value from the file
            fread(&rgb, sizeof(rgb), 1, l_file);
    
            // And store it
            l_texture[j+0] = rgb.rgbtRed; // Red component
            l_texture[j+1] = rgb.rgbtGreen; // Green component
            l_texture[j+2] = rgb.rgbtBlue; // Blue component
            l_texture[j+3] = 255; // Alpha value
            j += 4; // Go to the next position
        }
    
        fclose(l_file); // Closes the file stream
    
        glGenTextures(1, &num_texture);
    
        glBindTexture(GL_TEXTURE_2D, num_texture); // Bind the ID texture specified by the 2nd parameter
    
        // The next commands sets the texture parameters
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // If the u,v coordinates overflow the range 0,1 the image is repeated
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // The magnification function ("linear" produces better results)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); //The minifying function
    
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // We don't combine the color with the original surface color, use only the texture map.
    
        // Finally we define the 2d texture
        glTexImage2D(GL_TEXTURE_2D, 0, 4, infoheader.biWidth, infoheader.biHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, l_texture);
    
        // And create 2d mipmaps for the minifying function
        gluBuild2DMipmaps(GL_TEXTURE_2D, 4, infoheader.biWidth, infoheader.biHeight, GL_RGBA, GL_UNSIGNED_BYTE, l_texture);
    
        free(l_texture); // Free the memory we used to load the texture
    
        count++;
    
        return (num_texture); // Returns the current texture OpenGL ID
    }
    Last edited by scwizzo; 07-01-2008 at 10:16 AM.

  6. #6
    Registered User
    Join Date
    Feb 2008
    Location
    Rochester, NY
    Posts
    27
    Good to hear you solved the issue.

    Yeah I completely overlooked that you didn't call glGenTextures.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Why only 32x32? (OpenGL) [Please help]
    By Queatrix in forum Game Programming
    Replies: 2
    Last Post: 01-23-2006, 02:39 PM
  2. Linking OpenGL in Dev-C++
    By linkofazeroth in forum Game Programming
    Replies: 4
    Last Post: 09-13-2005, 10:17 AM
  3. Pong is completed!!!
    By Shamino in forum Game Programming
    Replies: 11
    Last Post: 05-26-2005, 10:50 AM
  4. OpenGL Window
    By Morgul in forum Game Programming
    Replies: 1
    Last Post: 05-15-2005, 12:34 PM
  5. OpenGL and Windows
    By sean345 in forum Game Programming
    Replies: 5
    Last Post: 06-24-2002, 10:14 PM