mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
1574 lines
No EOL
35 KiB
C++
1574 lines
No EOL
35 KiB
C++
/*
|
|
|
|
Modified by Chris Losinger for Smaller Animals Software's ImgLib/ImgDLL.
|
|
Esp. RGB->BGR and row order switches. 9/98
|
|
*/
|
|
#include <stdio.h>
|
|
#include <io.h>
|
|
|
|
/*
|
|
TGADefs.h - Tye and Constant declaration file
|
|
This File defines the Types, and the Constant Values used by the
|
|
TGAFile Class.
|
|
|
|
Created By: Timothy A. Bish
|
|
Created On: 08/18/98
|
|
*/
|
|
|
|
#ifndef TGADEFSH
|
|
#define TGADEFSH
|
|
|
|
#include <windows.h>
|
|
|
|
#pragma pack(1) // Align the structure on byte boundries...
|
|
|
|
// Possible Image Types
|
|
#define TGA_NOIMAGETYPE 0 // No Image Data Included in Image
|
|
#define TGA_MAPRGBTYPE 1 // Colormapped Image Data - No Compression
|
|
#define TGA_RAWRGBTYPE 2 // Truecolor Image Data - No Compression
|
|
#define TGA_RAWMONOTYPE 3 // Monochrome Image Data - No Compression
|
|
#define TGA_MAPENCODETYPE 9 // Colormapped Image Data - Compressed RLE
|
|
#define TGA_RAWENCODETYPE 10 // Truecolor Image Data - Compressed RLE
|
|
#define TGA_MONOENCODETYPE 11 // Monochrome Image Data - Compressed RLE
|
|
// Version Macro
|
|
#define TGA_VERSIONONE 1 // Version 1 File Format
|
|
#define TGA_VERSIONTWO 2 // Version 2 File Format
|
|
// File Read Write Modes
|
|
const int GREYSC = 0; // Image is Greyscale
|
|
const int COLOUR = 1; // Image is Color
|
|
const int MAPPED = 2; // Image has a Color Map
|
|
const int RLENCO = 4; // Image is RLE Encoded
|
|
|
|
// 18 Byte Sturcture representin the basic definitions of
|
|
// the image
|
|
typedef struct _aTGAHEADER
|
|
{
|
|
BYTE IDLength; // 00h Size of ID Field
|
|
BYTE ColorMapType; // 01h Color Map Type
|
|
BYTE ImageType; // 02h Image Type Code
|
|
WORD CMapStart; // 03h Color Map Origin
|
|
WORD CMapLength; // 05h Color Map Length
|
|
BYTE CMapDepth; // 07h Color Map Depth
|
|
WORD XOffset; // 08h X origin of Image
|
|
WORD YOffset; // 0Ah Y origin of Image
|
|
WORD Width; // 0Ch Width of Image
|
|
WORD Height; // 0Eh Height of Image
|
|
BYTE PixelDepth; // 10h Image Pixel Size
|
|
BYTE ImageDescriptor; // 11h Image Description Byte
|
|
} TGAHEADER;
|
|
|
|
// The footer is 26 Bytes in length and is always at the end of a
|
|
// TGA v2.0 file.
|
|
typedef struct _aTGAFOOTER
|
|
{
|
|
DWORD ExtensionOffset; // Extension Area Offset
|
|
DWORD DeveloperOffset; // Developer Directory Offset
|
|
CHAR Signature[18]; // TGA Signature
|
|
} TGAFOOTER;
|
|
|
|
typedef struct _aTGATAG
|
|
{
|
|
WORD TagNumber; // ID Number of the Tag
|
|
DWORD DataOffset; // Offset Location of the Tag
|
|
DWORD DataSize; // Size of the Tag Data in Bytes
|
|
} TGATAG;
|
|
|
|
// The extension area is basically the second header in the TGA v2.0
|
|
// file format.
|
|
typedef struct _aTGAEXTENSION
|
|
{
|
|
WORD Size; // Extension Size
|
|
CHAR AuthorName[41]; // Author Name
|
|
CHAR AuthorComment[324]; // Author Comment
|
|
WORD StampMonth; // Date/Time Stamp: Month
|
|
WORD StampDay; // Date/Time Stamp: Day
|
|
WORD StampYear; // Date/Time Stamp: Year
|
|
WORD StampHour; // Date/Time Stamp: Hour
|
|
WORD StampMinute; // Date/Time Stamp: Minute
|
|
WORD StampSecond; // Date/Time Stamp: Second
|
|
CHAR JobName[41]; // Job Name/ID
|
|
WORD JobHour; // Job Time: Hours
|
|
WORD JobMinute; // Job Time: Minutes
|
|
WORD JobSecond; // Job Time: Seconds
|
|
CHAR SoftwareId[41]; // Software ID
|
|
WORD VersionNumber; // Version Number of Software
|
|
BYTE VersionLetter; // Version Letter of Software
|
|
DWORD KeyColor; // Key Color
|
|
WORD PixelNumerator; // Pixel Aspect Ratio
|
|
WORD PixelDenominator; // Pixel Aspect Ratio
|
|
WORD GammaNumerator; // Gamma Value
|
|
WORD GammaDenominator; // Gamma Value
|
|
DWORD ColorOffset; // Color Correction Offset
|
|
DWORD StampOffset; // Postage Stamp Offset
|
|
DWORD ScanOffset; // Scanline Table Offset
|
|
BYTE AttributesType; // Attributes Type
|
|
} TGAEXTENSION;
|
|
|
|
// The Color Correction Table is an array of 2048 Bytes in length, which
|
|
// contians 256 entries used to store the values used for color remapping.
|
|
typedef struct _aTGACOLORCORRECTIONTABLE
|
|
{
|
|
SHORT Alpha; // Alpha Channel Seldom Used
|
|
SHORT Red; // Red Value of Correction
|
|
SHORT Green; // Green Value of Correction
|
|
SHORT Blue; // Green Value of Correction
|
|
} TGACOLORCORRECTIONTABLE;
|
|
|
|
#define TRIALVERSION -1 // LIB was not initialized with a registered key
|
|
|
|
#define IMGOK 0 // no err
|
|
#define MEMERR 1 // out of mem
|
|
#define FILEOPENERR 2 // error on file open
|
|
#define FILEREADERR 3 // error on file read
|
|
#define FILEWRITEERR 4 // error on file write
|
|
#define BADPARAMERR 5 // bad user param
|
|
#define INVALIDBMPERR 6 // bad BMP file
|
|
#define BMPRLEERR 7 // we don't do compressed (RLE) BMP files
|
|
#define INVALIDGIFERR 8 // bad GIF file
|
|
#define INVALIDJPGERR 9 // bad JPG file
|
|
#define IMGDCERR 10 // error with device context
|
|
#define IMGDIBERR 11 // problem with a GetDIBits call
|
|
#define NOGIFERR 12 // GIF support disabled
|
|
#define IMGNORESOURCE 13 // resource not found
|
|
#define CALLBACKCANCEL 14 // callback returned FALSE - operation aborted
|
|
#define INVALIDPNGERR 15 // bad PNG file
|
|
#define PNGCREATEERR 16 // internal PNG lib behavior - contact smaller animals s.w.
|
|
#define IMGDLLINTERNAL 17 // misc unexpected behavior error - contact smaller animals s.w.
|
|
#define IMGFONTERR 18 // trouble creating a font object
|
|
#define INTTIFFERR 19 // misc internal TIFF error
|
|
#define INVALIDTIFFERR 20 // invalid TIFF file
|
|
#define TIFFLZWNOTSUPPORTED 21 // this will not read TIFF-LZW iamges
|
|
#define INVALIDPCXERR 22 // invalid PCX image
|
|
#define CREATEBMPERR 23 // a call to the fn CreateCompatibleBitmap failed
|
|
#define IMGNOLINES 24 // end of an image while using single-line de/compression
|
|
#define GETDIBERR 25 // error during a call to GetDIBits
|
|
#define DEVOPNOSUPPORT 26 // device does not support an operation required by this function
|
|
#define INVALIDWMF 27 // invalid windows metafile
|
|
#define DEPTHMISMATCHERR 28 // the file was not of the requested bit-depth
|
|
#define INVALIDTGAERR 35 // Invalid TGA File
|
|
#define NOTGATHUMBNAIL 36 // No TGA Thumbnail in the file
|
|
|
|
#pragma pack()
|
|
|
|
#endif
|
|
|
|
class TGAFile
|
|
{
|
|
|
|
public:
|
|
|
|
// parameters
|
|
__int32 m_error;
|
|
|
|
public:
|
|
|
|
// operations
|
|
|
|
TGAFile();
|
|
|
|
BOOL IsFileTGA(const char * fileName);
|
|
|
|
LPVOID LoadTGA( const char *fileName, // Name of file
|
|
UINT32 *width, // Width in Pixel
|
|
UINT32 *height); // Height
|
|
|
|
HGLOBAL LoadTGA8Bit(const char *fileName, // Name of File
|
|
UINT32 *width, // Width in pixels
|
|
UINT32 *height, // Height
|
|
RGBQUAD *pal); // Palette of RGBQUADS
|
|
|
|
BOOL GetTGADims(const char *fileName,
|
|
UINT32 *width,
|
|
UINT32 *height);
|
|
|
|
BOOL SaveTGA32(const char * fileName, // output path
|
|
BYTE *inBuf, // RGB buffer
|
|
UINT32 width, // size
|
|
UINT32 height);
|
|
|
|
BOOL Save8BitTGA(const char * fileName, // output path
|
|
BYTE *colormappedbuffer, // one BYTE per pixel colomapped image
|
|
UINT32 width, // Width of image
|
|
UINT32 height, // Height of image
|
|
__int32 colors, // number of colors (number of RGBQUADs)
|
|
RGBQUAD *colormap); // array of RGBQUADs
|
|
|
|
HGLOBAL LoadTGAThumbnail(const char *fileName, // Name of file
|
|
UINT32 *width, // Width in Pixel
|
|
UINT32 *height); // Height
|
|
|
|
private:
|
|
|
|
// Parameters
|
|
|
|
char TGA_ImageIDFeild[256];// Text in file
|
|
BYTE TGA_Attribute; // Number of attribute bytes per pixel
|
|
// i.e. 1 for T16 and 8 for T32
|
|
UINT32 mode; // Mode of current Read or Write
|
|
|
|
// RLE Decompression Variables
|
|
BYTE Red, // Stores pixel value for
|
|
Grn, // RLE series of oixels
|
|
Blu,
|
|
Alpha;
|
|
UINT32 l; // Used when 8 bit files use RLE
|
|
__int32 RLECount, RLEFlag; // Indicates whether the RLE series
|
|
// is still going or is finished
|
|
|
|
private:
|
|
|
|
// Operations
|
|
|
|
__int32 TGA_GetFileVersion(FILE *fp); // Determines whether this is a V1.0
|
|
// or V2.0 TGA File
|
|
BOOL TGA_GetMapEntry(BYTE *Red, // Get the Color Values out of the
|
|
BYTE *Green, // Color map in the TGA File
|
|
BYTE *Blue, // Return TRUE on Success
|
|
BYTE *Alpha,
|
|
FILE *fp,
|
|
UINT32 Depth);
|
|
|
|
// version that takes a file ptr
|
|
BOOL TGA_GetPixelValue(BYTE *Red, // Get and parse a single pixel value
|
|
BYTE *Grn, // from the TGA file. Handles Unencoding
|
|
BYTE *Blu, // of RLE encoded files.
|
|
BYTE *Alp, // plus Alpha (08jan00/bgw)
|
|
FILE *fp,
|
|
UINT32 PixelDepth,
|
|
RGBQUAD *CMap);
|
|
|
|
// version that takes a buffer ptr
|
|
BOOL TGA_GetPixelValue(BYTE *Red, // Get and parse a single pixel value
|
|
BYTE *Grn, // from the TGA file. Handles Unencoding
|
|
BYTE *Blu, // of RLE encoded files.
|
|
BYTE *Alp, // plus Alpha (08jan00/bgw)
|
|
BYTE ** ppTGAData,
|
|
UINT32 PixelDepth,
|
|
RGBQUAD *CMap);
|
|
};
|
|
|
|
//#define MAX_IMAGEREAD_BUFFER 65535
|
|
//BYTE * gpImageReadBuffer = NULL;
|
|
//long glImageReadBufferSize = 0;
|
|
//BYTE * gpImageReadBufPos = NULL;
|
|
//
|
|
//
|
|
//typedef struct tagTGAColorComponents
|
|
// {
|
|
// BYTE red;
|
|
// BYTE green;
|
|
// BYTE blue;
|
|
// BYTE alpha;
|
|
// } TGAColorComponents;
|
|
|
|
/* TGA File REader Classs Implementation File
|
|
This Implementation Allows the reading of TGA (Targa) Files
|
|
into an RGB buffer. Also the class allows an RGB Buffer to be
|
|
written to a TGA File. There is also a function to determine
|
|
the dimensions of a TGA file.
|
|
|
|
Created By: Timothy A. Bish
|
|
Created On: 08/17/98
|
|
|
|
*/
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// No Much going on here
|
|
TGAFile::TGAFile()
|
|
{
|
|
m_error = IMGOK;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// GetTGADimns
|
|
// Find dims of the image in a TGA file
|
|
// Returns - TRUE on success
|
|
BOOL
|
|
TGAFile::GetTGADims(const char * fileName, UINT32 * width, UINT32 * height)
|
|
{
|
|
// for safety
|
|
*width = 0;
|
|
*height = 0;
|
|
FILE * fp;
|
|
TGAHEADER tgahd;
|
|
|
|
// Init the file Header to all zeros
|
|
ZeroMemory(&tgahd, sizeof(tgahd));
|
|
|
|
// init
|
|
m_error = IMGOK;
|
|
fp = fopen(fileName, "rb");
|
|
|
|
if(fp == NULL)
|
|
{
|
|
m_error = FILEOPENERR;
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the Header
|
|
if(fread(&tgahd, 1, sizeof(TGAHEADER), fp) != sizeof(TGAHEADER))
|
|
{
|
|
m_error = FILEREADERR;
|
|
fclose(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
// Check fo valid data in structure
|
|
if(tgahd.PixelDepth > 32)
|
|
{
|
|
// I don't do Pixel Depths Bigger than 32
|
|
m_error = INVALIDTGAERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Anything other than the standard TGA types
|
|
// and I quit
|
|
switch(tgahd.ImageType)
|
|
{
|
|
case TGA_MAPRGBTYPE:
|
|
case TGA_RAWRGBTYPE:
|
|
case TGA_RAWMONOTYPE:
|
|
case TGA_MAPENCODETYPE:
|
|
case TGA_RAWENCODETYPE:
|
|
case TGA_MONOENCODETYPE:
|
|
break;
|
|
|
|
default:
|
|
m_error = INVALIDTGAERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Grab the Image dimensions
|
|
*width = tgahd.Width;
|
|
*height = tgahd.Height;
|
|
fclose(fp);
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* NAME:
|
|
* TGAFile::IsFileTGA
|
|
*
|
|
* DESCRIPTION:
|
|
* Description goes here...
|
|
*
|
|
*******************************************************************************/
|
|
BOOL
|
|
TGAFile::IsFileTGA(const char * fileName)
|
|
{
|
|
TGAHEADER tgahd;
|
|
FILE * fp;
|
|
|
|
ZeroMemory(&tgahd, sizeof(tgahd));
|
|
fp = fopen(fileName, "rb");
|
|
long rc = fread(&tgahd, 1, sizeof(TGAHEADER), fp);
|
|
fclose(fp);
|
|
|
|
if( (rc == sizeof(TGAHEADER)) && // must be big enough for a header...
|
|
(tgahd.PixelDepth == 32) && // 32-bit TGAs only
|
|
(tgahd.ImageType == TGA_RAWRGBTYPE) ) // Raw RGBA format only
|
|
return(TRUE);
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// LoadTGA
|
|
// load a .TGA file - 1,4,8,24,32 bit
|
|
// allocates and returns an RGB buffer containing the image.
|
|
// modifies width and height accordingly - NULL, 0, 0 on error
|
|
LPVOID
|
|
TGAFile::LoadTGA(const char * fileName, UINT32 * width, UINT32 * height)
|
|
{
|
|
LPVOID pNew = NULL;
|
|
BYTE * pRGB = NULL;
|
|
BYTE Alpha;
|
|
|
|
TGAHEADER tgahd;
|
|
|
|
BYTE TGA_Origin = 0;
|
|
|
|
RGBQUAD CColMap[256];
|
|
|
|
// for safety
|
|
*width = 0;
|
|
*height = 0;
|
|
|
|
// init
|
|
m_error = IMGOK;
|
|
|
|
// Init the file Header to all zeros
|
|
ZeroMemory(&tgahd, sizeof(tgahd));
|
|
FILE * fp;
|
|
fp = fopen(fileName, "rb");
|
|
|
|
if(fp == NULL)
|
|
{
|
|
m_error = FILEOPENERR;
|
|
return FALSE;
|
|
}
|
|
|
|
// Read the TGA Header
|
|
long rc = fread(&tgahd, 1, sizeof(TGAHEADER), fp);
|
|
|
|
if(rc != sizeof(TGAHEADER))
|
|
{
|
|
m_error = FILEREADERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Check fo valid data in structure
|
|
if((tgahd.PixelDepth> 32) || (tgahd.PixelDepth<8))
|
|
{
|
|
// I don't do Pixel Depths Bigger than 32
|
|
m_error = INVALIDTGAERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Anything other than the standard TGA types
|
|
// and I quit
|
|
switch(tgahd.ImageType)
|
|
{
|
|
case TGA_MAPRGBTYPE:
|
|
case TGA_RAWRGBTYPE:
|
|
case TGA_RAWMONOTYPE:
|
|
case TGA_MAPENCODETYPE:
|
|
case TGA_RAWENCODETYPE:
|
|
case TGA_MONOENCODETYPE:
|
|
break;
|
|
|
|
default:
|
|
m_error = INVALIDTGAERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Set the number of Color Planes
|
|
if(tgahd.ImageType == TGA_RAWMONOTYPE)
|
|
{
|
|
mode = GREYSC;
|
|
}
|
|
else
|
|
{
|
|
mode = COLOUR;
|
|
}
|
|
|
|
// Read the ID Descriptor if present
|
|
if(tgahd.IDLength != 0)
|
|
{
|
|
// Read the TGA Comments
|
|
long rc = fread(&TGA_ImageIDFeild, 1, tgahd.IDLength, fp);
|
|
|
|
if(rc != tgahd.IDLength)
|
|
{
|
|
m_error = FILEREADERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Parse the Image Descriptor
|
|
TGA_Attribute = (BYTE)(tgahd.ImageDescriptor & 0x0f);
|
|
TGA_Origin = (BYTE)((tgahd.ImageDescriptor & 0x20) / 32);
|
|
|
|
// If present read the color map
|
|
if(tgahd.ColorMapType != 0)
|
|
{
|
|
// Get the color map
|
|
for(__int32 i = 0; i < (tgahd.CMapStart + tgahd.CMapLength); i++)
|
|
{
|
|
TGA_GetMapEntry(&CColMap[i].rgbRed, &CColMap[i].rgbGreen, &CColMap[i].rgbBlue, &Alpha, fp, tgahd.CMapDepth);
|
|
}
|
|
|
|
// If the TGA file actually needs the color map
|
|
// Set the mode to show this
|
|
if((tgahd.ImageType != TGA_RAWRGBTYPE) && (tgahd.ImageType != TGA_RAWMONOTYPE) && (tgahd.ImageType != TGA_RAWENCODETYPE))
|
|
mode = mode | MAPPED;
|
|
}
|
|
|
|
// Check Run Length Encoding
|
|
if((tgahd.ImageType == TGA_MAPENCODETYPE) || (tgahd.ImageType == TGA_RAWENCODETYPE) || (tgahd.ImageType == TGA_MONOENCODETYPE))
|
|
mode = mode | RLENCO;
|
|
|
|
long lImgDataSize = (tgahd.Height * tgahd.Width) * (tgahd.PixelDepth / 8);
|
|
|
|
// Allocate the memory buffers
|
|
pNew = malloc(lImgDataSize);
|
|
// pNew = (LPVOID) theApp.m_TGABuffer.GetBuffer((size_t)(tgahd.Width * tgahd.Height * 4));
|
|
|
|
if(pNew == NULL)
|
|
{
|
|
m_error = MEMERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
else
|
|
pRGB = (BYTE *)pNew;
|
|
|
|
// RGB from image Data
|
|
//DWORD destOffset = 0;
|
|
|
|
RLECount = 0;
|
|
RLEFlag = 0;
|
|
|
|
// //
|
|
// // (re-)alocate a local image buffer to read the TGA formatted
|
|
// // data into. this avoids the huge critical-section delays in
|
|
// // every call to getc().
|
|
// //
|
|
// long lBufSize = lImgDataSize + 16; // slop
|
|
// if(lBufSize < MAX_IMAGEREAD_BUFFER)
|
|
// lBufSize = MAX_IMAGEREAD_BUFFER;
|
|
// if(glImageReadBufferSize < lBufSize)
|
|
// {
|
|
// if(gpImageReadBuffer)
|
|
// {
|
|
// free(gpImageReadBuffer);
|
|
// gpImageReadBuffer = NULL; // tidy
|
|
// gpImageReadBufPos = NULL;
|
|
// }
|
|
//
|
|
// glImageReadBufferSize = lBufSize;
|
|
// gpImageReadBuffer = (BYTE *) malloc(glImageReadBufferSize);
|
|
//
|
|
// if(!gpImageReadBuffer)
|
|
// {
|
|
// glImageReadBufferSize = 0;
|
|
// return NULL; // v. bad news.
|
|
// }
|
|
// TRACE("* (Re-)Allocated local TGA data buffer: %d bytes\n", glImageReadBufferSize);
|
|
// }
|
|
|
|
//
|
|
// Read the TGA format data into the local buffer
|
|
//
|
|
long lTGABytesRead = fread(pRGB, 1, lImgDataSize, fp);
|
|
if(lTGABytesRead != lImgDataSize)
|
|
{
|
|
// ASSERT(0);
|
|
//free(pNew);
|
|
return NULL;
|
|
}
|
|
|
|
// Grab the image dimensions
|
|
*width = tgahd.Width;
|
|
*height = tgahd.Height;
|
|
|
|
// Clean Up
|
|
fclose(fp);
|
|
m_error = IMGOK;
|
|
return pNew;
|
|
|
|
///////////////
|
|
// all out...dorks didn't realize that TGA's memory format == DIBSections!
|
|
//////////////
|
|
#if 0
|
|
//
|
|
// Read the TGA format data into the local buffer
|
|
//
|
|
long lTGABytesRead = fread(gpImageReadBuffer, 1, lImgDataSize, fp);
|
|
if(lTGABytesRead != lImgDataSize)
|
|
{
|
|
ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
gpImageReadBufPos = gpImageReadBuffer;
|
|
|
|
// copy DWORDs instead of bytes...
|
|
UINT32 * pPixel = (UINT32 *) pRGB;
|
|
UINT32 * pReadBufPixel = (UINT32 *) gpImageReadBufPos;
|
|
|
|
for(UINT32 row = 0; row < tgahd.Height; row++)
|
|
{
|
|
for(UINT32 col = 0; col < tgahd.Width; col++)
|
|
{
|
|
|
|
// Reset RLE Counters
|
|
BYTE Red, Grn, Blu, Alp;
|
|
TGA_GetPixelValue(&Red, &Grn, &Blu, &Alp, &gpImageReadBufPos, tgahd.PixelDepth, CColMap);
|
|
|
|
// Invert if the image origin is in Bottom left
|
|
if(TGA_Origin != 0)
|
|
{ // Bottom Left Origin
|
|
destOffset = ((tgahd.Height -1) -row) * tgahd.Width * 4 + col * 4;
|
|
*(pRGB + destOffset + 0) = Red;
|
|
*(pRGB + destOffset + 1) = Grn;
|
|
*(pRGB + destOffset + 2) = Blu;
|
|
*(pRGB + destOffset + 3) = Alp;
|
|
}
|
|
else
|
|
{ // Top Left Origin
|
|
*(pRGB + destOffset + 0) = Red;
|
|
*(pRGB + destOffset + 1) = Grn;
|
|
*(pRGB + destOffset + 2) = Blu;
|
|
*(pRGB + destOffset + 3) = Alp;
|
|
destOffset += 4;
|
|
}
|
|
#if 0 // even faster!
|
|
// Red = *(gpImageReadBufPos++);
|
|
// Grn = *(gpImageReadBufPos++);
|
|
// Blu = *(gpImageReadBufPos++);
|
|
// Alp = *(gpImageReadBufPos++);
|
|
//
|
|
// *(pRGB + destOffset + 0) = Red;
|
|
// *(pRGB + destOffset + 1) = Grn;
|
|
// *(pRGB + destOffset + 2) = Blu;
|
|
// *(pRGB + destOffset + 3) = Alp;
|
|
// destOffset += 4;
|
|
|
|
// TGAColorComponents rgbaPixel;
|
|
|
|
*(pPixel++) = *(pReadBufPixel++);
|
|
|
|
// BYTE * p = pRGB + destOffset;
|
|
// *(p++) = *(gpImageReadBufPos++);
|
|
// *(p++) = *(gpImageReadBufPos++);
|
|
// *(p++) = *(gpImageReadBufPos++);
|
|
// *(p++) = *(gpImageReadBufPos++);
|
|
// destOffset += 4;
|
|
#endif
|
|
} // loop col
|
|
} // loop row
|
|
|
|
// Grab the image dimensions
|
|
*width = tgahd.Width;
|
|
*height = tgahd.Height;
|
|
|
|
// Clean Up
|
|
fclose(fp);
|
|
m_error = IMGOK;
|
|
return pNew;
|
|
#endif
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// LoadTGA8Bit
|
|
// Loads in an 8 Bit buffer and the color palette that is
|
|
// associated with that buffer, if the image is 8 Bit, else
|
|
// it sets global error to DEPTHMISMATCHERR
|
|
HGLOBAL
|
|
TGAFile::LoadTGA8Bit(const char * fileName, // Name of File
|
|
UINT32 * width, // Width in pixels
|
|
UINT32 * height, // Height
|
|
RGBQUAD * pal) // Palette of RGBQUADS
|
|
{
|
|
HGLOBAL hNew = NULL;
|
|
BYTE * pRGB = NULL;
|
|
BYTE Alpha;
|
|
|
|
TGAHEADER tgahd;
|
|
|
|
BYTE TGA_Origin = 0;
|
|
|
|
// for safety
|
|
*width = 0;
|
|
*height = 0;
|
|
|
|
// init
|
|
m_error = IMGOK;
|
|
|
|
// Init the file Header to all zeros
|
|
ZeroMemory(&tgahd, sizeof(tgahd));
|
|
|
|
// Init the Palette to all zeros
|
|
ZeroMemory(pal, sizeof(pal));
|
|
FILE * fp;
|
|
fp = fopen(fileName, "rb");
|
|
|
|
if(fp == NULL)
|
|
{
|
|
m_error = FILEOPENERR;
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Read the TGA Header
|
|
long rc = fread(&tgahd, 1, sizeof(TGAHEADER), fp);
|
|
|
|
if(rc != sizeof(TGAHEADER))
|
|
{
|
|
m_error = FILEREADERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Check fo valid data in structure
|
|
if(tgahd.PixelDepth> 8)
|
|
{
|
|
// Not an 8bit Image
|
|
m_error = DEPTHMISMATCHERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Anything other than the standard TGA types
|
|
// and I quit
|
|
switch(tgahd.ImageType)
|
|
{
|
|
case TGA_MAPRGBTYPE:
|
|
case TGA_MAPENCODETYPE:
|
|
break;
|
|
|
|
default:
|
|
m_error = DEPTHMISMATCHERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Set the Color Mode
|
|
if(tgahd.ImageType == TGA_RAWMONOTYPE)
|
|
{
|
|
mode = GREYSC;
|
|
}
|
|
else
|
|
{
|
|
mode = COLOUR;
|
|
}
|
|
|
|
// Read the ID Descriptor if present
|
|
if(tgahd.IDLength != 0)
|
|
{
|
|
// Read the TGA Comments
|
|
long rc = fread(&TGA_ImageIDFeild, 1, tgahd.IDLength, fp);
|
|
|
|
if(rc != tgahd.IDLength)
|
|
{
|
|
m_error = FILEREADERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Parse the Image Descriptor
|
|
TGA_Attribute = (BYTE)(tgahd.ImageDescriptor & 0x0f);
|
|
TGA_Origin = (BYTE)((tgahd.ImageDescriptor & 0x20) / 32);
|
|
|
|
// If present read the color map
|
|
if(tgahd.ColorMapType != 0)
|
|
{
|
|
// Get the color map
|
|
for(__int32 i = 0; i < (tgahd.CMapStart + tgahd.CMapLength); i++)
|
|
{
|
|
TGA_GetMapEntry(&pal[i].rgbRed, &pal[i].rgbGreen, &pal[i].rgbBlue, &Alpha, fp, tgahd.CMapDepth);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_error = INVALIDTGAERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Check Run Length Encoding
|
|
if((tgahd.ImageType == TGA_MAPENCODETYPE) || (tgahd.ImageType == TGA_RAWENCODETYPE) || (tgahd.ImageType == TGA_MONOENCODETYPE))
|
|
mode = mode | RLENCO;
|
|
|
|
// Allocate the memory buffers
|
|
hNew = GlobalAlloc(GHND, tgahd.Width * tgahd.Height);
|
|
|
|
if(hNew == NULL)
|
|
{
|
|
m_error = MEMERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
pRGB = (BYTE *)GlobalLock(hNew);
|
|
|
|
if(pRGB == NULL)
|
|
{
|
|
m_error = MEMERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// RGB from image Data
|
|
DWORD destOffset = 0;
|
|
|
|
RLECount = 0;
|
|
RLEFlag = 0;
|
|
|
|
for(UINT32 row = 0; row < tgahd.Height; row++)
|
|
{
|
|
for(UINT32 col = 0; col < tgahd.Width; col++)
|
|
{
|
|
BYTE Red, Grn, Blu, Alp;
|
|
|
|
// Reset RLE Counters
|
|
TGA_GetPixelValue(&Red, &Grn, &Blu, &Alp, fp, tgahd.PixelDepth, pal);
|
|
|
|
// Invert if the image origin is in Bottom left
|
|
if(TGA_Origin == 0)
|
|
{ // Bottom Left Origin
|
|
*(pRGB + destOffset) = Red;
|
|
destOffset = ((tgahd.Height -1) -row) * tgahd.Width + col;
|
|
}
|
|
else
|
|
{ // Top Left Origin
|
|
*(pRGB + destOffset) = Red;
|
|
destOffset++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Grab the image dimensions
|
|
*width = tgahd.Width;
|
|
*height = tgahd.Height;
|
|
|
|
// Clean Up
|
|
GlobalUnlock(hNew);
|
|
fclose(fp);
|
|
m_error = IMGOK;
|
|
return hNew;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// LoadTGAThumbNail
|
|
// Checks the TGA file for the existance of a thumbnail image
|
|
// Reads and returns it in a 24 Bit RGB Buffer if a thumbnail
|
|
// exists. Returns NULL if there isn't one sets TGANOTHUMBNAIL
|
|
HGLOBAL
|
|
TGAFile::LoadTGAThumbnail
|
|
(
|
|
const char * fileName, // Name of file
|
|
UINT32 * width, // Width in Pixel
|
|
UINT32 * height // Height
|
|
)
|
|
{
|
|
HGLOBAL hNew = NULL;
|
|
|
|
TGAHEADER tgahd;
|
|
TGAFOOTER tgaft;
|
|
TGAEXTENSION tgaext;
|
|
|
|
BYTE stampWidth = 0, stampHeight = 0;
|
|
long lResult;
|
|
|
|
// for safety
|
|
*width = 0;
|
|
*height = 0;
|
|
|
|
// init
|
|
m_error = IMGOK;
|
|
|
|
// Init the file structs
|
|
ZeroMemory(&tgahd, sizeof(tgahd));
|
|
ZeroMemory(&tgaft, sizeof(tgaft));
|
|
ZeroMemory(&tgaext, sizeof(tgaext));
|
|
FILE * fp;
|
|
fp = fopen(fileName, "rb");
|
|
|
|
if(fp == NULL)
|
|
{
|
|
m_error = FILEOPENERR;
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Read the TGA Header
|
|
long rc = fread(&tgahd, 1, sizeof(TGAHEADER), fp);
|
|
|
|
if(rc != sizeof(TGAHEADER))
|
|
{
|
|
m_error = FILEREADERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Check fo valid data in structure
|
|
if((tgahd.PixelDepth> 32) || (tgahd.PixelDepth<8))
|
|
{
|
|
// I don't do Pixel Depths Bigger than 32
|
|
m_error = INVALIDTGAERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Anything other than the standard TGA types
|
|
// and I quit
|
|
switch(tgahd.ImageType)
|
|
{
|
|
case TGA_MAPRGBTYPE:
|
|
case TGA_RAWRGBTYPE:
|
|
case TGA_RAWMONOTYPE:
|
|
case TGA_MAPENCODETYPE:
|
|
case TGA_RAWENCODETYPE:
|
|
case TGA_MONOENCODETYPE:
|
|
break;
|
|
|
|
default:
|
|
m_error = INVALIDTGAERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Set the number of Color Planes
|
|
if(tgahd.ImageType == TGA_RAWMONOTYPE)
|
|
{
|
|
mode = GREYSC;
|
|
}
|
|
else
|
|
{
|
|
mode = COLOUR;
|
|
}
|
|
|
|
// Check for file Version
|
|
// Seek the last 26 bytes of the file
|
|
if(fseek(fp, -26, SEEK_END))
|
|
{
|
|
// Error Quit
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Read in the last 26 Bytes of the File
|
|
lResult = fread(&tgaft, 1, sizeof(TGAFOOTER), fp);
|
|
|
|
if(lResult != sizeof(TGAFOOTER))
|
|
{
|
|
m_error = FILEREADERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Check for the Marker at the end of the file
|
|
lResult = strcmp(tgaft.Signature, "TRUEVISION-XFILE.");
|
|
|
|
if(lResult != 0)
|
|
{
|
|
// Not V2.0 File no Thumbnail
|
|
m_error = NOTGATHUMBNAIL;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Check for the existance of an extension area
|
|
if(tgaft.ExtensionOffset == 0)
|
|
{
|
|
// No Thumbnail in this file
|
|
m_error = NOTGATHUMBNAIL;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Seek the extension area
|
|
if(fseek(fp, tgaft.ExtensionOffset, SEEK_SET))
|
|
{
|
|
// Error Quit
|
|
m_error = FILEREADERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Read in the last 26 Bytes of the File
|
|
lResult = fread(&tgaext, 1, sizeof(TGAEXTENSION), fp);
|
|
|
|
if(lResult != sizeof(TGAEXTENSION))
|
|
{
|
|
m_error = FILEREADERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Seek the thumbnail image
|
|
if(fseek(fp, tgaext.StampOffset, SEEK_SET))
|
|
{
|
|
// Error Quit
|
|
m_error = FILEREADERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
// Read the Width and Height from the first two bytes
|
|
// of the postage stamp data.
|
|
fread(&stampWidth, 1, 1, fp);
|
|
fread(&stampHeight, 1, 1, fp);
|
|
|
|
if((stampWidth <= 0) || (stampWidth> 64) || (stampHeight <= 0) || (stampHeight> 64))
|
|
{
|
|
m_error = INVALIDTGAERR;
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Clean Up
|
|
*width = stampWidth;
|
|
*height = stampHeight;
|
|
fclose(fp);
|
|
|
|
// Return Okay Image
|
|
return hNew;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// SaveTGA32
|
|
// Saves the buffer as a 32 bit True Color Image in TGA format
|
|
BOOL
|
|
TGAFile::SaveTGA32
|
|
(
|
|
const char * fileName, // output path
|
|
BYTE * inBuf, // BGR buffer
|
|
UINT32 width, // size in pixels
|
|
UINT32 height
|
|
)
|
|
{
|
|
long lResult = 0;
|
|
|
|
TGAHEADER tgahd;
|
|
m_error = IMGOK;
|
|
|
|
// Init the file Header to all zeros
|
|
ZeroMemory(&tgahd, sizeof(tgahd));
|
|
|
|
if(inBuf == NULL)
|
|
{
|
|
m_error = BADPARAMERR;
|
|
return FALSE;
|
|
}
|
|
|
|
if((width == 0) || (height == 0))
|
|
{
|
|
m_error = BADPARAMERR;
|
|
return FALSE;
|
|
}
|
|
|
|
// Initialize the Header for the File
|
|
tgahd.IDLength = 0;
|
|
tgahd.ColorMapType = 0;
|
|
tgahd.ImageType = TGA_RAWRGBTYPE;
|
|
tgahd.CMapStart = 0;
|
|
tgahd.CMapLength = 0;
|
|
tgahd.CMapDepth = 0;
|
|
tgahd.XOffset = 0;
|
|
tgahd.YOffset = 0;
|
|
tgahd.Width = (WORD)width;
|
|
tgahd.Height = (WORD)height;
|
|
tgahd.PixelDepth = 32;
|
|
tgahd.ImageDescriptor = 0;
|
|
|
|
// Open a file to write
|
|
FILE * fp = fopen(fileName, "wb");
|
|
|
|
if(fp == NULL)
|
|
{
|
|
m_error = FILEOPENERR;
|
|
return FALSE;
|
|
}
|
|
|
|
// Write the Header to File.
|
|
if((lResult = fwrite(&tgahd, 1, sizeof(TGAHEADER), fp)) != 18)
|
|
{
|
|
fclose(fp);
|
|
m_error = FILEWRITEERR;
|
|
return FALSE;
|
|
}
|
|
|
|
// Wrte the Bytes to file
|
|
DWORD destOffset = 0;
|
|
BYTE temp = 0;
|
|
DWORD rowStride = tgahd.Width * 4;
|
|
|
|
for(UINT32 row = 0; row < tgahd.Height; row++)
|
|
{
|
|
//DWORD rowOffset = rowStride * row;
|
|
DWORD rowOffset = rowStride *((tgahd.Height -1) -row);
|
|
|
|
for(UINT32 col = 0; col < tgahd.Width; col++)
|
|
{
|
|
destOffset = rowOffset + 4 * col;
|
|
temp = *(inBuf + destOffset + 2);
|
|
|
|
if(fwrite(&temp, 1, 1, fp) != 1)
|
|
{
|
|
m_error = FILEWRITEERR;
|
|
fclose(fp);
|
|
return FALSE;
|
|
}
|
|
temp = *(inBuf + destOffset + 1);
|
|
|
|
if(fwrite(&temp, 1, 1, fp) != 1)
|
|
{
|
|
m_error = FILEWRITEERR;
|
|
fclose(fp);
|
|
return FALSE;
|
|
}
|
|
temp = *(inBuf + destOffset + 0);
|
|
|
|
if(fwrite(&temp, 1, 1, fp) != 1)
|
|
{
|
|
m_error = FILEWRITEERR;
|
|
fclose(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
if(fwrite(&temp, 1, 1, fp) != 1)
|
|
{
|
|
m_error = FILEWRITEERR;
|
|
fclose(fp);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cleanup
|
|
fclose(fp);
|
|
m_error = IMGOK;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// Save8BitTGA
|
|
// Save's to an 8 Bit Color mapped file using the Palette
|
|
// passed in to the function.
|
|
BOOL
|
|
TGAFile::Save8BitTGA(const char * fileName, // output path
|
|
BYTE * inBuf, // one BYTE per pixel colomapped image
|
|
UINT32 width, // Width of Image
|
|
UINT32 height, // Height of Image
|
|
__int32 colors, // number of colors (number of RGBQUADs)
|
|
RGBQUAD * colormap) // array of RGBQUADs
|
|
{
|
|
long lResult = 0;
|
|
|
|
TGAHEADER tgahd;
|
|
|
|
// Init
|
|
m_error = IMGOK;
|
|
|
|
// Init the file Header to all zeros
|
|
ZeroMemory(&tgahd, sizeof(tgahd));
|
|
|
|
if(inBuf == NULL)
|
|
{
|
|
m_error = BADPARAMERR;
|
|
return FALSE;
|
|
}
|
|
|
|
if((width == 0) || (height == 0))
|
|
{
|
|
m_error = BADPARAMERR;
|
|
return FALSE;
|
|
}
|
|
|
|
if(colormap == NULL)
|
|
{
|
|
m_error = BADPARAMERR;
|
|
return FALSE;
|
|
}
|
|
|
|
// Initialize the Header for the File
|
|
tgahd.IDLength = 0;
|
|
tgahd.ColorMapType = 1;
|
|
tgahd.ImageType = TGA_MAPRGBTYPE;
|
|
tgahd.CMapStart = 0;
|
|
tgahd.CMapLength = (SHORT)colors;
|
|
tgahd.CMapDepth = 24;
|
|
tgahd.XOffset = 0;
|
|
tgahd.YOffset = 0;
|
|
tgahd.Width = (WORD)width;
|
|
tgahd.Height = (WORD)height;
|
|
tgahd.PixelDepth = 8;
|
|
tgahd.ImageDescriptor = 0x28;
|
|
|
|
// Open a file to write
|
|
FILE * fp = fopen(fileName, "wb");
|
|
|
|
if(fp == NULL)
|
|
{
|
|
m_error = FILEOPENERR;
|
|
return FALSE;
|
|
}
|
|
|
|
// Write the Header to File.
|
|
if((lResult = fwrite(&tgahd, 1, sizeof(TGAHEADER), fp)) != 18)
|
|
{
|
|
m_error = FILEWRITEERR;
|
|
fclose(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
// Write out the Colormap
|
|
for(__int32 i = 0; i < colors; i++)
|
|
{
|
|
putc(colormap[i].rgbBlue, fp);
|
|
putc(colormap[i].rgbGreen, fp);
|
|
putc(colormap[i].rgbRed, fp);
|
|
}
|
|
|
|
// Wrte the Bytes to file
|
|
DWORD destOffset = 0;
|
|
BYTE temp = 0;
|
|
|
|
for(UINT32 row = 0; row < tgahd.Height; row++)
|
|
{
|
|
for(UINT32 col = 0; col < tgahd.Width; col++)
|
|
{
|
|
temp = *(inBuf + destOffset + 0);
|
|
|
|
if(fwrite(&temp, 1, 1, fp) != 1)
|
|
{
|
|
m_error = FILEWRITEERR;
|
|
fclose(fp);
|
|
return FALSE;
|
|
}
|
|
destOffset += 1;
|
|
}
|
|
}
|
|
|
|
// Cleanup
|
|
fclose(fp);
|
|
m_error = IMGOK;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// TGA_GetMapEntry
|
|
// Get the Color Values out of the
|
|
// Color map in the TGA File
|
|
// Return 0 on Success
|
|
BOOL
|
|
TGAFile::TGA_GetMapEntry(BYTE * Red, BYTE * Green, BYTE * Blue, BYTE * Alpha, FILE * fp, UINT32 Depth)
|
|
{
|
|
UINT32 j, k, l;
|
|
BYTE i, r, g, b, a = 0;
|
|
long lResult;
|
|
|
|
switch(Depth)
|
|
{
|
|
case 8: // Greyscale Read and Triplicate
|
|
lResult = fread(&i, 1, 1, fp);
|
|
|
|
// Check for error
|
|
if(lResult != 1)
|
|
{
|
|
m_error = FILEREADERR;
|
|
return FALSE;
|
|
}
|
|
|
|
// Set RGB Values
|
|
r = i;
|
|
g = i;
|
|
b = i;
|
|
break;
|
|
|
|
case 16: // 5 bits each of Red, Green, and Blue
|
|
|
|
case 15: // Watch for the Byte order
|
|
lResult = fread(&j, 1, 1, fp);
|
|
lResult = lResult + fread(&k, 1, 1, fp);
|
|
|
|
// Check for error
|
|
if(lResult != 2)
|
|
{
|
|
m_error = FILEREADERR;
|
|
return FALSE;
|
|
}
|
|
l = j + k * 256;
|
|
b = (BYTE)(((l >> 10) & 31) << 3);
|
|
g = (BYTE)(((l >> 5) & 31) << 3);
|
|
r = (BYTE)((l & 31) << 3);
|
|
break;
|
|
|
|
case 32: // Read the Alpha bit a Throw it away
|
|
|
|
case 24: // Eight bits for each Red, Green and Blue
|
|
lResult = fread(&i, 1, 1, fp);
|
|
r = i;
|
|
lResult = lResult + fread(&i, 1, 1, fp);
|
|
g = i;
|
|
lResult = lResult + fread(&i, 1, 1, fp);
|
|
b = i;
|
|
|
|
// Check for error
|
|
if(lResult != 3)
|
|
{
|
|
m_error = FILEREADERR;
|
|
return FALSE;
|
|
}
|
|
|
|
if(Depth == 32)
|
|
{
|
|
lResult = fread(&i, 1, 1, fp);
|
|
|
|
if(lResult != 1)
|
|
{
|
|
m_error = FILEREADERR;
|
|
return FALSE;
|
|
}
|
|
|
|
// Stroe Alpha bit
|
|
a = i;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// Some Other Pixel Depth Which I don't support
|
|
return FALSE;
|
|
}
|
|
*Red = r;
|
|
*Green = g;
|
|
*Blue = b;
|
|
*Alpha = a;
|
|
|
|
// Reutrn No Error
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// TGA_GetFileVersion
|
|
// Retrieves the Version of the TGA File
|
|
// BYTES 8-23 of a Version 2.0 Footer will be equal
|
|
// to "TRUEVISION-XFILE" as ASCII
|
|
// Returns - Version number 1 or 2
|
|
__int32
|
|
TGAFile::TGA_GetFileVersion(FILE * fp)
|
|
{
|
|
long result;
|
|
fpos_t pos;
|
|
|
|
TGAFOOTER tgaft;
|
|
|
|
// Save the Current position of the File Stream
|
|
if(fgetpos(fp, &pos))
|
|
{
|
|
// Error Quit
|
|
return FILEREADERR;
|
|
}
|
|
|
|
// Seek the last 26 bytes of the file
|
|
if(fseek(fp, -26, SEEK_END))
|
|
{
|
|
// Error Quit
|
|
return FILEREADERR;
|
|
}
|
|
|
|
// Read in the last 26 Bytes of the File
|
|
result = fread(&tgaft, 1, sizeof(TGAFOOTER), fp);
|
|
|
|
if(result != sizeof(TGAFOOTER))
|
|
{
|
|
m_error = FILEREADERR;
|
|
return FILEREADERR;
|
|
}
|
|
|
|
// Return the File Stream to its initial position
|
|
if(fsetpos(fp, &pos))
|
|
{
|
|
// Error Quit
|
|
return FILEREADERR;
|
|
}
|
|
|
|
// Check for the Marker at the end of the file
|
|
if(!strcspn(tgaft.Signature, "TRUEVISION-XFILE"))
|
|
{
|
|
// Marker found its V2.0 TGA
|
|
return TGA_VERSIONTWO;
|
|
}
|
|
|
|
// No Marker was found Assume V1.0 TGA
|
|
return TGA_VERSIONONE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// TGA_getPixelValue
|
|
// Retreve a pixel value from the buffer and parse
|
|
// the value if its RLE encoded. Returns the RGB
|
|
// value of the pixel.
|
|
// Retruns - TRUE on success
|
|
BOOL
|
|
TGAFile::TGA_GetPixelValue
|
|
(
|
|
BYTE * rRed,
|
|
BYTE * rGrn,
|
|
BYTE * rBlu,
|
|
BYTE * rAlp,
|
|
BYTE ** ppTGAData,
|
|
UINT32 PixelDepth,
|
|
RGBQUAD * CColMap
|
|
)
|
|
{
|
|
//
|
|
// Buffered TGAs are always 32-bit,
|
|
// so go direct from file to RGBA
|
|
//
|
|
*rRed = *((*ppTGAData)++);
|
|
*rGrn = *((*ppTGAData)++);
|
|
*rBlu = *((*ppTGAData)++);
|
|
*rAlp = *((*ppTGAData)++);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// TGA_getPixelValue
|
|
// Retreve a pixel value from the file and parse
|
|
// the value if its RLE encoded. Returns the RGB
|
|
// value of the pixel.
|
|
// Retruns - TRUE on success
|
|
BOOL
|
|
TGAFile::TGA_GetPixelValue(BYTE * rRed, BYTE * rGrn, BYTE * rBlu, BYTE * rAlp, FILE * fp, UINT32 PixelDepth, RGBQUAD * CColMap)
|
|
{
|
|
BYTE i, j, k;
|
|
long lResult;
|
|
|
|
// Check for Run Length Encoding
|
|
if((mode & RLENCO) != 0)
|
|
{
|
|
if(RLECount == 0)
|
|
{ // Restrat the rum
|
|
lResult = fread(&i, 1, 1, fp);
|
|
|
|
if(lResult != 1)
|
|
{
|
|
m_error = FILEREADERR;
|
|
return FALSE;
|
|
}
|
|
RLEFlag = (i & 0x80) >> 7;
|
|
|
|
if(RLEFlag == 0)
|
|
{ // Stream of unencoded pixels
|
|
RLECount = i + 1;
|
|
}
|
|
else
|
|
{ // Single Pixel Replicated
|
|
RLECount = i-127;
|
|
}
|
|
RLECount--; // ecrement count and get pixel
|
|
}
|
|
else
|
|
{
|
|
// I have already read the count and at least the first pixel
|
|
RLECount--;
|
|
|
|
if(RLEFlag != 0)
|
|
{
|
|
// Replicated Pixels
|
|
goto PixelEncode;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Rea the appropiate number of BYTES and break into RGB
|
|
switch(PixelDepth)
|
|
{
|
|
case 8: // Greyscale Read 1 Byte and Triplicate
|
|
lResult = fread(&i, 1, 1, fp);
|
|
|
|
if(lResult != 1)
|
|
{
|
|
m_error = FILEREADERR;
|
|
return FALSE;
|
|
}
|
|
Red = i;
|
|
Grn = i;
|
|
Blu = i;
|
|
l = i;
|
|
break;
|
|
|
|
case 16: // 1 Bit alpha not used
|
|
|
|
case 15: // Five bits each for RGB watch byte ordering
|
|
lResult = fread(&j, 1, 1, fp);
|
|
lResult = lResult + fread(&k, 1, 1, fp);
|
|
|
|
// Check for error
|
|
if(lResult != 2)
|
|
{
|
|
m_error = FILEREADERR;
|
|
return FALSE;
|
|
}
|
|
l = j + k * 256;
|
|
Blu = (BYTE)(((l >> 10) & 31) << 3);
|
|
Grn = (BYTE)(((l >> 5) & 31) << 3);
|
|
Red = (BYTE)((l & 31) << 3);
|
|
break;
|
|
|
|
case 24: // Eight bits each for RGB
|
|
lResult = fread(&i, 1, 1, fp);
|
|
Red = i;
|
|
lResult = lResult + fread(&i, 1, 1, fp);
|
|
Grn = i;
|
|
lResult = lResult + fread(&i, 1, 1, fp);
|
|
Blu = i;
|
|
|
|
// opaque alpha (08jan00/bgw)
|
|
Alpha = 0xFF;
|
|
|
|
// Check for error
|
|
if(lResult != 3)
|
|
{
|
|
m_error = FILEREADERR;
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case 32: // With alpha (08jan00/bgw)
|
|
lResult = fread(&i, 1, 1, fp);
|
|
Red = i;
|
|
lResult = lResult + fread(&i, 1, 1, fp);
|
|
Grn = i;
|
|
lResult = lResult + fread(&i, 1, 1, fp);
|
|
Blu = i;
|
|
lResult = lResult + fread(&i, 1, 1, fp);
|
|
Alpha = i;
|
|
|
|
// Check for error
|
|
if(lResult != 4)
|
|
{
|
|
m_error = FILEREADERR;
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
default: // Unknown number of bis per pixel
|
|
m_error = INVALIDTGAERR;
|
|
return NULL;
|
|
}
|
|
|
|
PixelEncode: // Set the actual pixel values
|
|
|
|
if((mode & MAPPED) == MAPPED)
|
|
{
|
|
// Remap Color Mapped Pixels
|
|
*rRed = CColMap[l].rgbRed;
|
|
*rGrn = CColMap[l].rgbGreen;
|
|
*rBlu = CColMap[l].rgbBlue;
|
|
*rAlp = 0xFF; // opaque always (08jan00/bgw)
|
|
}
|
|
else
|
|
{
|
|
// Set Unmapped Values
|
|
*rRed = Red;
|
|
*rGrn = Grn;
|
|
*rBlu = Blu;
|
|
*rAlp = Alpha;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
extern "C" unsigned char * LoadTGAFile
|
|
(
|
|
const char * filename,
|
|
int * width,
|
|
int * height
|
|
)
|
|
{
|
|
TGAFile tgaFile;
|
|
return (unsigned char *)tgaFile.LoadTGA(filename, (UINT32 *)width, (UINT32 *)height);
|
|
} |