PDA

View Full Version : Question regarding an example from Super Bibble



myst_iori
06-06-2011, 09:21 PM
I was playing around with one example of loading TGA image file from OpenGL SuperBible. Unfortunately, a black window appeared, no image was displayed. I checked the code, and realized that the sizeof( TGAHEADER ) was actually 20 while the author claimed it was 18 in one of his comments. I wonder this 2 bytes would causes the unexpected result. Any idea?


In this example, we load an TGA format image from a file called "Fire.tga" and display the image. See attached file.



typedef struct
{
GLbyte identsize; // Size of ID field that follows header (0)
GLbyte colorMapType; // 0 = None, 1 = paletted
GLbyte imageType; // 0 = none, 1 = indexed, 2 = rgb, 3 = grey, +8=rle
unsigned short colorMapStart; // First colour map entry
unsigned short colorMapLength; // Number of colors
unsigned char colorMapBits; // bits per palette entry
unsigned short xstart; // image x origin
unsigned short ystart; // image y origin
unsigned short width; // width in pixels
unsigned short height; // height in pixels
GLbyte bits; // bits per pixel (8 16, 24, 32)
GLbyte descriptor; // image descriptor
} TGAHEADER;


GLbyte *gltLoadTGA(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat)
{
FILE *pFile; // File pointer
TGAHEADER tgaHeader; // TGA file header
unsigned long lImageSize; // Size in bytes of image
short sDepth; // Pixel depth;
GLbyte *pBits = NULL; // Pointer to bits

// Default/Failed values
*iWidth = 0;
*iHeight = 0;
*eFormat = GL_BGR_EXT;
*iComponents = GL_RGB8;

// Attempt to open the fil
pFile = fopen(szFileName, "rb");
if(pFile == NULL)
return NULL;

// Read in header (binary)
fread(&tgaHeader, 18/* sizeof(TGAHEADER)*/, 1, pFile);

// Do byte swap for big vs little endian
#ifdef __APPLE__
LITTLE_ENDIAN_WORD(&tgaHeader.colorMapStart);
LITTLE_ENDIAN_WORD(&tgaHeader.colorMapLength);
LITTLE_ENDIAN_WORD(&tgaHeader.xstart);
LITTLE_ENDIAN_WORD(&tgaHeader.ystart);
LITTLE_ENDIAN_WORD(&tgaHeader.width);
LITTLE_ENDIAN_WORD(&tgaHeader.height);
#endif


// Get width, height, and depth of texture
*iWidth = tgaHeader.width;
*iHeight = tgaHeader.height;
sDepth = tgaHeader.bits / 8;

// Put some validity checks here. Very simply, I only understand
// or care about 8, 24, or 32 bit targa's.
if(tgaHeader.bits != 8 && tgaHeader.bits != 24 && tgaHeader.bits != 32)
return NULL;

// Calculate size of image buffer
lImageSize = tgaHeader.width * tgaHeader.height * sDepth;

// Allocate memory and check for success
pBits = (GLbyte*)malloc(lImageSize * sizeof(GLbyte));
if(pBits == NULL)
return NULL;

// Read in the bits
// Check for read error. This should catch RLE or other
// weird formats that I don't want to recognize
if(fread(pBits, lImageSize, 1, pFile) != 1)
{
free(pBits);
return NULL;
}

// Set OpenGL format expected
switch(sDepth)
{
case 3: // Most likely case
*eFormat = GL_BGR_EXT;
*iComponents = GL_RGB8;
break;
case 4:
*eFormat = GL_BGRA_EXT;
*iComponents = GL_RGBA8;
break;
case 1:
*eFormat = GL_LUMINANCE;
*iComponents = GL_LUMINANCE8;
break;
};


// Done with File
fclose(pFile);

// Return pointer to image data
return pBits;
}


//////////////////////////////////////////////////////////////////
// This function does any needed initialization on the rendering
// context.
void SetupRC()
{
// Black background
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}


///////////////////////////////////////////////////////////////////////
// Called to draw scene
void RenderScene(void)
{
GLbyte *pImage = NULL;
GLint iWidth, iHeight, iComponents;
GLenum eFormat;

// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT);

// Targa's are 1 byte aligned
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

// Load the TGA file, get width, height, and component/format information
pImage = gltLoadTGA("Fire.tga", &iWidth, &iHeight, &iComponents, &eFormat);

// Use Window coordinates to set raster position
glRasterPos2i(0, 0);

// Draw the pixmap
if(pImage != NULL)
glDrawPixels(iWidth, iHeight, eFormat, GL_UNSIGNED_BYTE, pImage);

// Don't need the image data anymore
free(pImage);

// Do the buffer Swap
glutSwapBuffers();
}


//////////////////////////////////////////////////////////////
// For this example, it really doesn't matter what the
// projection is since we are using glWindowPos
void ChangeSize(int w, int h)
{
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0)
h = 1;

glViewport(0, 0, w, h);

// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

// Set the clipping volume
gluOrtho2D(0.0f, (GLfloat) w, 0.0, (GLfloat) h);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

/////////////////////////////////////////////////////////////
// Main program entrypoint
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GL_DOUBLE);
glutInitWindowSize(512 ,512);
glutCreateWindow("OpenGL Image Loading");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);

SetupRC();
glutMainLoop();

return 0;
}

RefleX
06-07-2011, 12:21 AM
Why are you loading your image every frame?

The header size for tga is 18 bytes you can find out about the formating of image formats on wikipedia, here's the link for TGA (http://en.wikipedia.org/wiki/Truevision_TGA). If you still having problems try to spit out some information to debug with so you can find the problem.

Dan Bartlett
06-07-2011, 05:35 AM
Your compiler is likely inserting a couple of extra bytes to ensure your fields are naturally aligned. In your case, it ensures that 2 byte types are aligned on 2 byte boundaries.

typedef struct
{
GLbyte identsize; // Size of ID field that follows header (0)
GLbyte colorMapType; // 0 = None, 1 = paletted
GLbyte imageType; // 0 = none, 1 = indexed, 2 = rgb, 3 = grey, +8=rle
[* one byte padding to ensure colorMapStart is naturally aligned*]
unsigned short colorMapStart; // First colour map entry
unsigned short colorMapLength; // Number of colors
unsigned char colorMapBits; // bits per palette entry
[* one byte padding to ensure xstart is naturally aligned *]
unsigned short xstart; // image x origin
unsigned short ystart; // image y origin
unsigned short width; // width in pixels
unsigned short height; // height in pixels
GLbyte bits; // bits per pixel (8 16, 24, 32)
GLbyte descriptor; // image descriptor
} TGAHEADER;
Using #pragma pack might help you, see http://en.wikipedia.org/wiki/Data_structure_alignment for more info.

#pragma pack(push) /* push current alignment to stack */
#pragma pack(1) /* set alignment to 1 byte boundary */
[*struct declaration*]
#pragma pack(pop) /* restore original alignment from stack */

myst_iori
06-07-2011, 07:39 PM
@Dan Bartlett: Thank you, #prama pack actually solved the problem.
@RefleX: Thanks for pointing that out. Very good point.