Hi, I'm writing a program in C++/OpenGL as part of a university assignment but I am having difficulty using the function glBindTexture to bind my loaded textures onto the models that I load in and render. I can actually wrap the texture around my 3D model no problem but I can't seem to do it unless the texture has only just been loaded into memory and then I immediately bind it to my model. This means that every time I want to use a texture I have to read through all the data in the texture file every single frame; this is EXTREMELY inefficient....

Below shows the main sections of code involved (I have attached the full listing for the involved classes too though):

for(int i=0;i<nBalls;i++){
	  TexID[i]= myBall[i].loadBitMap(BitMapList[i]);
	  myBall[i].draw(TexID[i]);
  }

This above code is in my 'scene' class and within a render function called each frame. The loadBitMap function that is called in the loop returns an ID that should be able to then be used to bind a texture and hence shouldn't be used in a render loop....problem is, the ID and binding (which is done in my 'ball' class) only works if the texture was loaded into memory immediately before.

int Ball::loadBitMap(char *currenttexture){
		textureid =LoadBitmap(currenttexture);
		return textureid;
	}

This the code in 'ball' which calls the LoadBitmap function to read the text file.

#include <stdio.h>
#include <windows.h>
#include "glut.h"
#include <GL/glu.h>
#include <GL/gl.h>
#include "texture.h"



/**********************************************************
 *
 * VARIABLES DECLARATION
 *
 *********************************************************/

int num_texture=-1; //Counter to keep track of the last loaded texture



/**********************************************************
 *
 * FUNCTION LoadBitmap(char *)
 *
 * This function loads a bitmap file and return the OpenGL reference ID to use that texture
 *
 *********************************************************/

int LoadBitmap(char *filename) 
{
     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
}

Above is the code that I use to load a bitmap texture. You will notice that I don't use genTextures anywhere and that is only because when I tried using genTextures it still didn't work but made my code run even slower :s

finally in my ball class the code that binds my texture before drawing the model(s):

void Ball::draw(int TexID){

	int l_index;
	glPushMatrix();
  	glColor3f(0.0f,1.0f,0.0f);
  	glTranslatef(x,y,z);
  
  	if (fileloaded){
		glScalef(scalex,scaley,scalez);

   glRotatef(theta,1.0f,0.0f,0.0f);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,TexID);
	glBegin(GL_TRIANGLES); // glBegin and glEnd delimit the vertices that define a primitive (in our case triangles)
    for (l_index=0;l_index<object.polygons_qty;l_index++)
    {
        //----------------- FIRST VERTEX -----------------
        glTexCoord2f(object.mapcoord[ object.polygon[l_index].a ].u,object.mapcoord[ object.polygon[l_index].a ].v);
        glVertex3f( object.vertex[ object.polygon[l_index].a ].x,
                    object.vertex[ object.polygon[l_index].a ].y,
                    object.vertex[ object.polygon[l_index].a ].z); //Vertex definition

        //----------------- SECOND VERTEX -----------------
        // Coordinates of the second vertex
		glTexCoord2f(object.mapcoord[ object.polygon[l_index].b ].u,object.mapcoord[ object.polygon[l_index].b ].v);
        glVertex3f( object.vertex[ object.polygon[l_index].b ].x,
                    object.vertex[ object.polygon[l_index].b ].y,
                    object.vertex[ object.polygon[l_index].b ].z);
        
        //----------------- THIRD VERTEX -----------------
        // Coordinates of the Third vertex
		glTexCoord2f(object.mapcoord[ object.polygon[l_index].c ].u,object.mapcoord[ object.polygon[l_index].c ].v);
        glVertex3f( object.vertex[ object.polygon[l_index].c ].x,
                    object.vertex[ object.polygon[l_index].c ].y,
                    object.vertex[ object.polygon[l_index].c ].z);
    }
    glEnd(); 
	glDisable(GL_TEXTURE_2D);
	glDeleteTextures(1,(GLuint *)&TexID);
  }
  else
   {
    	glScalef(0.05f,0.05f,0.05f);
		glutSolidCube(5.0);
   }
  glPopMatrix();

}

Please excuse the random class names etc. I have been using this code for testing purposes and have kept it seperate it from my main project which incorporates models and lighting etc. rendered through a scene graph.

