Making textures from bitmaps

Hi, I do currently have this code which task is to read a bitmap file and then store it as an OpenGL texture.

This code does compile, but whenever I run it, it will crash. Note that if I remove all the gl-commands after the loop (glBindTexture() to gluBuild2DMipmaps()) it will not crash, but I will not have gotten my texture either.

Am I doing something wrong? Is there an easier way to accomplish this task?

int LoadBitmap(std::string filename)
{
    unsigned char *l_texture; // The pointer to the memory zone in which we will load the texture
    int width, height, size; //Storage for bitmap-info
    num_texture++; // A variable which keeps track of the number of textures

    FILE *mf;
    mf = fopen(filename.c_str(), "rb"); //Open file
    if (mf == NULL)                        //Check if the file opened
        exit(13);
    
    fseek(mf, 18, SEEK_SET);
    fread(&width, sizeof(int), 1, mf);    //Read in the width of the image
    
    fseek(mf, 22, SEEK_SET);
    fread(&height, sizeof(int), 1, mf);    //Read in the height of the image
        
    size = height * width * 4;        //The size for all the important bytes

    // Now we need to allocate the memory for our image (width * height * color deep)
    l_texture = (unsigned char *) malloc(size);
    // And fill it with zeros
    memset(l_texture, 0, size);
 
    // At this point we can read every pixel of the image
    for (int i=0; i < size; i += 4)
    {            
            // We load the red, green and blue values
            char r, g, b;
            fread(&r, 1, 1, mf); 
            fread(&g, 1, 1, mf); 
            fread(&b, 1, 1, mf); 
                        
            // And store it
            l_texture[i+0] = r; // Red component
            l_texture[i+1] = g; // Green component
            l_texture[i+2] = b; // Blue component
            l_texture[i+3] = 255; // Alpha value
    }

    fclose(mf); // 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, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, l_texture);

    // And create 2d mipmaps for the minifying function
    gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, 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
}

Properly formatted with colors at pastebin

Note, this is c++ ,but I am mainly worried about the gl-calls.

num_texture++; // A variable which keeps track of the number of textures

where this number come from? It’s a global variable?
Have you called glGenTexture?

You should add this before the glBindTexture

glGenTextures(1, &num_texture);

don’t try to manage the texture names by yourself.

Should I then call glGenTextures() once in my init-function, or once every time I create a new texture?

glGenTextures creates as many textures as you tell to create (1st parmeter). So if you know how many texture you need, you can put all texture names in an array… it depends more on the way you represent textures in your code.

Look at the wiki to see the good way to create textures with OpenGL:
http://www.opengl.org/wiki/index.php/Texture_Mapping
And man pages:
http://www.opengl.org/sdk/docs/man/

I have now changed my code slighly, yet it crashes at runtime.

GLuint LoadBitmap(std::string filename)
{
    unsigned char *l_texture; // The pointer to the memory zone in which we will load the texture
    int width, height, size; //Storage for bitmap-info
    GLuint texture; // A variable which keeps track of the number of textures

    FILE *mf;
	mf = fopen(filename.c_str(), "rb"); //Open file
	if (mf == NULL)						//Check if the file opened
		exit(13);
	
	fseek(mf, 18, SEEK_SET);
	fread(&width, sizeof(int), 1, mf);	//Read in the width of the image
	
	fseek(mf, 22, SEEK_SET);
	fread(&height, sizeof(int), 1, mf);	//Read in the height of the image
		
	size = height * width * 3;		//The size for all the important bytes

    // Now we need to allocate the memory for our image (width * height * color deep)
    l_texture = (unsigned char *) malloc(size);
	
    // And fill it with zeros
    memset(l_texture, 0, size);
	
	fseek(mf, 54, SEEK_SET);
	fread(l_texture, size, 1, mf);
	
    fclose(mf); // Closes the file stream
	
	glGenTextures( 1, &texture );
	
	glBindTexture( GL_TEXTURE_2D, texture );
	
    // 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, 3, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, l_texture);

    // And create 2d mipmaps for the minifying function
    gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, GL_RGBA, GL_UNSIGNED_BYTE, l_texture);

    free(l_texture); // Free the memory we used to load the texture

    return texture; // Returns the current texture OpenGL ID
}

you can check whether you have the right file path to read in the bitmap file.I guess its not able to read the file.The first code posted worked fine.

It is correct. If the file could not have been read, it would exit with exit code 13 (at line 12).

Could you provide the code you tested?

What are the width and the height of your texture? They must be power-of-two!

Oh, and glTexImage2D line is redundant, as gluBuild… performs the same call internally.

The width and height are both 1024. I have output the values which I read and they all seem correct. I just can’t get what I am doing wrong.

Strange indeed… Does it work if you skip the mipmaps? (I mean, if you just load the texture and use linear filtering)

I think I have a found a sample that partly works. Il come by later and tell you what I did wrong.

Ok, a new modification. This time it does not crash, but the values which I read from the file is all garbage (ranging from -3 to 3 even though the picture is all black). I do however suspect that this is an easier problem than my last problem.

int LoadBMP(std::string filename)
{
	unsigned char *array; // The pointer to the memory zone in which we will load the texture
    int width, height, size; //Storage for bitmap-info

    FILE *mf;
    mf = fopen(filename.c_str(), "rb"); //Open file
    if (mf == NULL)                        //Check if the file opened
        exit(13);
    
    fseek(mf, 18, SEEK_SET);
    fread(&width, sizeof(int), 1, mf);    //Read in the width of the image
    
    fseek(mf, 22, SEEK_SET);
    fread(&height, sizeof(int), 1, mf);    //Read in the height of the image
        
    size = height * width * 4;        //The size for all the important bytes

    // Now we need to allocate the memory for our image (width * height * color deep)
    array = new unsigned char[size];
 
    // At this point we can read every pixel of the image
    for (int i=0; i < size; i += 4)
    {            
            // We load the red, green and blue values
            char r, g, b;
            fread(&r, 1, 1, mf); 
            fread(&b, 1, 1, mf); 
            fread(&g, 1, 1, mf); 
                        
            // And store it
            array[i+0] = r; // Red component
            array[i+1] = g; // Green component
            array[i+2] = b; // Blue component
            array[i+3] = 255; // Alpha value
    }

    fclose(mf); // Closes the file stream
     
	counter++;
    glBindTexture(GL_TEXTURE_2D, counter); // 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, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, array);

    // And create 2d mipmaps for the minifying function
    gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, GL_RGBA, GL_UNSIGNED_BYTE, array);

    free(array);
	
	return counter;
}

Note that this time it is not a function as that causes it to crash.

Edit: In retrospective I do also see that my first function do also work outside of a function. Why is this?

Edit2: I think it has something to with the order in which things are done.

Solved:
My problem was that I called this function before I had initialised OpenGL. You’d think that is was obvious, but I did not know that constructors of class2 in class1 is called before the constructor of class1. This is important! Apart from that, I think that every example posted in this thread will work. I ended up using the code above.