PDA

View Full Version : Problem rendering bitmap (very long post!)



stodge
01-15-2003, 11:59 AM
This will be a long post so bear with me!

I have the following code to load a bitmap using SDL_Image:



void hbBaseMaterial::Load()
{
HBboolean alpha = HB_TRUE;
HBint x, y;
HBint pos = 0;

mSurface = IMG_Load(mFilename.c_str());
if (mSurface == NULL)
{
HBstring error = "Error loading material " + mFilename;
throw hbBaseException(error);
}

int dim = mSurface->w * mSurface->h * ((alpha) ? 4 : 3);

mData = new HBubyte[dim];
if(!mData)
{
throw hbBaseException("Error creating texture.");
}

for(y=(mSurface->h-1); y>-1; y--)
{
for(x=0; x<mSurface->w; x++)
{
Uint8 r,g,b,a;
// Note about getpixel function. It's a simple function
// taken from SDL's manuals. It just returns the color
// of specifig pixel in Uint32 format. Just ask me
// if you want me to show the function.
Uint32 color = getpixel(mSurface, x,y);

if(!alpha)
SDL_GetRGB(color, mSurface->format, &amp;r,&amp;g,&amp;b);
else
SDL_GetRGBA(color, mSurface->format, &amp;r,&amp;g,&amp;b,&amp;a);

mData[pos] = r; pos++;
mData[pos] = g; pos++;
mData[pos] = b; pos++;
if(alpha)
{
mData[pos] = a; pos++;
}
}
}
}


The following code sets up OpenGL initially:



glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0);

//glDepthFunc(GL_LESS);
//glEnable(GL_DEPTH_TEST);
//glShadeModel(GL_SMOOTH);
//glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

glViewport(0,0,mWidth, mHeight);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();


gluPerspective(45.0f, (GLfloat)mWidth/(GLfloat)mHeight, 0.1f, 100.0f);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glEnable(GL_TEXTURE_2D);


The following code sets up for 2D rendering:



// Setup the projection for 2D.
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

glOrtho(0, mWidth, mHeight, 0, 1.0, -1.0);

// Initialise the model matrix.
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

// Draw on top of everything.
glDisable(GL_DEPTH_TEST);


The following code ends the 2D rendering:



glEnable(GL_DEPTH_TEST);

// Restore the projection matrix.
glMatrixMode(GL_PROJECTION);
glPopMatrix();

glMatrixMode(GL_MODELVIEW);
glPopMatrix();


Now I can get a white rectangle displayed on the screen, using this code:



HBint = mMaterial->GetTextureId();
HBubyte* texture = (HBubyte *)mMaterial->GetData();

glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, mSizeX, mSizeY,
0, GL_RGBA, GL_UNSIGNED_BYTE, texture);

glBegin(GL_QUADS);

glTexCoord2i(mPosX, mPosY);
glVertex2i(mPosX, mPosY);

glTexCoord2i(mPosX+mSizeX, mPosY);
glVertex2i(mPosX+mSizeX, mPosY);

glTexCoord2i(mPosX+mSizeX, mPosY+mSizeY);
glVertex2i(mPosX+mSizeX, mPosY+mSizeY);

glTexCoord2i(mPosX, mPosY+mSizeY);
glVertex2i(mPosX, mPosY+mSizeY);

glEnd();


But that's it. I can't get OpenGL to display the bitmap. Can you see anything blatantly wrong here? I think I'm following basically what other people appear to be doing.

Many thanks!!

[This message has been edited by stodge (edited 01-15-2003).]

Bob
01-15-2003, 12:32 PM
A white texture generally indicates an invalid texture. A common problem is wrong size of the texture, make sure the size is a power of two (for example, 256x256, 256x512, 128x64).

You don't have to load the texture everytime you need it. Call glTexImage once on startup and just rebind it's id with glBindTexture.

Your texture cooridnates are wrong. Texture coordinates (for the whole image) is (0,0) for the lower left corner, and (1,1) for the upper right corner.

I am a little bit confused by the third and fourth code piece. Are they separate functions, or the same function? When are they called?

stodge
01-15-2003, 12:37 PM
The bitmap is 512x512. I double checked that, and I tried other bitmaps that I know with other programs.

I'm not loading the bitmap every frame; these are just code snippets and aren't shown in the corrent order. Sorry!

Each code snippet is in a different file; I'm writing a C++ engine.

The basic order from my first post is:

- setup OpenGL
- load the texture
- start 2D frame
- render the quad and texture
- end the 2D frame

So:



glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0);

//glDepthFunc(GL_LESS);
//glEnable(GL_DEPTH_TEST);
//glShadeModel(GL_SMOOTH);
//glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

glViewport(0,0,mWidth, mHeight);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();


gluPerspective(45.0f, (GLfloat)mWidth/(GLfloat)mHeight, 0.1f, 100.0f);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glEnable(GL_TEXTURE_2D);





void hbBaseMaterial::Load()
{
HBboolean alpha = HB_TRUE;
HBint x, y;
HBint pos = 0;

mSurface = IMG_Load(mFilename.c_str());
if (mSurface == NULL)
{
HBstring error = "Error loading material " + mFilename;
throw hbBaseException(error);
}

int dim = mSurface->w * mSurface->h * ((alpha) ? 4 : 3);

mData = new HBubyte[dim];
if(!mData)
{
throw hbBaseException("Error creating texture.");
}

for(y=(mSurface->h-1); y>-1; y--)
{
for(x=0; x<mSurface->w; x++)
{
Uint8 r,g,b,a;
// Note about getpixel function. It's a simple function
// taken from SDL's manuals. It just returns the color
// of specifig pixel in Uint32 format. Just ask me
// if you want me to show the function.
Uint32 color = getpixel(mSurface, x,y);

if(!alpha)
SDL_GetRGB(color, mSurface->format, &amp;r,&amp;g,&amp;b);
else
SDL_GetRGBA(color, mSurface->format, &amp;r,&amp;g,&amp;b,&amp;a);

mData[pos] = r; pos++;
mData[pos] = g; pos++;
mData[pos] = b; pos++;
if(alpha)
{
mData[pos] = a; pos++;
}
}
}
}