Any help would be greatly appreciated.

Thanks

Edited 6 Years Ago by Valaraukar: Forgot to attach code listing

Attachments
#include "ball.h"

void Ball::draw(int TexID){

	int l_index;
	glPushMatrix();
  	glColor3f(0.0f,1.0f,0.0f);
  	glTranslatef(x,y,z);
  
  	if (fileloaded){
		glScalef(scalex,scaley,scalez);

   glRotatef(theta,1.0f,0.0f,0.0f);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,TexID);
	glBegin(GL_TRIANGLES); // glBegin and glEnd delimit the vertices that define a primitive (in our case triangles)
    for (l_index=0;l_index<object.polygons_qty;l_index++)
    {
        //----------------- FIRST VERTEX -----------------
        glTexCoord2f(object.mapcoord[ object.polygon[l_index].a ].u,object.mapcoord[ object.polygon[l_index].a ].v);
        glVertex3f( object.vertex[ object.polygon[l_index].a ].x,
                    object.vertex[ object.polygon[l_index].a ].y,
                    object.vertex[ object.polygon[l_index].a ].z); //Vertex definition

        //----------------- SECOND VERTEX -----------------
        // Coordinates of the second vertex
		glTexCoord2f(object.mapcoord[ object.polygon[l_index].b ].u,object.mapcoord[ object.polygon[l_index].b ].v);
        glVertex3f( object.vertex[ object.polygon[l_index].b ].x,
                    object.vertex[ object.polygon[l_index].b ].y,
                    object.vertex[ object.polygon[l_index].b ].z);
        
        //----------------- THIRD VERTEX -----------------
        // Coordinates of the Third vertex
		glTexCoord2f(object.mapcoord[ object.polygon[l_index].c ].u,object.mapcoord[ object.polygon[l_index].c ].v);
        glVertex3f( object.vertex[ object.polygon[l_index].c ].x,
                    object.vertex[ object.polygon[l_index].c ].y,
                    object.vertex[ object.polygon[l_index].c ].z);
    }
    glEnd(); 
	glDisable(GL_TEXTURE_2D);
	glDeleteTextures(1,(GLuint *)&TexID);
  }
  else
   {
    	glScalef(0.05f,0.05f,0.05f);
		glutSolidCube(5.0);
   }
  glPopMatrix();

}

void Ball::initialise(float tx,float ty, float tz){
		
      x=tx;y=ty;z=tz;
    }

void Ball::load3dsFile(char *currentfilename){
	fileloaded=Load3DS (&object,currentfilename);
}

int Ball::loadBitMap(char *currenttexture){
		textureid =LoadBitmap(currenttexture);
		return textureid;
	}

//void Ball::getBitMap(char *currenttexture){
		//theTexture=LoadBitmap(currenttexture);
		//object.id_texture=SetTextureID(theTexture,currenttexture);
	//}

void Ball::spin(){
			if (theta >= 360)
				theta = 0.0f;
         else
             theta += 25.0f;
    }
#ifndef _BALL_H_
#define _BALL_H_

#include <windows.h>
#include <GL\gl.h>
#include <GL\glu.h>
#include "glut.h"
#include "3dsloader.h"
#include "texture.h"
#include "otypes.h"


class Ball{

    float x,y,z; // position in space
    float vx,vy,vz; //movement vector
	float scalex,scaley,scalez;//scaling factor
    float theta;
	obj_type object;
	char fileloaded;
	int textureid;
	char *TextureFileName;
	char *meshFilename;
	
	public:
    Ball(){}
    Ball(float tx,float ty, float tz){x=tx;y=ty;z=tz;}

    //================== prototype methods =======

    void load3dsFile(char *);
	int loadBitMap(char *);
	//void getBitMap(char *);
	void spin();
	void initialise(float,float, float);
      //================== complete methods =======
  
	void setangle(){theta = 0.0f;}
	float getx(){return x;}
    float gety(){return y;}
    float getz(){return z;}
    
    float getvx(){return vx;}
    float getvy(){return vy;}
    float getvz(){return vz;}

    void setx(float tx){x=tx;}
    void sety(float ty){y=ty;}
    void setz(float tz){z=tz;}

