You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
291 lines
6.9 KiB
291 lines
6.9 KiB
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ilu.h>
|
|
#include <lzo/lzo1x.h>
|
|
#include "il_paa.h"
|
|
|
|
// globals
|
|
static ILHANDLE PAAFile;
|
|
static long OFFSOffset = 0;
|
|
|
|
// internal
|
|
ILboolean ilSavePAAInternal(void);
|
|
|
|
//! Writes a PAA file
|
|
ILenum ILAPIENTRY ilSavePAA(const char *FileName)
|
|
{
|
|
PAAFile = fopen(FileName, "w");
|
|
if (PAAFile == NULL) {
|
|
return IL_FILE_WRITE_ERROR;
|
|
}
|
|
|
|
if (ilSavePAAInternal() == IL_FALSE) {
|
|
return IL_INTERNAL_ERROR;
|
|
}
|
|
|
|
fclose(PAAFile);
|
|
PAAFile = NULL;
|
|
|
|
return IL_NO_ERROR;
|
|
}
|
|
|
|
void WriteTagg(ILconst_string name, ILuint size, ILubyte* data)
|
|
{
|
|
fwrite(PAA_TAGG_SIGNATURE, sizeof(int8_t), 4, PAAFile);
|
|
fwrite(name, sizeof(int8_t), 4, PAAFile);
|
|
fwrite(&size, sizeof(int32_t), 1, PAAFile);
|
|
fwrite(data, sizeof(int8_t), size, PAAFile);
|
|
}
|
|
|
|
ILubyte* GetAvgColor()
|
|
{
|
|
ILuint Image, TempImage;
|
|
ILubyte *Data;
|
|
ILint Size;
|
|
ILenum Format, Type;
|
|
ILuint NumPixel, R, G, B, A;
|
|
|
|
TempImage = Image = ilGetInteger(IL_CUR_IMAGE);
|
|
Format = ilGetInteger(IL_IMAGE_FORMAT);
|
|
Type = ilGetInteger(IL_IMAGE_TYPE);
|
|
|
|
if ((Type != IL_UNSIGNED_BYTE && Type != IL_BYTE) || Format == IL_COLOUR_INDEX) {
|
|
TempImage = ilGenImage();
|
|
ilCopyImage(Image);
|
|
ilBindImage(TempImage);
|
|
ilConvertImage(IL_UNSIGNED_BYTE, IL_RGBA);
|
|
}
|
|
|
|
Size = ilGetInteger(IL_IMAGE_SIZE_OF_DATA);
|
|
NumPixel = ilGetInteger(IL_IMAGE_WIDTH) * ilGetInteger(IL_IMAGE_HEIGHT);
|
|
Data = ilGetData();
|
|
|
|
R = G = B = A = 0;
|
|
for (int i = 0; i < Size; i += 4) {
|
|
R += Data[i];
|
|
G += Data[i+1];
|
|
B += Data[i+2];
|
|
A += Data[i+3];
|
|
}
|
|
|
|
ILubyte* color = malloc(sizeof(int8_t) * 4);
|
|
color[0] = R / NumPixel;
|
|
color[1] = G / NumPixel;
|
|
color[2] = B / NumPixel;
|
|
color[3] = A / NumPixel;
|
|
|
|
if (TempImage != Image)
|
|
{
|
|
ilDeleteImage(TempImage);
|
|
ilBindImage(Image);
|
|
}
|
|
|
|
return color;
|
|
}
|
|
|
|
void WriteMipmap(ILushort width, ILushort height, ILuint size, ILubyte* data)
|
|
{
|
|
ILubyte SizeInt24[3];
|
|
|
|
fwrite(&width, sizeof(int16_t), 1, PAAFile);
|
|
fwrite(&height, sizeof(int16_t), 1, PAAFile);
|
|
|
|
if (width && height) {
|
|
// convert ILuint to uint24
|
|
SizeInt24[0] = (ILubyte) (size & 0xFF);
|
|
SizeInt24[1] = (ILubyte) (size >> 8);
|
|
SizeInt24[2] = (ILubyte) (size >> 16);
|
|
fwrite(SizeInt24, sizeof(int8_t), 3, PAAFile);
|
|
|
|
fwrite(data, sizeof(int8_t), size, PAAFile);
|
|
}
|
|
}
|
|
|
|
ILboolean WritePAAHeader(void)
|
|
{
|
|
ILint DXTCFormat = ilGetInteger(IL_DXTC_FORMAT);
|
|
ILenum FlagTagg = PAA_TAGG_FLAG_NONE;
|
|
|
|
if (DXTCFormat == IL_DXT1) {
|
|
WritePAAType(PAA_TYPE_DXT1)
|
|
FlagTagg = PAA_TAGG_FLAG_ALPHA_NOT_INTERPOLATED;
|
|
} else if (DXTCFormat == IL_DXT5) {
|
|
WritePAAType(PAA_TYPE_DXT5)
|
|
FlagTagg = PAA_TAGG_FLAG_BASIC_TRANSPARENCY;
|
|
} else {
|
|
// Unsupported Format
|
|
return IL_FALSE;
|
|
}
|
|
|
|
// Write Taggs
|
|
WriteAVGCTagg()
|
|
WriteMAXCTagg()
|
|
if (FlagTagg != PAA_TAGG_FLAG_NONE) {
|
|
WriteFLAGTagg(FlagTagg);
|
|
}
|
|
|
|
// Write empty OFFS Tagg
|
|
OFFSOffset = ftell(PAAFile);
|
|
ILubyte *EmptyOffs = calloc(PAA_TAGG_OFFS_OFFSET_NUM, sizeof(int32_t));
|
|
if (EmptyOffs == NULL) {
|
|
return IL_FALSE;
|
|
}
|
|
WriteTagg(PAA_TAGG_OFFS, PAA_TAGG_OFFS_SIZE, EmptyOffs);
|
|
free(EmptyOffs);
|
|
|
|
// Write empty Palette
|
|
ILushort Palette = 0;
|
|
fwrite(&Palette, sizeof(int16_t), 1, PAAFile);
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
void CompleteOffsets(ILuint* offsets)
|
|
{
|
|
long Pos = ftell(PAAFile);
|
|
fseek(PAAFile, OFFSOffset, SEEK_SET);
|
|
|
|
WriteTagg(PAA_TAGG_OFFS, PAA_TAGG_OFFS_SIZE, (ILubyte *) offsets);
|
|
|
|
OFFSOffset = 0;
|
|
fseek(PAAFile, Pos, SEEK_SET);
|
|
}
|
|
|
|
ILubyte* LZOCompressDXT(ILubyte* Data, ILuint Size, lzo_uint *CompressedSize)
|
|
{
|
|
int r;
|
|
lzo_voidp WrkMem;
|
|
ILubyte *Buffer;
|
|
|
|
*CompressedSize = Size + Size / 16 + 64 + 3;
|
|
|
|
if (lzo_init() != LZO_E_OK) {
|
|
// TODO: Error logging
|
|
return NULL;
|
|
}
|
|
|
|
WrkMem = malloc(LZO1X_999_MEM_COMPRESS);
|
|
if (WrkMem == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
Buffer = malloc(*CompressedSize);
|
|
if (Buffer == NULL) {
|
|
free(WrkMem);
|
|
return NULL;
|
|
}
|
|
|
|
r = lzo1x_999_compress(Data, Size, Buffer, (lzo_uint *) CompressedSize, WrkMem);
|
|
|
|
free(WrkMem);
|
|
|
|
if (r != LZO_E_OK) {
|
|
free(Buffer);
|
|
// TODO: Error logging
|
|
return NULL;
|
|
}
|
|
|
|
if (*CompressedSize >= Size) {
|
|
free(Buffer);
|
|
// Return original data because it is smaller
|
|
*CompressedSize = 0;
|
|
return Data;
|
|
}
|
|
|
|
return Buffer;
|
|
}
|
|
|
|
ILboolean WriteImages(void)
|
|
{
|
|
ILuint Image, Offsets[PAA_TAGG_OFFS_OFFSET_NUM], Width, Height, DXTCSize;
|
|
ILint NumMipmaps, DXTCFormat;
|
|
ILubyte *DXTCData, *CompressedData;
|
|
ILushort End = 0;
|
|
lzo_uint CompressedSize;
|
|
|
|
if (!iluBuildMipmaps()) {
|
|
return IL_FALSE;
|
|
}
|
|
|
|
Image = ilGetInteger(IL_CUR_IMAGE);
|
|
DXTCFormat = ilGetInteger(IL_DXTC_FORMAT);
|
|
NumMipmaps = ilGetInteger(IL_NUM_MIPMAPS);
|
|
if (NumMipmaps > PAA_TAGG_OFFS_OFFSET_NUM) {
|
|
NumMipmaps = PAA_TAGG_OFFS_OFFSET_NUM;
|
|
}
|
|
memset(Offsets, 0, sizeof(int32_t) * PAA_TAGG_OFFS_OFFSET_NUM);
|
|
|
|
// Write MipMaps
|
|
for (int i = 0; i < NumMipmaps; ++i) {
|
|
ilBindImage(Image);
|
|
ilActiveMipmap(i);
|
|
|
|
Offsets[i] = ftell(PAAFile);
|
|
|
|
Width = ilGetInteger(IL_IMAGE_WIDTH);
|
|
Height = ilGetInteger(IL_IMAGE_HEIGHT);
|
|
|
|
DXTCData = ilCompressDXT(ilGetData(), Width, Height, 1, DXTCFormat, &DXTCSize);
|
|
|
|
if (DXTCData == NULL) {
|
|
return IL_FALSE;
|
|
}
|
|
|
|
// Compress only the first (PAA_LZO_MODE_COMPRESS_FIRST) Mipmap (original size)
|
|
if (i == 0) {
|
|
CompressedData = LZOCompressDXT(DXTCData, DXTCSize, &CompressedSize);
|
|
if (CompressedData == NULL) {
|
|
return IL_FALSE;
|
|
} else if (CompressedSize > 0) {
|
|
free(DXTCData);
|
|
DXTCData = CompressedData;
|
|
DXTCSize = CompressedSize;
|
|
|
|
Width |= 0x8000u;
|
|
}
|
|
}
|
|
|
|
WriteMipmap(Width, Height, DXTCSize, DXTCData);
|
|
// TODO: Remove Offset if MipMap was not written (Width or Height == 0), Handle abort case
|
|
}
|
|
|
|
// Create empty MipMap to mark end
|
|
WriteMipmap(0, 0, -1, NULL);
|
|
|
|
// Write last 2 zero bytes to mark the end
|
|
fwrite(&End, sizeof(int16_t), 1, PAAFile);
|
|
|
|
// Write offsets, now that we know
|
|
CompleteOffsets(Offsets);
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
ILboolean ilSavePAAInternal(void)
|
|
{
|
|
WritePAAHeader();
|
|
WriteImages();
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
// internal API
|
|
ILboolean il_paa_init(void)
|
|
{
|
|
ILboolean Register;
|
|
|
|
Register = ilRegisterSave("paa", (IL_SAVEPROC) &ilSavePAA);
|
|
// Register &= ilRegisterLoad("paa", (IL_LOADPROC) &ilLoadPAA);
|
|
|
|
return Register;
|
|
}
|
|
|
|
ILboolean il_paa_destroy(void)
|
|
{
|
|
ILboolean Remove;
|
|
|
|
Remove = ilRemoveSave("paa");
|
|
// Remove &= ilRemoveLoad("paa");
|
|
|
|
return Remove;
|
|
}
|
|
|