// Setup the projection for 2D.
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

glOrtho(0, mWidth, mHeight, 0, 1.0, -1.0);

// Initialise the model matrix.
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

// Draw on top of everything.
glDisable(GL_DEPTH_TEST);





HBint = mMaterial->GetTextureId();
HBubyte* texture = (HBubyte *)mMaterial->GetData();

glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, mSizeX, mSizeY,
0, GL_RGBA, GL_UNSIGNED_BYTE, texture);

glBegin(GL_QUADS);

glTexCoord2i(mPosX, mPosY);
glVertex2i(mPosX, mPosY);

glTexCoord2i(mPosX+mSizeX, mPosY);
glVertex2i(mPosX+mSizeX, mPosY);

glTexCoord2i(mPosX+mSizeX, mPosY+mSizeY);
glVertex2i(mPosX+mSizeX, mPosY+mSizeY);

glTexCoord2i(mPosX, mPosY+mSizeY);
glVertex2i(mPosX, mPosY+mSizeY);

glEnd();





glEnable(GL_DEPTH_TEST);

// Restore the projection matrix.
glMatrixMode(GL_PROJECTION);
glPopMatrix();

glMatrixMode(GL_MODELVIEW);
glPopMatrix();



Hopefully I have copied the code in the right order.

Thanks


[This message has been edited by stodge (edited 01-15-2003).]

stodge
01-15-2003, 12:45 PM
Sorry forgot this code that is used by the loading mechanism:



Uint32 getpixel(SDL_Surface *surface, int x, int y)
{
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

switch(bpp) {
case 1:
return *p;

case 2:
return *(Uint16 *)p;

case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
return p[0] << 16 | p[1] << 8 | p[2];
else
return p[0] | p[1] << 8 | p[2] << 16;

case 4:
return *(Uint32 *)p;

default:
return 0; /* shouldn't happen, but avoids warnings */
}
}


I tried just using:




mSurface = IMG_Load(mFilename.c_str());
if (mSurface == NULL)
{
HBstring error = "Error loading material " + mFilename;
throw hbBaseException(error);
}


and then passing (HBubyte*)mSurface->pixels to the glTexImage2D call, but that didn't make a difference.

Thanks

[This message has been edited by stodge (edited 01-15-2003).]

stodge
01-15-2003, 12:54 PM
I should point out that:

mPosX = 0
mPosY = 0
mSizeX = 100
mSizeY = 100

Bob
01-15-2003, 01:36 PM
HBint = mMaterial->GetTextureId();
HBubyte* texture = (HBubyte *)mMaterial->GetData();

glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, mSizeX, mSizeY,
0, GL_RGBA, GL_UNSIGNED_BYTE, texture);

glBegin(GL_QUADS);

glTexCoord2i(mPosX, mPosY);
glVertex2i(mPosX, mPosY);

glTexCoord2i(mPosX+mSizeX, mPosY);
glVertex2i(mPosX+mSizeX, mPosY);

glTexCoord2i(mPosX+mSizeX, mPosY+mSizeY);
glVertex2i(mPosX+mSizeX, mPosY+mSizeY);

glTexCoord2i(mPosX, mPosY+mSizeY);
glVertex2i(mPosX, mPosY+mSizeY);

glEnd();

You're not loading the bitmap every frame, you're loading the the bitmap as a texture each frame. That's what the call to glTexImage does. You only need to call that once.

And you say that mSizeX=100 and mSizeY=100. That means you're uploading a texture that is 100x100 pixels, which is an invalid size. 100 is not a power of two.

stodge
01-15-2003, 01:39 PM
So that won't work even though the texture is 512x512? The Quad is 100x100 but the texture is a power of two.

Bob
01-15-2003, 02:18 PM
The texture you're trying to upload is 100x100 pixels, and that won't work. The fact that the original image data is actually 512x512 is irrelevant.

Honestly, do you really understand texturing in OpenGL? I suggest you go to nehe.gamedev.net (http://nehe.gamedev.net) and read up on texturing a bit.

stodge
01-15-2003, 02:20 PM
I thought I did, but I guess not.

Thanks

stodge
01-15-2003, 07:49 PM
Thanks Bob. I went back and re-read Nehe's tutorial and it works now! http://www.opengl.org/discussion_boards/ubb/smile.gif

john
01-15-2003, 09:19 PM
I'd like to say that I think the original poster deserves large amounts of kudos. He had a problem, but instead of posting saying "help" and dumping his ~entire~ code like a number of posts I have seen, he tried to work out the problem by himself and annotated his thoughts and methods he used to try and resolve the problem in the post.

Good work, solider.

Bob
01-16-2003, 02:37 AM
I agree. Not very often you see well asked questions like this http://www.opengl.org/discussion_boards/ubb/smile.gif

stodge
01-16-2003, 06:25 AM
Well thanks! That's awfully kind of you. http://www.opengl.org/discussion_boards/ubb/smile.gif