    void setvx(float tx){vx=tx;}
    void setvy(float ty){vy=ty;}
    void setvz(float tz){vz=tz;}

	void setscalex(float tx){scalex=tx;}
    void setscaley(float ty){scaley=ty;}
    void setscalez(float tz){scalez=tz;}
    
    void move(){x+=vx;y+=vy;z+=vz;}

    void draw(int);

};
#endif //_BALL_H_
#include "scene.h"
#include "ball.h"
#include <string.h>



void Scene::initialise(){
    // x=0.0;
    //y=0.0;
    //z=0.0;
	
    float startarray[4][9]={{9.0f,9.0f,0.0f,0.1f,-0.25f,0.0f,0.02f,0.02f,0.02f},
                            {7.0f,9.0f,0.0f,0.05,-0.05f,0.0f,1.0f,1.0f,1.0f},
                            {3.0f,9.0f,0.0f,0.01f,-0.02f,0.0f,0.03f,0.03f,0.03f},
                            {0.0f,9.0f,0.0f,0.03f,-0.076f,0.0f,0.04f,0.04f,0.04f}
    };
	
	nBalls=4;

	
	MeshList = (char **)malloc(sizeof(char *[MAXBALLS]));
	BitMapList = (char **)malloc(sizeof(char *[MAXBALLS]));
	
	MeshList[0]= "spaceship.3ds";
	BitMapList[0]="spaceshiptexture.bmp";
	
	MeshList[1]= "earth.3ds";
	BitMapList[1]="earth.bmp";

	MeshList[2]= "spaceship.3ds";
	BitMapList[2]="spaceshiptexture.bmp";

	MeshList[3]= "spaceship.3ds";
	BitMapList[3]="spaceshiptexture.bmp";
    
	glEnable(GL_TEXTURE_2D);
    myBall=new Ball[nBalls];

	for(int i=0;i<nBalls;i++){
		myBall[i].initialise(0.0f,0.0f,0.0f);
	}

    for(int i=0;i<nBalls;i++){
        myBall[i].setx(startarray[i][0]);
        myBall[i].sety( startarray[i][1] );
		myBall[i].setz(startarray[i][2]  );
		
        myBall[i].setvx(startarray[i][3] );
        myBall[i].setvy(startarray[i][4] );
        myBall[i].setvz(startarray[i][5] );

		myBall[i].setscalex(startarray[i][6] );
        myBall[i].setscaley(startarray[i][7] );
        myBall[i].setscalez(startarray[i][8] );
       
		myBall[i].load3dsFile(MeshList[i]);
		//TexID[i]= myBall[i].loadBitMap(BitMapList[i]);
        myBall[i].setangle();
    }
 
}
 
void Scene::spinballs(){
  for(int i=0;i<nBalls;i++){
      myBall[i].spin();
    }
}

void Scene::moveobjects(){
    for(int i=0;i<nBalls;i++){
      myBall[i].move();
    }
}

void Scene::render(){
  glColor3f(1.0f,0.0f,0.0f);
//  glTranslatef(x,y,z);
  // glScalef(10.0f,10.0f,10.0f);
  //glutSolidCube(5.0);
  for(int i=0;i<nBalls;i++){
	  TexID[i]= myBall[i].loadBitMap(BitMapList[i]);
	  myBall[i].draw(TexID[i]);
  }
}

void Scene::cdetect(){
   
    for(int i=0;i<nBalls;i++){
      if((myBall[i].getx()<-10.0)||(myBall[i].getx()>10.0))
        myBall[i].setvx(myBall[i].getvx()*-1.0f);

      if((myBall[i].gety()<-10.0)||(myBall[i].gety()>10.0))
        myBall[i].setvy(myBall[i].getvy()*-1.0f);
    }

    for(int i=0;i<nBalls;i++){
	for(int j=i+1;j<nBalls;j++){
	    float tx=myBall[i].getx()-myBall[j].getx();
	    float ty=myBall[i].gety()-myBall[j].gety();
	    float tz=myBall[i].getz()-myBall[j].getz();

            float dist=sqrt(tx*tx+ty*ty+tz*tz);
            if(dist<0.9f){
                float temp=myBall[i].getvx();
                myBall[i].setvx(myBall[j].getvx());
                myBall[j].setvx(temp);
                temp=myBall[i].getvy();
                myBall[i].setvy(myBall[j].getvy());
                myBall[j].setvy(temp);
                temp=myBall[i].getvz();
                myBall[i].setvz(myBall[j].getvz());
                myBall[j].setvz(temp);
	    }
	}
    }


  

}
#ifndef _SCENE_H_
#define _SCENE_H_

