Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
887 lines
19 KiB
C
887 lines
19 KiB
C
//-----------------------------------------------------------------------------
|
|
//
|
|
// ImageLib Sources
|
|
// Copyright (C) 2000-2002 by Denton Woods
|
|
// Last modified: 05/22/2002 <--Y2K Compliant! =]
|
|
//
|
|
// Filename: src-IL/src/il_targa.c
|
|
//
|
|
// Description: Reads from and writes to a targa (.tga) file.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#include "il_internal.h"
|
|
#ifndef IL_NO_TGA
|
|
#include "il_targa.h"
|
|
//#include <time.h> // for ilMakeString()
|
|
#include <string.h>
|
|
#include "il_manip.h"
|
|
#include "il_bits.h"
|
|
|
|
#ifdef DJGPP
|
|
#include <dos.h>
|
|
#endif
|
|
|
|
|
|
//! Checks if the file specified in FileName is a valid Targa file.
|
|
ILboolean ilIsValidTga(ILconst_string FileName)
|
|
{
|
|
ILHANDLE TargaFile;
|
|
ILboolean bTarga = IL_FALSE;
|
|
|
|
if (!iCheckExtension(FileName, IL_TEXT("tga")) &&
|
|
!iCheckExtension(FileName, IL_TEXT("vda")) &&
|
|
!iCheckExtension(FileName, IL_TEXT("icb")) &&
|
|
!iCheckExtension(FileName, IL_TEXT("vst"))) {
|
|
ilSetError(IL_INVALID_EXTENSION);
|
|
return bTarga;
|
|
}
|
|
|
|
TargaFile = iopenr(FileName);
|
|
if (TargaFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return bTarga;
|
|
}
|
|
|
|
bTarga = ilIsValidTgaF(TargaFile);
|
|
icloser(TargaFile);
|
|
|
|
return bTarga;
|
|
}
|
|
|
|
|
|
//! Checks if the ILHANDLE contains a valid Targa file at the current position.
|
|
ILboolean ilIsValidTgaF(ILHANDLE File)
|
|
{
|
|
ILuint FirstPos;
|
|
ILboolean bRet;
|
|
|
|
iSetInputFile(File);
|
|
FirstPos = itell();
|
|
bRet = iIsValidTarga();
|
|
iseek(FirstPos, IL_SEEK_SET);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//! Checks if Lump is a valid Targa lump.
|
|
ILboolean ilIsValidTgaL(const ILvoid *Lump, ILuint Size)
|
|
{
|
|
iSetInputLump(Lump, Size);
|
|
return iIsValidTarga();
|
|
}
|
|
|
|
|
|
// Internal function used to get the Targa header from the current file.
|
|
ILboolean iGetTgaHead(TARGAHEAD *Header)
|
|
{
|
|
Header->IDLen = igetc();
|
|
Header->ColMapPresent = igetc();
|
|
Header->ImageType = igetc();
|
|
Header->FirstEntry = GetLittleShort();
|
|
Header->ColMapLen = GetLittleShort();
|
|
Header->ColMapEntSize = igetc();
|
|
|
|
Header->OriginX = GetLittleShort();
|
|
Header->OriginY = GetLittleShort();
|
|
Header->Width = GetLittleUShort();
|
|
Header->Height = GetLittleUShort();
|
|
Header->Bpp = igetc();
|
|
Header->ImageDesc = igetc();
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
// Internal function to get the header and check it.
|
|
ILboolean iIsValidTarga()
|
|
{
|
|
TARGAHEAD Head;
|
|
|
|
if (!iGetTgaHead(&Head))
|
|
return IL_FALSE;
|
|
iseek(-(ILint)sizeof(TARGAHEAD), IL_SEEK_CUR);
|
|
|
|
return iCheckTarga(&Head);
|
|
}
|
|
|
|
|
|
// Internal function used to check if the HEADER is a valid Targa header.
|
|
ILboolean iCheckTarga(TARGAHEAD *Header)
|
|
{
|
|
if (Header->Width == 0 || Header->Height == 0)
|
|
return IL_FALSE;
|
|
if (Header->Bpp != 8 && Header->Bpp != 15 && Header->Bpp != 16
|
|
&& Header->Bpp != 24 && Header->Bpp != 32)
|
|
return IL_FALSE;
|
|
if (Header->ImageDesc & BIT_4) // Supposed to be set to 0
|
|
return IL_FALSE;
|
|
|
|
// check type (added 20040218)
|
|
if(Header->ImageType != TGA_NO_DATA
|
|
&& Header->ImageType != TGA_COLMAP_UNCOMP
|
|
&& Header->ImageType != TGA_UNMAP_UNCOMP
|
|
&& Header->ImageType != TGA_BW_UNCOMP
|
|
&& Header->ImageType != TGA_COLMAP_COMP
|
|
&& Header->ImageType != TGA_UNMAP_COMP
|
|
&& Header->ImageType != TGA_BW_COMP)
|
|
return IL_FALSE;
|
|
|
|
// Doesn't work well with the bitshift so change it.
|
|
if (Header->Bpp == 15)
|
|
Header->Bpp = 16;
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
//! Reads a Targa file
|
|
ILboolean ilLoadTarga(ILconst_string FileName)
|
|
{
|
|
ILHANDLE TargaFile;
|
|
ILboolean bTarga = IL_FALSE;
|
|
|
|
TargaFile = iopenr(FileName);
|
|
if (TargaFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return bTarga;
|
|
}
|
|
|
|
bTarga = ilLoadTargaF(TargaFile);
|
|
icloser(TargaFile);
|
|
|
|
return bTarga;
|
|
}
|
|
|
|
|
|
//! Reads an already-opened Targa file
|
|
ILboolean ilLoadTargaF(ILHANDLE File) {
|
|
ILuint FirstPos;
|
|
ILboolean bRet;
|
|
|
|
iSetInputFile(File);
|
|
FirstPos = itell();
|
|
bRet = iLoadTargaInternal();
|
|
iseek(FirstPos, IL_SEEK_SET);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//! Reads from a memory "lump" that contains a Targa
|
|
ILboolean ilLoadTargaL(const ILvoid *Lump, ILuint Size)
|
|
{
|
|
iSetInputLump(Lump, Size);
|
|
return iLoadTargaInternal();
|
|
}
|
|
|
|
|
|
// Internal function used to load the Targa.
|
|
ILboolean iLoadTargaInternal()
|
|
{
|
|
TARGAHEAD Header;
|
|
ILboolean bTarga;
|
|
ILenum iOrigin;
|
|
|
|
if (iCurImage == NULL) {
|
|
ilSetError(IL_ILLEGAL_OPERATION);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
if (!iGetTgaHead(&Header))
|
|
return IL_FALSE;
|
|
if (!iCheckTarga(&Header)) {
|
|
ilSetError(IL_INVALID_FILE_HEADER);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
switch (Header.ImageType)
|
|
{
|
|
case TGA_NO_DATA:
|
|
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
|
return IL_FALSE;
|
|
case TGA_COLMAP_UNCOMP:
|
|
case TGA_COLMAP_COMP:
|
|
bTarga = iReadColMapTga(&Header);
|
|
break;
|
|
case TGA_UNMAP_UNCOMP:
|
|
case TGA_UNMAP_COMP:
|
|
bTarga = iReadUnmapTga(&Header);
|
|
break;
|
|
case TGA_BW_UNCOMP:
|
|
case TGA_BW_COMP:
|
|
bTarga = iReadBwTga(&Header);
|
|
break;
|
|
default:
|
|
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
// @JASON Extra Code to manipulate the image depending on
|
|
// the Image Descriptor's origin bits.
|
|
iOrigin = Header.ImageDesc & IMAGEDESC_ORIGIN_MASK;
|
|
|
|
switch (iOrigin)
|
|
{
|
|
case IMAGEDESC_TOPLEFT:
|
|
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
|
break;
|
|
|
|
case IMAGEDESC_TOPRIGHT:
|
|
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
|
iMirror();
|
|
break;
|
|
|
|
case IMAGEDESC_BOTLEFT:
|
|
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
|
break;
|
|
|
|
case IMAGEDESC_BOTRIGHT:
|
|
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
|
iMirror();
|
|
break;
|
|
}
|
|
|
|
ilFixImage();
|
|
|
|
return bTarga;
|
|
}
|
|
|
|
|
|
ILboolean iReadColMapTga(TARGAHEAD *Header)
|
|
{
|
|
char ID[255];
|
|
ILuint i;
|
|
ILushort Pixel;
|
|
|
|
if (iread(ID, 1, Header->IDLen) != Header->IDLen)
|
|
return IL_FALSE;
|
|
|
|
if (!ilTexImage(Header->Width, Header->Height, 1, (ILubyte)(Header->Bpp >> 3), 0, IL_UNSIGNED_BYTE, NULL)) {
|
|
return IL_FALSE;
|
|
}
|
|
if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize)
|
|
ifree(iCurImage->Pal.Palette);
|
|
|
|
iCurImage->Format = IL_COLOUR_INDEX;
|
|
iCurImage->Pal.PalSize = Header->ColMapLen * (Header->ColMapEntSize >> 3);
|
|
|
|
switch (Header->ColMapEntSize)
|
|
{
|
|
case 16:
|
|
iCurImage->Pal.PalType = IL_PAL_BGRA32;
|
|
iCurImage->Pal.PalSize = Header->ColMapLen * 4;
|
|
break;
|
|
case 24:
|
|
iCurImage->Pal.PalType = IL_PAL_BGR24;
|
|
break;
|
|
case 32:
|
|
iCurImage->Pal.PalType = IL_PAL_BGRA32;
|
|
break;
|
|
default:
|
|
// Should *never* reach here
|
|
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
|
|
if (iCurImage->Pal.Palette == NULL) {
|
|
return IL_FALSE;
|
|
}
|
|
|
|
// Do we need to do something with FirstEntry? Like maybe:
|
|
// iread(Image->Pal + Targa->FirstEntry, 1, Image->Pal.PalSize); ??
|
|
if (Header->ColMapEntSize != 16) {
|
|
if (iread(iCurImage->Pal.Palette, 1, iCurImage->Pal.PalSize) != iCurImage->Pal.PalSize)
|
|
return IL_FALSE;
|
|
}
|
|
else {
|
|
// 16 bit palette, so we have to break it up.
|
|
for (i = 0; i < iCurImage->Pal.PalSize; i += 4) {
|
|
Pixel = GetBigUShort();
|
|
if (ieof())
|
|
return IL_FALSE;
|
|
iCurImage->Pal.Palette[3] = (Pixel & 0x8000) >> 12;
|
|
iCurImage->Pal.Palette[0] = (Pixel & 0xFC00) >> 7;
|
|
iCurImage->Pal.Palette[1] = (Pixel & 0x03E0) >> 2;
|
|
iCurImage->Pal.Palette[2] = (Pixel & 0x001F) << 3;
|
|
}
|
|
}
|
|
|
|
if (Header->ImageType == TGA_COLMAP_COMP) {
|
|
if (!iUncompressTgaData(iCurImage)) {
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
else {
|
|
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData) {
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
ILboolean iReadUnmapTga(TARGAHEAD *Header)
|
|
{
|
|
ILubyte Bpp;
|
|
char ID[255];
|
|
|
|
if (iread(ID, 1, Header->IDLen) != Header->IDLen)
|
|
return IL_FALSE;
|
|
|
|
/*if (Header->Bpp == 16)
|
|
Bpp = 3;
|
|
else*/
|
|
Bpp = (ILubyte)(Header->Bpp >> 3);
|
|
|
|
if (!ilTexImage(Header->Width, Header->Height, 1, Bpp, 0, IL_UNSIGNED_BYTE, NULL)) {
|
|
return IL_FALSE;
|
|
}
|
|
|
|
switch (iCurImage->Bpp)
|
|
{
|
|
case 1:
|
|
iCurImage->Format = IL_COLOUR_INDEX; // wtf? How is this possible?
|
|
break;
|
|
case 2: // 16-bit is not supported directly!
|
|
//iCurImage->Format = IL_RGB5_A1;
|
|
/*iCurImage->Format = IL_RGBA;
|
|
iCurImage->Type = IL_UNSIGNED_SHORT_5_5_5_1_EXT;*/
|
|
//iCurImage->Type = IL_UNSIGNED_SHORT_5_6_5_REV;
|
|
|
|
// Remove?
|
|
//ilCloseImage(iCurImage);
|
|
//ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
|
//return IL_FALSE;
|
|
|
|
/*iCurImage->Bpp = 4;
|
|
iCurImage->Format = IL_BGRA;
|
|
iCurImage->Type = IL_UNSIGNED_SHORT_1_5_5_5_REV;*/
|
|
|
|
iCurImage->Format = IL_BGR;
|
|
|
|
break;
|
|
case 3:
|
|
iCurImage->Format = IL_BGR;
|
|
break;
|
|
case 4:
|
|
iCurImage->Format = IL_BGRA;
|
|
break;
|
|
default:
|
|
ilSetError(IL_INVALID_VALUE);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
|
|
// @TODO: Determine this:
|
|
// We assume that no palette is present, but it's possible...
|
|
// Should we mess with it or not?
|
|
|
|
|
|
if (Header->ImageType == TGA_UNMAP_COMP) {
|
|
if (!iUncompressTgaData(iCurImage)) {
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
else {
|
|
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData) {
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
|
|
// Go ahead and expand it to 24-bit.
|
|
if (Header->Bpp == 16) {
|
|
if (!i16BitTarga(iCurImage))
|
|
return IL_FALSE;
|
|
return IL_TRUE;
|
|
}
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
ILboolean iReadBwTga(TARGAHEAD *Header)
|
|
{
|
|
char ID[255];
|
|
|
|
if (iread(ID, 1, Header->IDLen) != Header->IDLen)
|
|
return IL_FALSE;
|
|
|
|
// We assume that no palette is present, but it's possible...
|
|
// Should we mess with it or not?
|
|
|
|
if (!ilTexImage(Header->Width, Header->Height, 1, (ILubyte)(Header->Bpp >> 3), IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL)) {
|
|
return IL_FALSE;
|
|
}
|
|
|
|
if (Header->ImageType == TGA_BW_COMP) {
|
|
if (!iUncompressTgaData(iCurImage)) {
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
else {
|
|
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData) {
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
ILboolean iUncompressTgaData(ILimage *Image)
|
|
{
|
|
ILuint BytesRead = 0, Size, RunLen, i;
|
|
ILubyte Header, Color[4];
|
|
ILint c;
|
|
|
|
Size = Image->Width * Image->Height * Image->Depth * Image->Bpp;
|
|
|
|
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
|
|
iPreCache(iCurImage->SizeOfData / 2);
|
|
|
|
while (BytesRead < Size) {
|
|
Header = igetc();
|
|
if (Header & BIT_7) {
|
|
ClearBits(Header, BIT_7);
|
|
if (iread(Color, 1, Image->Bpp) != Image->Bpp) {
|
|
iUnCache();
|
|
return IL_FALSE;
|
|
}
|
|
RunLen = (Header+1) * Image->Bpp;
|
|
for (i = 0; i < RunLen; i += Image->Bpp) {
|
|
for (c = 0; c < Image->Bpp; c++) {
|
|
Image->Data[BytesRead+i+c] = Color[c];
|
|
}
|
|
}
|
|
BytesRead += RunLen;
|
|
}
|
|
else {
|
|
RunLen = (Header+1) * Image->Bpp;
|
|
if (iread(Image->Data + BytesRead, 1, RunLen) != RunLen) {
|
|
iUnCache();
|
|
return IL_FALSE;
|
|
}
|
|
BytesRead += RunLen;
|
|
}
|
|
}
|
|
|
|
iUnCache();
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
// Pretty damn unoptimized
|
|
ILboolean i16BitTarga(ILimage *Image)
|
|
{
|
|
ILushort *Temp1;
|
|
ILubyte *Data, *Temp2;
|
|
ILuint x, PixSize = Image->Width * Image->Height;
|
|
|
|
Data = (ILubyte*)ialloc(Image->Width * Image->Height * 3);
|
|
Temp1 = (ILushort*)Image->Data;
|
|
Temp2 = Data;
|
|
|
|
if (Data == NULL)
|
|
return IL_FALSE;
|
|
|
|
for (x = 0; x < PixSize; x++) {
|
|
*Temp2++ = (*Temp1 & 0x001F) << 3; // Blue
|
|
*Temp2++ = (*Temp1 & 0x03E0) >> 2; // Green
|
|
*Temp2++ = (*Temp1 & 0x7C00) >> 7; // Red
|
|
|
|
Temp1++;
|
|
|
|
|
|
/*s = *Temp;
|
|
s = SwapShort(s);
|
|
a = !!(s & BIT_15);
|
|
|
|
s = s << 1;
|
|
|
|
//if (a) {
|
|
SetBits(s, BIT_0);
|
|
//}
|
|
|
|
//SetBits(s, BIT_15);
|
|
|
|
*Temp++ = s;*/
|
|
}
|
|
|
|
if (!ilTexImage(Image->Width, Image->Height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, Data)) {
|
|
ifree(Data);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
ifree(Data);
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
//! Writes a Targa file
|
|
ILboolean ilSaveTarga(ILconst_string FileName)
|
|
{
|
|
ILHANDLE TargaFile;
|
|
ILboolean bTarga = IL_FALSE;
|
|
|
|
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
|
if (iFileExists(FileName)) {
|
|
ilSetError(IL_FILE_ALREADY_EXISTS);
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
|
|
TargaFile = iopenw(FileName);
|
|
if (TargaFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return bTarga;
|
|
}
|
|
|
|
bTarga = ilSaveTargaF(TargaFile);
|
|
iclosew(TargaFile);
|
|
|
|
return bTarga;
|
|
}
|
|
|
|
|
|
//! Writes a Targa to an already-opened file
|
|
ILboolean ilSaveTargaF(ILHANDLE File)
|
|
{
|
|
iSetOutputFile(File);
|
|
return iSaveTargaInternal();
|
|
}
|
|
|
|
|
|
//! Writes a Targa to a memory "lump"
|
|
ILboolean ilSaveTargaL(ILvoid *Lump, ILuint Size)
|
|
{
|
|
iSetOutputLump(Lump, Size);
|
|
return iSaveTargaInternal();
|
|
}
|
|
|
|
|
|
// Internal function used to save the Targa.
|
|
ILboolean iSaveTargaInternal()
|
|
{
|
|
char *ID = iGetString(IL_TGA_ID_STRING);
|
|
char *AuthName = iGetString(IL_TGA_AUTHNAME_STRING);
|
|
char *AuthComment = iGetString(IL_TGA_AUTHCOMMENT_STRING);
|
|
ILubyte IDLen = 0, UsePal, Type, PalEntSize;
|
|
ILshort ColMapStart = 0, PalSize;
|
|
ILubyte Temp;
|
|
ILenum Format;
|
|
ILboolean Compress;
|
|
ILuint RleLen;
|
|
ILubyte *Rle;
|
|
ILpal *TempPal = NULL;
|
|
ILimage *TempImage = NULL;
|
|
ILuint ExtOffset, i;
|
|
char *Footer = "TRUEVISION-XFILE.\0";
|
|
char *idString = "Developer's Image Library (DevIL)";
|
|
ILuint Day, Month, Year, Hour, Minute, Second;
|
|
char *TempData;
|
|
|
|
if (iCurImage == NULL) {
|
|
ilSetError(IL_ILLEGAL_OPERATION);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
if (iGetInt(IL_TGA_RLE) == IL_TRUE)
|
|
Compress = IL_TRUE;
|
|
else
|
|
Compress = IL_FALSE;
|
|
|
|
if (ID)
|
|
IDLen = (ILubyte)strlen(ID);
|
|
|
|
if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize && iCurImage->Pal.PalType != IL_PAL_NONE)
|
|
UsePal = IL_TRUE;
|
|
else
|
|
UsePal = IL_FALSE;
|
|
|
|
iwrite(&IDLen, sizeof(ILubyte), 1);
|
|
iwrite(&UsePal, sizeof(ILubyte), 1);
|
|
|
|
Format = iCurImage->Format;
|
|
switch (Format) {
|
|
case IL_COLOUR_INDEX:
|
|
if (Compress)
|
|
Type = 9;
|
|
else
|
|
Type = 1;
|
|
break;
|
|
case IL_BGR:
|
|
case IL_BGRA:
|
|
if (Compress)
|
|
Type = 10;
|
|
else
|
|
Type = 2;
|
|
break;
|
|
case IL_RGB:
|
|
case IL_RGBA:
|
|
ilSwapColours();
|
|
if (Compress)
|
|
Type = 10;
|
|
else
|
|
Type = 2;
|
|
break;
|
|
case IL_LUMINANCE:
|
|
if (Compress)
|
|
Type = 11;
|
|
else
|
|
Type = 3;
|
|
break;
|
|
default:
|
|
// Should convert the types here...
|
|
ilSetError(IL_INVALID_VALUE);
|
|
ifree(ID);
|
|
ifree(AuthName);
|
|
ifree(AuthComment);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
iwrite(&Type, sizeof(ILubyte), 1);
|
|
SaveLittleShort(ColMapStart);
|
|
|
|
switch (iCurImage->Pal.PalType)
|
|
{
|
|
case IL_PAL_NONE:
|
|
PalSize = 0;
|
|
PalEntSize = 0;
|
|
break;
|
|
case IL_PAL_BGR24:
|
|
PalSize = iCurImage->Pal.PalSize / 3;
|
|
PalEntSize = 24;
|
|
TempPal = &iCurImage->Pal;
|
|
break;
|
|
|
|
case IL_PAL_RGB24:
|
|
case IL_PAL_RGB32:
|
|
case IL_PAL_RGBA32:
|
|
case IL_PAL_BGR32:
|
|
case IL_PAL_BGRA32:
|
|
TempPal = iConvertPal(&iCurImage->Pal, IL_PAL_BGR24);
|
|
if (TempPal == NULL)
|
|
return IL_FALSE;
|
|
PalSize = TempPal->PalSize / 3;
|
|
PalEntSize = 24;
|
|
break;
|
|
default:
|
|
ilSetError(IL_INVALID_VALUE);
|
|
ifree(ID);
|
|
ifree(AuthName);
|
|
ifree(AuthComment);
|
|
PalSize = 0;
|
|
PalEntSize = 0;
|
|
return IL_FALSE;
|
|
}
|
|
SaveLittleShort(PalSize);
|
|
iwrite(&PalEntSize, sizeof(ILubyte), 1);
|
|
|
|
if (iCurImage->Bpc > 1) {
|
|
TempImage = iConvertImage(iCurImage, iCurImage->Format, IL_UNSIGNED_BYTE);
|
|
if (TempImage == NULL) {
|
|
ifree(ID);
|
|
ifree(AuthName);
|
|
ifree(AuthComment);
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
else {
|
|
TempImage = iCurImage;
|
|
}
|
|
|
|
if (TempImage->Origin != IL_ORIGIN_LOWER_LEFT)
|
|
TempData = (char*)iGetFlipped(TempImage);
|
|
else
|
|
TempData = (char*)TempImage->Data;
|
|
|
|
// Write out the origin stuff.
|
|
Temp = 0;
|
|
iwrite(&Temp, sizeof(ILshort), 1);
|
|
iwrite(&Temp, sizeof(ILshort), 1);
|
|
|
|
Temp = iCurImage->Bpp << 3; // Changes to bits per pixel
|
|
SaveLittleUShort((ILushort)iCurImage->Width);
|
|
SaveLittleUShort((ILushort)iCurImage->Height);
|
|
iwrite(&Temp, sizeof(ILubyte), 1);
|
|
|
|
// Still don't know what exactly this is for...
|
|
Temp = 0;
|
|
iwrite(&Temp, sizeof(ILubyte), 1);
|
|
iwrite(ID, sizeof(char), IDLen);
|
|
ifree(ID);
|
|
//iwrite(ID, sizeof(ILbyte), IDLen - sizeof(ILuint));
|
|
//iwrite(&iCurImage->Depth, sizeof(ILuint), 1);
|
|
|
|
// Write out the colormap
|
|
if (UsePal)
|
|
iwrite(TempPal->Palette, sizeof(ILubyte), TempPal->PalSize);
|
|
// else do nothing
|
|
|
|
if (!Compress)
|
|
iwrite(TempData, sizeof(ILubyte), TempImage->SizeOfData);
|
|
else {
|
|
Rle = (ILubyte*)ialloc(TempImage->SizeOfData + TempImage->SizeOfData / 2 + 1); // max
|
|
if (Rle == NULL) {
|
|
ifree(AuthName);
|
|
ifree(AuthComment);
|
|
return IL_FALSE;
|
|
}
|
|
RleLen = ilRleCompress((unsigned char*)TempData, TempImage->Width, TempImage->Height,
|
|
TempImage->Depth, TempImage->Bpp, Rle, IL_TGACOMP, NULL);
|
|
|
|
iwrite(Rle, 1, RleLen);
|
|
ifree(Rle);
|
|
}
|
|
|
|
// Write the extension area.
|
|
ExtOffset = itellw();
|
|
SaveLittleUShort(495); // Number of bytes in the extension area (TGA 2.0 spec)
|
|
iwrite(AuthName, 1, ilStrLen(AuthName));
|
|
ipad(41 - ilStrLen(AuthName));
|
|
iwrite(AuthComment, 1, ilStrLen(AuthComment));
|
|
ipad(324 - ilStrLen(AuthComment));
|
|
ifree(AuthName);
|
|
ifree(AuthComment);
|
|
|
|
// Write time/date
|
|
iGetDateTime(&Month, &Day, &Year, &Hour, &Minute, &Second);
|
|
SaveLittleUShort((ILushort)Month);
|
|
SaveLittleUShort((ILushort)Day);
|
|
SaveLittleUShort((ILushort)Year);
|
|
SaveLittleUShort((ILushort)Hour);
|
|
SaveLittleUShort((ILushort)Minute);
|
|
SaveLittleUShort((ILushort)Second);
|
|
|
|
for (i = 0; i < 6; i++) { // Time created
|
|
SaveLittleUShort(0);
|
|
}
|
|
for (i = 0; i < 41; i++) { // Job name/ID
|
|
iputc(0);
|
|
}
|
|
for (i = 0; i < 3; i++) { // Job time
|
|
SaveLittleUShort(0);
|
|
}
|
|
|
|
iwrite(idString, 1, strlen(idString)); // Software ID
|
|
for (i = 0; i < 41 - strlen(idString); i++) {
|
|
iputc(0);
|
|
}
|
|
SaveLittleUShort(IL_VERSION); // Software version
|
|
iputc(' '); // Release letter (not beta anymore, so use a space)
|
|
|
|
SaveLittleUInt(0); // Key colour
|
|
SaveLittleUInt(0); // Pixel aspect ratio
|
|
SaveLittleUInt(0); // Gamma correction offset
|
|
SaveLittleUInt(0); // Colour correction offset
|
|
SaveLittleUInt(0); // Postage stamp offset
|
|
SaveLittleUInt(0); // Scan line offset
|
|
iputc(3); // Attributes type
|
|
|
|
// Write the footer.
|
|
SaveLittleUInt(ExtOffset); // No extension area
|
|
SaveLittleUInt(0); // No developer directory
|
|
iwrite(Footer, 1, strlen(Footer));
|
|
|
|
if (TempImage->Origin != IL_ORIGIN_LOWER_LEFT) {
|
|
ifree(TempData);
|
|
}
|
|
if (Format == IL_RGB || Format == IL_RGBA) {
|
|
ilSwapColours();
|
|
}
|
|
|
|
if (TempPal != &iCurImage->Pal && TempPal != NULL) {
|
|
ifree(TempPal->Palette);
|
|
ifree(TempPal);
|
|
}
|
|
|
|
if (TempImage != iCurImage)
|
|
ilCloseImage(TempImage);
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
/*// Makes a neat string to go into the id field of the .tga
|
|
ILvoid iMakeString(char *Str)
|
|
{
|
|
char *PSG = "Generated by Developer's Image Library: ";
|
|
char TimeStr[255];
|
|
|
|
time_t Time;
|
|
struct tm *CurTime;
|
|
|
|
time(&Time);
|
|
#ifdef _WIN32
|
|
_tzset();
|
|
#endif
|
|
CurTime = localtime(&Time);
|
|
|
|
strftime(TimeStr, 255 - strlen(PSG), "%#c (%z)", CurTime);
|
|
//strftime(TimeStr, 255 - strlen(PSG), "%C (%Z)", CurTime);
|
|
sprintf(Str, "%s%s", PSG, TimeStr);
|
|
|
|
return;
|
|
}*/
|
|
|
|
|
|
//changed name to iGetDateTime on 20031221 to fix bug 830196
|
|
ILvoid iGetDateTime(ILuint *Month, ILuint *Day, ILuint *Yr, ILuint *Hr, ILuint *Min, ILuint *Sec)
|
|
{
|
|
#ifdef DJGPP
|
|
struct date day;
|
|
struct time curtime;
|
|
|
|
gettime(&curtime);
|
|
getdate(&day);
|
|
|
|
*Month = day.da_mon;
|
|
*Day = day.da_day;
|
|
*Yr = day.da_year;
|
|
|
|
*Hr = curtime.ti_hour;
|
|
*Min = curtime.ti_min;
|
|
*Sec = curtime.ti_sec;
|
|
|
|
return;
|
|
#else
|
|
|
|
#ifdef _WIN32
|
|
SYSTEMTIME Time;
|
|
|
|
GetSystemTime(&Time);
|
|
|
|
*Month = Time.wMonth;
|
|
*Day = Time.wDay;
|
|
*Yr = Time.wYear;
|
|
|
|
*Hr = Time.wHour;
|
|
*Min = Time.wMinute;
|
|
*Sec = Time.wSecond;
|
|
|
|
return;
|
|
#else
|
|
|
|
*Month = 0;
|
|
*Day = 0;
|
|
*Yr = 0;
|
|
|
|
*Hr = 0;
|
|
*Min = 0;
|
|
*Sec = 0;
|
|
|
|
return;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
#endif//IL_NO_TGA
|