PDA

View Full Version : Making textures from bitmaps



Lillefix
12-25-2008, 12:10 PM
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(&amp;r, 1, 1, mf);
fread(&amp;g, 1, 1, mf);
fread(&amp;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 (http://pastebin.com/f600e3405)

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

Rosario Leonardi
12-25-2008, 01:18 PM
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.

Lillefix
12-25-2008, 02:34 PM
Should I then call glGenTextures() once in my init-function, or once every time I create a new texture?

dletozeun
12-25-2008, 03:16 PM
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/

Lillefix
12-25-2008, 04:44 PM
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(&amp;width, sizeof(int), 1, mf); //Read in the width of the image

fseek(mf, 22, SEEK_SET);
fread(&amp;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, &amp;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
}

sud24
12-25-2008, 05:54 PM
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.

Lillefix
12-26-2008, 03:19 AM
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?

Zengar
12-26-2008, 03:43 AM
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.

Lillefix
12-26-2008, 03:51 AM
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.

Zengar
12-26-2008, 03:58 AM
Strange indeed... Does it work if you skip the mipmaps? (I mean, if you just load the texture and use linear filtering)

Lillefix
12-26-2008, 07:29 AM
I think I have a found a sample that partly works. Il come by later and tell you what I did wrong.

Lillefix
12-26-2008, 11:21 AM
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(&amp;width, sizeof(int), 1, mf); //Read in the width of the image

fseek(mf, 22, SEEK_SET);
fread(&amp;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(&amp;r, 1, 1, mf);
fread(&amp;b, 1, 1, mf);
fread(&amp;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.