#include <windows.h>
#include <GL\gl.h>
#include <GL\glu.h>
#include "glut.h"
#include <math.h>
//#include <string.h>
#include "ball.h"
#define MAXBALLS 10

class Scene{
    //float x,y,z;
    int nBalls;
    Ball *myBall;
	char **MeshList;
	char **BitMapList;
	GLuint TexID[MAXBALLS];

 public:
  Scene(){return;}
  ~Scene(){return;}

 void initialise();
 void render();
 void moveobjects();
 void cdetect();
 void spinballs();
};

#endif //_SCENE_H_
#include <stdio.h>
#include <windows.h>
#include "glut.h"
#include <GL/glu.h>
#include <GL/gl.h>
#include "texture.h"



/**********************************************************
 *
 * VARIABLES DECLARATION
 *
 *********************************************************/

int num_texture=-1; //Counter to keep track of the last loaded texture



/**********************************************************
 *
 * FUNCTION LoadBitmap(char *)
 *
 * This function loads a bitmap file and return the OpenGL reference ID to use that texture
 *
 *********************************************************/

int LoadBitmap(char *filename) 
{
     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
}
/**********************************************************
 *
 * VARIABLES DECLARATION
 *
 *********************************************************/

// Counter to keep track of the last loaded texture
extern int num_texture;



/**********************************************************
 *
 * FUNCTION LoadBitmap(char *)
 *
 * This function loads a bitmap file and return the OpenGL reference ID to use that texture
 *
 *********************************************************/

extern int LoadBitmap(char *filename);
//extern int SetTextureID(unsigned char *l_texture, char *filename);

In your main class, load in all of the textures in your init function.
Then when displaying the objects, use glBindTexture(GL_TEXTURE_2D,id);
where the id is the id of a certain texture.

That doesn't seem to work. In fact when I do what you suggested no textures are applied at all :s

That doesn't seem to work. In fact when I do what you suggested no textures are applied at all :s

Did you enable texture inside the init function. Also remove any
disable call to GL_TEXTURE_2D.

Done but still no luck :(
I can't see what the problem is at all....its as if it is only being stored temporarily in memory

Done but still no luck :(
I can't see what the problem is at all....its as if it is only being stored temporarily in memory

Did you call glBindTexture before texturing it. And make sure your
tex coord is correct.

yup. Its basically the bind that doesn't work. the texture id doesn't seem to be associated to any textures unless I read the textures in immediately before binding

You can use glGentexture to have opengl generate a texture id, but
opengl automatically does this. I don't remember if the first texture
starts with 0 or 1, but after that every time you load a texture, the id of
that texture is n, where n is the number of total texture it loaded at that point.

Well I understand that but that's kind of where my problem is because it doesn't seem to be doing that :s

I can only load a texture if I bind its ID immediately after I have read the data from file whereas I should be able to use it at any point after I have I done that.

<quote>

for(int i=0;i<nBalls;i++){
	  TexID[i]= myBall[i].loadBitMap(BitMapList[i]);
//	  myBall[i].draw(TexID[i]);
 }

Put that in your main init function, without the myBall.draw();
I assume TexID is an array of ints?


Put this :

glEnable(GL_TEXTURE_2D);

in your init function as well.

Make sure

glTexCoord2f(object.mapcoord[ object.polygon[l_index].a ].u,object.mapcoord[ object.polygon[l_index].a ].v);

are all of type floats.

Remove this code especially :

glDisable(GL_TEXTURE_2D);
glDeleteTextures(1,(GLuint *)&TexID); //why are you deleting it?

tell me how that goes.

Sorry I didn't get back to you, I've been cracking on with another assignment that I've also got to get done. I've tried what you suggested but still no luck and as to why I was using deleteTextures in the first place....well I don't know what I was thinking :s

This article has been dead for over six months. Start a new discussion instead.