Jump to content
  • Advertisement
Sign in to follow this  
Lonefox1

TGA header not recognising

This topic is 4835 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys i recently followed nehe's lesson 33 to create a TGA loader, the tga included with the example works perfectly, any other tga i create or get seems to fail on comparing the TGA header. im using this as the number to compare: GLubyte uTGAcompare[12] = {0,0,2,0,0,0,0,0,0,0,0,0}; and this to read in the header and check if uncompressed or compressed:
bool LoadTGA(Texture * texture, char * filename) //(pointe to tex struct, string for file name)
{
     FILE * fTGA;                   //declare file pointer
     fTGA = fopen(filename, "rb");  //open file for reading
     
     //error checking for file opening
     if(fTGA == NULL)     //if error
     {
             MessageBox(NULL,"file not found","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
             return false;
     }
     
     //attempt to read file header (first 12 bytes)
     if(fread(&tgaheader, sizeof(TGAHeader), 1, fTGA) == 0) //fread (buffer, number of bytes, number of times, file)
     {
             MessageBox(NULL,"could not read header","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
             return false;             
     }
     
     //now we try determine what type of file it is by comparing the new header to the two hard coded ones
     
    if(memcmp(uTGAcompare, &tgaheader, sizeof(tgaheader))==0) //if it matches uncompressed memcmp(pointer to buf 1, pointer to buf 2, num of bytes to compare)
     {
            //load uncompressed
            LoadUncompressedTGA(texture, filename, fTGA);
     }
     
     //if it matches compressed header:
     else if(memcmp(cTGAcompare, &tgaheader, sizeof(tgaheader))==0)
     {
          //load a compressed
          LoadCompressedTGA(texture, filename, fTGA);
     }
     else
     {
         MessageBox(NULL,"header numbers dont match compressed or uncompressed in TGA","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
         return false;
     }
}

its throwing me out at "header numbers dont match compressed or uncompressed in TGA" is there some sort of new TGA header standard? any help appreciated. lone

Share this post


Link to post
Share on other sites
Advertisement
That's a horrible way to load a TGA (but only in my humble opinion, of course :). The problem is probably that the data in the header of the TGA file you're trying to load is different to the hard-coded data. To fix this, you'll need to know some more about the structure of a TGA header...

If you peruse the TGA file format spec (you can find that at www.wotsit.org, if you're curious), you'll come across a detailed description of the header. Here's the header struct I use:


typedef struct tga_header_s
{

unsigned char ubIDLength;
unsigned char ubColourMapType;
unsigned char ubType;
unsigned char ubColourMapSpec[5];
unsigned short iOrigins[2];
unsigned short iWidth;
unsigned short iHeight;
unsigned char iColourDepth;
unsigned char iImageAttribs;

} tga_header_t;




This struct completely does away with the two that the NeHe tutorial uses (TGAHeader and TGA), and you only need one fread call to read the header as a result. Now that we know the structure of a TGA header, we can identify from uTGAcompare[12] that your problem is something to do with the ubType field. There are a bunch of types. They are:

0 - No Image Data Included
1 - Uncompressed, Color-mapped Image
2 - Uncompressed, True-color Image
3 - Uncompressed, Black-and-white Image
9 - Run-length encoded, Color-mapped Image
10 - Run-length encoded, True-color Image
11 - Run-length encoded, Black-and-white Image

For your code to succeed, a TGA file needs to be of type 2 or type 10 (the 2 and 10 in uTGAcompare and cTGAcompare respectively). The TGA files you are trying to load must be of a different type. What you need to do is use the header above, examine the ubType field to see what kind of image you're dealing with, and employ the right code to load it. This is much cleaner than the NeHe code, and much more readable. I'd suggest you make the changes, then print out the ubType field somehow (use MessageBox or something), so you can find out the type of the files you're trying to load.

Share this post


Link to post
Share on other sites
Hi Insanity

@Lonefox1:

I have written a image loading class for my gamedev library which will serve as the foundation of all my future project *hence codereuse*
The uncompressed TRUE COLOR loading code is tested and has been used for several years now the COMPRESSED RLE TRUE COLOR code is pretty new the color mapped versions will follow soon unfortunately i have no software that produces color mapped tgas

However here is the complete source code of the image class
I will enhance it from time to time to support more image types

I hope this helps you a litte bit

cya


namespace cross
{
//the standard cross image class
class image
{
public:
enum
{
MAX_TGA_HEADER_SIZE = 12,
MAX_FILENAME_LENGTH = 128,
PIXEL_PACKET_HEADER_FLAG = 0x80,
PIXEL_PACKET_HEADER_COUNT = 0x7F,
MAX_BYTES_PER_PIXEL = 4,
};
enum tga_m
{
IMG_TGA_UNCOMPRESSED_COLORMAP = 1,
IMG_TGA_UNCOMPRESSED_RGB = 2,
IMG_TAG_COMPRESSED_RLE_COLORMAP = 9,
IMG_TGA_COMPRESSED_RLE_RGB = 10,
};
enum img_colors_m
{
COLOR_RGB = 1,
COLOR_RGBA = 2,
COLOR_GRAYSCALE = 3,
COLOR_GRAYSCALE_ALPHA = 4,
};

class headerTGA
{
public:
ubyte8 m_uiIdentificationFieldLendth;
ubyte8 m_uiColorMapType;
ubyte8 m_uiImageType;
uint16 m_uiColorMapOrigin;
uint16 m_uiColorMapLength;
ubyte8 m_uiColorMapDepth;
uint16 m_uiLowerLeftCornerX;
uint16 m_uiLowerLeftCornerY;
uint16 m_uiWidth;
uint16 m_uiHeight;
ubyte8 m_uiPixelDepth;
ubyte8 m_uiImageDescriptorByte;
};
public:
// constructor
image()
{
m_uiBytes = 0;
m_uiFlags = 0;
m_uiWidth = 0;
m_uiHeight = 0;
m_uiVersion = 0;
m_uiBits = 0;
m_uiBytesPerPixel = 0;
m_uiType = 0;
m_pBuffer = NULL;
m_strFilename.reserve(MAX_FILENAME_LENGTH);
};

// load an arbitrary image
BOOL loadimage(const std::string strFilename, uint32 uiWidth = 0, uint32 uiHeight = 0)
{
if(strFilename.length() == 0)
return FALSE;


// search for file extensions to find the correct image loading function
//load .tga images
if(strFilename.find(".tga")!=std::string.npos)
{
if(loadtga(strFilename)==FALSE)
return FALSE;
}
//load .raw images
else if(strFilename.find(".raw") != std::string.npos)
{
if(uiWidth == 0 || uiHeight == 0)
return FALSE;

if(loadraw(strFilename, uiWidth, uiHeight) == FALSE)
return FALSE;
}
//load .img images
else if(strFilename.find(".img") != std::string.npos)
{
loadimg(strFilename);
}
//load .bmp images
else if(strFilename.find(".bmp") != std::string.npos)
{
loadbmp(strFilename);
}
m_strFilename = strFilename;

return TRUE;
};

// load .tga files
BOOL loadtga(const std::string strFilename)
{
std::ifstream file;
std::ios::pos_type sSize = 0;
uint32 i=0;
uint32 a=0;
uint32 b=0;
uint32 pixels;
ubyte8 ubSwap = 0;
ubyte8 ubHeader = 0;
ubyte8 ubCount =0;
ubyte8 ubPixel[MAX_BYTES_PER_PIXEL];

file.open(strFilename.c_str());

if(!file)
return FALSE;

//extract the header
file.read(reinterpret_cast<byte8*>(&header.tga),sizeof(headerTGA));

//set image properties
setbits(header.tga.m_uiPixelDepth);
setwidth(static_cast<uint32>(header.tga.m_uiWidth));
setheight(static_cast<uint32>(header.tga.m_uiHeight));

//calculate the number of pixels we have to read
pixels = m_uiWidth*m_uiHeight;

//try to create a buffer
if(createbuffer(pixels*m_uiBytesPerPixel) == FALSE)
{
file.close();
return FALSE;
}

switch(header.tga.m_uiImageType)
{
case IMG_TGA_UNCOMPRESSED_RGB:

//seek to the beginning of the image data field
file.seekg(18,std::ios::beg);

//read in the buffer
file.read(reinterpret_cast<byte8*>(m_pBuffer),m_uiBytes);

break;
case IMG_TGA_COMPRESSED_RLE_RGB:

//seek to the beginning of the image data field
file.seekg(18,std::ios::beg);

i=0;
//read until pixels pixels have been read
while(i<pixels)
{
//read the pixel header
file.read(reinterpret_cast<byte8*>(&ubHeader),sizeof(ubyte8));

//RLE encoded?
if(ubHeader & PIXEL_PACKET_HEADER_FLAG)
{
ubCount = ubHeader & PIXEL_PACKET_HEADER_COUNT + 1;

file.read(reinterpret_cast<byte8*>(ubPixel),m_uiBytesPerPixel);

for(a=0;a<ubCount;a++,i+=m_uiBytesPerPixel)
{
for(b=0;b<m_uiBytesPerPixel;b++)
{
m_pBuffer[i+b] = ubPixel;
}
}
}
}
break;
case IMG_TAG_COMPRESSED_RLE_COLORMAP:
break;
case IMG_TGA_UNCOMPRESSED_COLORMAP:
break;
}
file.close();


//swap the red and blue components
for(i=0;i<m_uiBytes;i+=m_uiBytesPerPixel)
{
ubSwap = m_pBuffer;
m_pBuffer = m_pBuffer[i+2];
m_pBuffer[i+2] = ubSwap;
}



return TRUE;
};

// load .raw files without header
BOOL loadraw(const std::string strFilename, uint32 uiWidth, uint32 uiHeight)
{
std::ifstream file;
std::ios::pos_type sSize = 0;

file.open(strFilename.c_str());

if(!file)
return FALSE;

if(createbuffer(uiWidth*uiHeight) == FALSE)
{
file.close();
return FALSE;
}

//get the file size
file.seekg(0,std::ios::end);
sSize = file.tellg();
file.seekg(0,std::ios::beg);
file.clear();

//see if the file is as large as specified
if(sSize < static_cast<int32>(uiWidth*uiHeight) )
{
file.close();
return FALSE;
}

file.read(reinterpret_cast<byte8*>(m_pBuffer),sSize);

file.close();

//set image dimensions
setwidth(uiWidth);
setheight(uiHeight);
setbits(8);

return TRUE;
};

//load .bmp files
BOOL loadbmp(const std::string strFilename)
{
return FALSE;
};

// load .img files, the standard format of the cross library
BOOL loadimg(const std::string strFilename)
{
return FALSE;
};

// save as .img file (used for converting images
BOOL saveimg(const std::string strFilename)
{
return FALSE;
};
private:
// create the storage buffer
BOOL createbuffer(uint32 uiSize)
{
if(uiSize == 0)
return FALSE;

if((m_pBuffer = new ubyte8[uiSize]) == NULL)
return FALSE;

m_uiBytes = uiSize;

return TRUE;
};

//set the image width
void setwidth(uint32 uiWidth)
{
m_uiWidth = uiWidth;
};

//set the image height
void setheight(uint32 uiHeight)
{
m_uiHeight = uiHeight;
};

//set the bits per pixel
void setbits(ubyte8 bits)
{
m_uiBits = bits;
setbytes_per_pixel(m_uiBits/8);
};

//set bytes per pixel
void setbytes_per_pixel(ubyte8 bytes)
{
m_uiBytesPerPixel = bytes;
};
private:
uint32 m_uiBytes;
uint32 m_uiFlags;
uint16 m_uiWidth;
uint16 m_uiHeight;
uint16 m_uiVersion;
ubyte8 m_uiBits;
ubyte8 m_uiBytesPerPixel;
ubyte8 m_uiType;
union imageHeaders
{
headerTGA tga;
}header;

ubyte8 *m_pBuffer;

std::string m_strFilename;
};
};

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!