mirror of
https://github.com/love2d/megasource.git
synced 2026-08-17 11:11:35 +02:00
Add DevIL 1.7.8.
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Last modified: 17/04/2005
|
||||
// by Meloni Dario
|
||||
//
|
||||
// Description: Common altivec function.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif //HAVE_CONFIG_H
|
||||
|
||||
#ifdef ALTIVEC_GCC
|
||||
#include "altivec_common.h"
|
||||
|
||||
// from http://developer.apple.com/hardware/ve/alignment.html
|
||||
/*vector unsigned char load_unaligned( unsigned char *buffer ) {
|
||||
vector unsigned char MSQ, LSQ;
|
||||
vector unsigned char mask;
|
||||
MSQ = vec_ld(0, buffer); // most significant quadword
|
||||
LSQ = vec_ld(15, buffer); // least significant quadword
|
||||
mask = vec_lvsl(0, buffer); // create the permute mask
|
||||
return vec_perm(MSQ, LSQ, mask);// align the data
|
||||
}*/
|
||||
|
||||
vector float fill_vector_f( float value ) {
|
||||
vector_t vec;
|
||||
vec.sf[0] = value;
|
||||
vector float temp = vec_ld(0,vec.sf);
|
||||
return vec_splat(temp,0);
|
||||
}
|
||||
|
||||
inline unsigned int round16( unsigned int v ) {
|
||||
return ((int)((v/16)*10)%10) > 0 ? (v/16) : (v/16)+1;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,230 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif //HAVE_CONFIG_H
|
||||
|
||||
#ifdef ALTIVEC_GCC
|
||||
#include "altivec_typeconversion.h"
|
||||
|
||||
static inline void abc2cba_internal( register const vector unsigned char p[4], unsigned char *data, register unsigned int length, unsigned char *newdata ) {
|
||||
register vector unsigned char d0,d1,d2,t0,t1,t2;
|
||||
|
||||
length = eround16(length);
|
||||
|
||||
if( length >= 3 ) {
|
||||
length -= 3;
|
||||
|
||||
d2 = vec_ld(32,data);
|
||||
d1 = vec_ld(16,data);
|
||||
d0 = vec_ld(0,data);
|
||||
|
||||
while( length >= 3 ) {
|
||||
t0 = vec_perm(d0,d1,p[0]);
|
||||
t1 = vec_perm(d1,d0,p[1]);
|
||||
t2 = vec_perm(d2,d1,p[2]);
|
||||
t1 = vec_perm(t1,d2,p[3]);
|
||||
|
||||
vec_st(t0,0,newdata);
|
||||
vec_st(t1,16,newdata);
|
||||
vec_st(t2,32,newdata);
|
||||
|
||||
length -= 3;
|
||||
data += 16*3;
|
||||
newdata += 16*3;
|
||||
|
||||
d2 = vec_ld(32,data);
|
||||
d1 = vec_ld(16,data);
|
||||
d0 = vec_ld(0,data);
|
||||
}
|
||||
t0 = vec_perm(d0,d1,p[0]);
|
||||
t1 = vec_perm(d1,d0,p[1]);
|
||||
t2 = vec_perm(d2,d1,p[2]);
|
||||
t1 = vec_perm(t1,d2,p[3]);
|
||||
|
||||
vec_st(t0,0,newdata);
|
||||
vec_st(t1,16,newdata);
|
||||
vec_st(t2,32,newdata);
|
||||
}
|
||||
|
||||
if( length == 2 ) {
|
||||
d0 = vec_ld(0,data);
|
||||
d1 = vec_ld(16,data);
|
||||
|
||||
t0 = vec_perm(d0,d1,p[0]);
|
||||
t1 = vec_perm(d1,d0,p[1]);
|
||||
|
||||
vec_st(t0,0,newdata);
|
||||
vec_st(t1,16,newdata);
|
||||
} else if( length == 1 ) {
|
||||
d0 = vec_ld(0,data);
|
||||
t0 = vec_perm(d0,d0,p[0]);
|
||||
vec_st(t0,0,newdata);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void abcd2cbad_internal( register const vector unsigned char p, unsigned char *data, unsigned int length, unsigned char *newdata ) {
|
||||
register vector unsigned char d0,d1,d2,z;
|
||||
z = vec_splat_u8(0);
|
||||
|
||||
length = eround16(length);
|
||||
|
||||
if( length >= 3 ) {
|
||||
length -= 3;
|
||||
|
||||
d2 = vec_ld(32,data);
|
||||
d1 = vec_ld(16,data);
|
||||
d0 = vec_ld(0,data);
|
||||
|
||||
while( length >= 3 ) {
|
||||
d0 = vec_perm(d0,z,p);
|
||||
d1 = vec_perm(d1,z,p);
|
||||
d2 = vec_perm(d2,z,p);
|
||||
|
||||
vec_st(d0,0,newdata);
|
||||
vec_st(d1,16,newdata);
|
||||
vec_st(d2,32,newdata);
|
||||
|
||||
length -= 3;
|
||||
data += 16*3;
|
||||
newdata += 16*3;
|
||||
|
||||
d2 = vec_ld(32,data);
|
||||
d1 = vec_ld(16,data);
|
||||
d0 = vec_ld(0,data);
|
||||
}
|
||||
d0 = vec_perm(d0,z,p);
|
||||
d1 = vec_perm(d1,z,p);
|
||||
d2 = vec_perm(d2,z,p);
|
||||
|
||||
vec_st(d0,0,newdata);
|
||||
vec_st(d1,16,newdata);
|
||||
vec_st(d2,32,newdata);
|
||||
}
|
||||
|
||||
if( length == 2 ) {
|
||||
d0 = vec_ld(0,data);
|
||||
d1 = vec_ld(16,data);
|
||||
|
||||
d0 = vec_perm(d0,z,p);
|
||||
d1 = vec_perm(d1,z,p);
|
||||
|
||||
vec_st(d0,0,newdata);
|
||||
vec_st(d1,16,newdata);
|
||||
} else if( length == 1 ) {
|
||||
d0 = vec_ld(0,data);
|
||||
d0 = vec_perm(d0,d0,z);
|
||||
vec_st(d0,0,newdata);
|
||||
}
|
||||
}
|
||||
|
||||
// Format conversion function
|
||||
void abc2cba_byte( ILubyte *data, ILuint length, ILubyte *newdata ) {
|
||||
const vector unsigned char p[4] =
|
||||
{ (vector unsigned char)(0x02,0x01,0x00,0x05,0x04,0x03,0x08,0x07,0x06,0x0B,0x0A,0x09,0x0E,0x0D,0x0C,0x11),
|
||||
(vector unsigned char)(0x00,0x10,0x04,0x03,0x02,0x07,0x06,0x05,0x0A,0x09,0x08,0x0D,0x0C,0x0B,0x0E,0x0F),
|
||||
(vector unsigned char)(0x1E,0x03,0x02,0x01,0x06,0x05,0x04,0x09,0x08,0x07,0x0C,0x0B,0x0A,0x0F,0x0E,0x0D),
|
||||
(vector unsigned char)(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x10,0x0F)};
|
||||
abc2cba_internal(p,data,length,newdata);
|
||||
}
|
||||
|
||||
void abc2cba_short( ILushort *data, ILuint length, ILushort *newdata ) {
|
||||
const vector unsigned char p[4] =
|
||||
{ (vector unsigned char)(0x04,0x05,0x02,0x03,0x00,0x01,0x0A,0x0B,0x08,0x09,0x06,0x07,0x10,0x11,0x0E,0x0F),
|
||||
(vector unsigned char)(0x1C,0x1D,0x06,0x07,0x04,0x05,0x02,0x03,0x0C,0x0D,0x0A,0x0B,0x08,0x09,0x0E,0x0F),
|
||||
(vector unsigned char)(0x00,0x01,0x1E,0x1F,0x08,0x09,0x06,0x07,0x04,0x05,0x0E,0x0F,0x0C,0x0D,0x0A,0x0B),
|
||||
(vector unsigned char)(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x12,0x13)};
|
||||
abc2cba_internal(p,(ILubyte*)data,length,(ILubyte*)newdata);
|
||||
}
|
||||
|
||||
void abc2cba_int( ILuint *data, ILuint length, ILuint *newdata ) {
|
||||
const vector unsigned char p[4] =
|
||||
{ (vector unsigned char)(0x08,0x09,0x0A,0x0B,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x14,0x15,0x16,0x17),
|
||||
(vector unsigned char)(0x00,0x01,0x02,0x03,0x1C,0x1D,0x1E,0x1F,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F),
|
||||
(vector unsigned char)(0x18,0x19,0x1A,0x1B,0x0C,0x0D,0x0E,0x0F,0x08,0x09,0x0A,0x0B,0x04,0x05,0x06,0x07),
|
||||
(vector unsigned char)(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x10,0x11,0x12,0x13,0x0C,0x0D,0x0E,0x0F)};
|
||||
abc2cba_internal(p,(ILubyte*)data,length,(ILubyte*)newdata);
|
||||
}
|
||||
|
||||
void abc2cba_double( ILdouble *data, ILuint length, ILdouble *newdata ) {
|
||||
const vector unsigned char p[4] =
|
||||
{ (vector unsigned char)(0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F),
|
||||
(vector unsigned char)(0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F),
|
||||
(vector unsigned char)(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F),
|
||||
(vector unsigned char)(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F)};
|
||||
abc2cba_internal(p,(ILubyte*)data,length,(ILubyte*)newdata);
|
||||
}
|
||||
|
||||
void abcd2cbad_byte( ILubyte *data, ILuint length, ILubyte *newdata ) {
|
||||
const vector unsigned char p = (vector unsigned char)(0x02,0x01,0x00,0x03,0x06,0x05,0x04,0x07,0x0A,0x09,0x08,0x0B, 0x0E,0x0D,0x0C,0x0F);
|
||||
abcd2cbad_internal(p,data,length,newdata);
|
||||
}
|
||||
|
||||
void abcd2cbad_short( ILushort *data, ILuint length, ILushort *newdata ) {
|
||||
const vector unsigned char p = (vector unsigned char)(0x04,0x05,0x02,0x03,0x00,0x01,0x06,0x07,0x0C,0x0D,0x0A,0x0B,0x08,0x09,0x0E,0x0F);
|
||||
abcd2cbad_internal(p,(ILubyte*)data,length,(ILubyte*)newdata);
|
||||
}
|
||||
|
||||
void abcd2cbad_int( ILuint *data, ILuint length, ILuint *newdata ) {
|
||||
const vector unsigned char p = (vector unsigned char)(0x08,0x09,0x0A,0x0B,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,0x0C,0x0D,0x0E,0x0F);
|
||||
abcd2cbad_internal(p,(ILubyte*)data,length,(ILubyte*)newdata);
|
||||
}
|
||||
|
||||
void abcd2cbad_double( ILdouble *tdata, ILuint length, ILdouble *tnewdata ) {
|
||||
register ILubyte *data = (ILubyte*)tdata;
|
||||
register ILubyte *newdata = (ILubyte*)tnewdata;
|
||||
const vector unsigned char p = (vector unsigned char)(0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F);
|
||||
register vector unsigned char d0,d1,d2,d3,t0,t1,t2,t3;
|
||||
|
||||
length = eround16(length);
|
||||
|
||||
if( length >= 4 ) {
|
||||
length -= 4;
|
||||
|
||||
d3 = vec_ld(48,data);
|
||||
d2 = vec_ld(32,data);
|
||||
d1 = vec_ld(16,data);
|
||||
d0 = vec_ld(0,data);
|
||||
|
||||
while( length >= 4 ) {
|
||||
t0 = vec_perm(d0,d1,p);
|
||||
t1 = vec_perm(d1,d0,p);
|
||||
t2 = vec_perm(d2,d3,p);
|
||||
t3 = vec_perm(d3,d2,p);
|
||||
|
||||
vec_st(t0,0,newdata);
|
||||
vec_st(t1,16,newdata);
|
||||
vec_st(t2,32,newdata);
|
||||
vec_st(t3,48,newdata);
|
||||
|
||||
length -= 4;
|
||||
data += 16*4;
|
||||
newdata += 16*4;
|
||||
|
||||
d3 = vec_ld(48,data);
|
||||
d2 = vec_ld(32,data);
|
||||
d1 = vec_ld(16,data);
|
||||
d0 = vec_ld(0,data);
|
||||
}
|
||||
t0 = vec_perm(d0,d1,p);
|
||||
t1 = vec_perm(d1,d0,p);
|
||||
t2 = vec_perm(d2,d3,p);
|
||||
t3 = vec_perm(d3,d2,p);
|
||||
|
||||
vec_st(d0,0,newdata);
|
||||
vec_st(d1,16,newdata);
|
||||
vec_st(d2,32,newdata);
|
||||
vec_st(d3,48,newdata);
|
||||
}
|
||||
|
||||
if( length == 2 ) {
|
||||
d0 = vec_ld(0,data);
|
||||
d1 = vec_ld(16,data);
|
||||
|
||||
t0 = vec_perm(d0,d1,p);
|
||||
t1 = vec_perm(d1,d0,p);
|
||||
|
||||
vec_st(t0,0,newdata);
|
||||
vec_st(t1,16,newdata);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,287 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Last modified: 08/17/2008
|
||||
//
|
||||
// Filename: src-IL/src/il_alloc.c
|
||||
//
|
||||
// Description: Memory allocation functions
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#define __ALLOC_C
|
||||
|
||||
// Memory leak detection
|
||||
#ifdef _WIN32
|
||||
#ifdef _DEBUG
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#ifndef _WIN32_WCE // Does not have this header.
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif//_WIN32
|
||||
|
||||
#include "il_internal.h"
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef MM_MALLOC
|
||||
#include <mm_malloc.h>
|
||||
#endif
|
||||
|
||||
static void ILAPIENTRY DefaultFreeFunc(const void * CONST_RESTRICT Ptr);
|
||||
static void* ILAPIENTRY DefaultAllocFunc(const ILsizei Size);
|
||||
|
||||
static mAlloc ialloc_ptr = DefaultAllocFunc;
|
||||
static mFree ifree_ptr = DefaultFreeFunc;
|
||||
|
||||
/*** Vector Allocation/Deallocation Function ***/
|
||||
#ifdef VECTORMEM
|
||||
void *vec_malloc(const ILsizei size)
|
||||
{
|
||||
const ILsizei _size = size % 16 > 0 ? size + 16 - (size % 16) : size; // align size value
|
||||
|
||||
#ifdef MM_MALLOC
|
||||
return _mm_malloc(_size,16);
|
||||
#else
|
||||
#ifdef VALLOC
|
||||
return valloc( _size );
|
||||
#else
|
||||
#ifdef POSIX_MEMALIGN
|
||||
char *buffer;
|
||||
return posix_memalign((void**)&buffer, 16, _size) == 0 ? buffer : NULL;
|
||||
#else
|
||||
#ifdef MEMALIGN
|
||||
return memalign( 16, _size );
|
||||
#else
|
||||
// Memalign hack from ffmpeg for MinGW
|
||||
void *ptr;
|
||||
int diff;
|
||||
ptr = malloc(_size+16+1);
|
||||
diff= ((-(int)ptr - 1)&15) + 1;
|
||||
ptr = (void*)(((char*)ptr)+diff);
|
||||
((char*)ptr)[-1]= diff;
|
||||
return ptr;
|
||||
#endif //MEMALIGN
|
||||
#endif //POSIX_MEMALIGN
|
||||
#endif //VALLOC
|
||||
#endif //MM_MALLOC
|
||||
}
|
||||
|
||||
void *ivec_align_buffer(void *buffer, const ILsizei size)
|
||||
{
|
||||
if( (ILsizei)buffer % 16 != 0 ) {
|
||||
void *aligned_buffer = vec_malloc( size );
|
||||
memcpy( aligned_buffer, buffer, size );
|
||||
ifree( buffer );
|
||||
return aligned_buffer;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*** Allocation/Deallocation Function ***/
|
||||
void* ILAPIENTRY ialloc(const ILsizei Size)
|
||||
{
|
||||
void *Ptr = ialloc_ptr(Size);
|
||||
if (Ptr == NULL)
|
||||
ilSetError(IL_OUT_OF_MEMORY);
|
||||
return Ptr;
|
||||
}
|
||||
|
||||
void ILAPIENTRY ifree(const void * CONST_RESTRICT Ptr)
|
||||
{
|
||||
if (Ptr == NULL)
|
||||
return;
|
||||
ifree_ptr(Ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
void* ILAPIENTRY icalloc(const ILsizei Size, const ILsizei Num)
|
||||
{
|
||||
void *Ptr = ialloc(Size * Num);
|
||||
if (Ptr == NULL)
|
||||
return Ptr;
|
||||
imemclear(Ptr, Size * Num);
|
||||
return Ptr;
|
||||
}
|
||||
|
||||
/*** Default Allocation/Deallocation Function ***/
|
||||
static void* ILAPIENTRY DefaultAllocFunc(const ILsizei Size)
|
||||
{
|
||||
#ifdef VECTORMEM
|
||||
return (void*)vec_malloc(Size);
|
||||
#else
|
||||
return malloc(Size);
|
||||
#endif //VECTORMEM
|
||||
}
|
||||
|
||||
static void ILAPIENTRY DefaultFreeFunc(const void * CONST_RESTRICT ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
#ifdef MM_MALLOC
|
||||
_mm_free((void*)ptr);
|
||||
#else
|
||||
#if defined(VECTORMEM) & !defined(POSIX_MEMALIGN) & !defined(VALLOC) & !defined(MEMALIGN) & !defined(MM_MALLOC)
|
||||
free(((char*)Ptr) - ((char*)Ptr)[-1]);
|
||||
#else
|
||||
free((void*)ptr);
|
||||
#endif //OTHERS...
|
||||
#endif //MM_MALLOC
|
||||
}
|
||||
}
|
||||
|
||||
/*** Manipulate Allocation/Deallocation Function ***/
|
||||
void ILAPIENTRY ilResetMemory() // Deprecated
|
||||
{
|
||||
ialloc_ptr = DefaultAllocFunc;
|
||||
ifree_ptr = DefaultFreeFunc;
|
||||
}
|
||||
|
||||
void ILAPIENTRY ilSetMemory(mAlloc AllocFunc, mFree FreeFunc)
|
||||
{
|
||||
ialloc_ptr = AllocFunc == NULL ? DefaultAllocFunc : AllocFunc;
|
||||
ifree_ptr = FreeFunc == NULL ? DefaultFreeFunc : FreeFunc;
|
||||
}
|
||||
|
||||
|
||||
/*#if defined(_WIN32) && defined(_MEM_DEBUG)
|
||||
#include <windows.h>
|
||||
|
||||
int bAtexit = 0;
|
||||
|
||||
|
||||
typedef struct ALLOC_INFO
|
||||
{
|
||||
unsigned long address;
|
||||
unsigned long size;
|
||||
char file[64];
|
||||
unsigned long line;
|
||||
struct ALLOC_INFO *Next;
|
||||
} ALLOC_INFO;
|
||||
ALLOC_INFO *AllocList;
|
||||
|
||||
|
||||
void AddTrack(unsigned long addr, unsigned long size, const char *file, unsigned long line)
|
||||
{
|
||||
ALLOC_INFO *Temp;
|
||||
|
||||
if (AllocList == NULL) {
|
||||
AllocList = (ALLOC_INFO*)malloc(sizeof(ALLOC_INFO)); // Just assume it succeeds.
|
||||
AllocList->address = addr;
|
||||
AllocList->size = size;
|
||||
AllocList->line = line;
|
||||
strncpy(AllocList->file, file, 63);
|
||||
AllocList->Next = NULL;
|
||||
}
|
||||
else {
|
||||
Temp = AllocList;
|
||||
AllocList = (ALLOC_INFO*)malloc(sizeof(ALLOC_INFO)); // Just assume it succeeds.
|
||||
AllocList->address = addr;
|
||||
AllocList->size = size;
|
||||
AllocList->line = line;
|
||||
strncpy(AllocList->file, file, 63);
|
||||
AllocList->Next = Temp;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void RemoveTrack(unsigned long addr)
|
||||
{
|
||||
ALLOC_INFO *Temp, *Prev;
|
||||
|
||||
Temp = AllocList;
|
||||
Prev = NULL;
|
||||
|
||||
if (Temp == NULL)
|
||||
return;
|
||||
|
||||
while (Temp != NULL) {
|
||||
if (Temp->address == addr) {
|
||||
if (Prev == NULL) {
|
||||
AllocList = Temp->Next;
|
||||
free(Temp);
|
||||
}
|
||||
else {
|
||||
Prev->Next = Temp->Next;
|
||||
free(Temp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
Prev = Temp;
|
||||
Temp = Temp->Next;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void DumpUnfreed(void)
|
||||
{
|
||||
unsigned long TotalSize = 0;
|
||||
char buf[1024];
|
||||
ALLOC_INFO *i = AllocList;
|
||||
|
||||
OutputDebugString("DevIL Unfreed Information:\n");
|
||||
while (i != NULL) {
|
||||
sprintf(buf, "%s(%d) : %d bytes unfreed at %d\n", i->file, i->line, i->size, i->address);
|
||||
OutputDebugString(buf);
|
||||
TotalSize += i->size;
|
||||
|
||||
AllocList = i->Next;
|
||||
free(i);
|
||||
i = AllocList;
|
||||
}
|
||||
|
||||
sprintf(buf, "-----------------------------------------------------------\n");
|
||||
OutputDebugString(buf);
|
||||
sprintf(buf, "Total Unfreed: %d bytes\n\n\n", TotalSize);
|
||||
OutputDebugString(buf);
|
||||
}
|
||||
|
||||
void AddToAtexit()
|
||||
{
|
||||
if (bAtexit)
|
||||
return;
|
||||
atexit(DumpUnfreed);
|
||||
bAtexit = 1;
|
||||
}
|
||||
|
||||
void *c_alloc(unsigned long size, unsigned long num, const char *file, unsigned long line)
|
||||
{
|
||||
void *ptr;
|
||||
ptr = calloc(size, num);
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
AddToAtexit();
|
||||
AddTrack((unsigned long)ptr, size * num, file, line);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void *m_alloc(unsigned long size, const char *file, unsigned long line)
|
||||
{
|
||||
void *ptr;
|
||||
ptr = malloc(size);
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
AddToAtexit();
|
||||
AddTrack((unsigned long)ptr, size, file, line);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void f_ree(void *ptr)
|
||||
{
|
||||
RemoveTrack((unsigned long)ptr);
|
||||
free(ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif//defined(_WIN32) && defined(_MEM_DEBUG)*/
|
||||
@@ -0,0 +1,185 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2008 by Denton Woods
|
||||
// Last modified: 08/14/2004
|
||||
//
|
||||
// Filename: src-IL/src/il_bits.c
|
||||
//
|
||||
// Description: Implements a file class that reads/writes bits directly.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#include "il_bits.h"
|
||||
|
||||
|
||||
// Opens a BITFILE just like fopen opens a FILE.
|
||||
/*BITFILE *bopen(const char *FileName, const char *Mode)
|
||||
{
|
||||
BITFILE *ToReturn = NULL;
|
||||
|
||||
if (FileName != NULL) {
|
||||
ToReturn = (BITFILE*)ialloc(sizeof(BITFILE));
|
||||
if (ToReturn != NULL) {
|
||||
iopenr((char*)FileName);
|
||||
ToReturn->File = iGetFile();
|
||||
ToReturn->BitPos = 0;
|
||||
ToReturn->ByteBitOff = 8;
|
||||
ToReturn->Buff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ToReturn;
|
||||
}*/
|
||||
|
||||
|
||||
// Converts a FILE to a BITFILE.
|
||||
BITFILE *bfile(ILHANDLE File)
|
||||
{
|
||||
BITFILE *ToReturn = NULL;
|
||||
|
||||
if (File != NULL) {
|
||||
ToReturn = (BITFILE*)ialloc(sizeof(BITFILE));
|
||||
if (ToReturn != NULL) {
|
||||
ToReturn->File = File;
|
||||
ToReturn->BitPos = itell() << 3;
|
||||
ToReturn->ByteBitOff = 8;
|
||||
ToReturn->Buff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ToReturn;
|
||||
}
|
||||
|
||||
|
||||
// Closes an open BITFILE and frees memory for it.
|
||||
ILint bclose(BITFILE *BitFile)
|
||||
{
|
||||
if (BitFile == NULL || BitFile->File == NULL)
|
||||
return IL_EOF;
|
||||
|
||||
// Removed 01-26-2008. The file will get closed later by
|
||||
// the calling function.
|
||||
//icloser(BitFile->File);
|
||||
ifree(BitFile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns the current bit position of a BITFILE.
|
||||
ILint btell(BITFILE *BitFile)
|
||||
{
|
||||
return BitFile->BitPos;
|
||||
}
|
||||
|
||||
|
||||
// Seeks in a BITFILE just like fseek for FILE.
|
||||
ILint bseek(BITFILE *BitFile, ILuint Offset, ILuint Mode)
|
||||
{
|
||||
ILint KeepPos, Len;
|
||||
|
||||
if (BitFile == NULL || BitFile->File == NULL)
|
||||
return 1;
|
||||
|
||||
switch (Mode)
|
||||
{
|
||||
case IL_SEEK_SET:
|
||||
if (!iseek(Offset >> 3, Mode)) {
|
||||
BitFile->BitPos = Offset;
|
||||
BitFile->ByteBitOff = BitFile->BitPos % 8;
|
||||
}
|
||||
break;
|
||||
case IL_SEEK_CUR:
|
||||
if (!iseek(Offset >> 3, Mode)) {
|
||||
BitFile->BitPos += Offset;
|
||||
BitFile->ByteBitOff = BitFile->BitPos % 8;
|
||||
}
|
||||
break;
|
||||
case IL_SEEK_END:
|
||||
KeepPos = itell();
|
||||
iseek(0, IL_SEEK_END);
|
||||
Len = itell();
|
||||
iseek(0, IL_SEEK_SET);
|
||||
|
||||
if (!iseek(Offset >> 3, Mode)) {
|
||||
BitFile->BitPos = (Len << 3) + Offset;
|
||||
BitFile->ByteBitOff = BitFile->BitPos % 8;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// hehe, "bread". It reads data into Buffer from the BITFILE, just like fread for FILE.
|
||||
ILint bread(void *Buffer, ILuint Size, ILuint Number, BITFILE *BitFile)
|
||||
{
|
||||
// Note that this function is somewhat useless: In binary image
|
||||
// formats, there are some pad bits after each scanline. This
|
||||
// function does not take that into account, so you must use bseek to
|
||||
// skip the calculated value of bits.
|
||||
|
||||
ILuint BuffPos = 0, Count = Size * Number;
|
||||
|
||||
while (BuffPos < Count) {
|
||||
if (BitFile->ByteBitOff < 0 || BitFile->ByteBitOff > 7) {
|
||||
BitFile->ByteBitOff = 7;
|
||||
if (iread(&BitFile->Buff, 1, 1) != 1) // Reached eof or error...
|
||||
return BuffPos;
|
||||
}
|
||||
|
||||
*((ILubyte*)(Buffer) + BuffPos) = (ILubyte)!!(BitFile->Buff & (1 << BitFile->ByteBitOff));
|
||||
|
||||
BuffPos++;
|
||||
BitFile->ByteBitOff--;
|
||||
}
|
||||
|
||||
return BuffPos;
|
||||
}
|
||||
|
||||
|
||||
// Reads bits and puts the first bit in the file as the highest in the return value.
|
||||
ILuint breadVal(ILuint NumBits, BITFILE *BitFile)
|
||||
{
|
||||
ILuint BuffPos = 0;
|
||||
ILuint Buffer = 0;
|
||||
|
||||
// Only returning up to 32 bits at one time
|
||||
if (NumBits > 32) {
|
||||
ilSetError(IL_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (BuffPos < NumBits) {
|
||||
Buffer <<= 1;
|
||||
if (BitFile->ByteBitOff < 0 || BitFile->ByteBitOff > 7) {
|
||||
BitFile->ByteBitOff = 7;
|
||||
if (iread(&BitFile->Buff, 1, 1) != 1) // Reached eof or error...
|
||||
return BuffPos;
|
||||
}
|
||||
|
||||
Buffer = Buffer + (ILubyte)!!(BitFile->Buff & (1 << BitFile->ByteBitOff));
|
||||
|
||||
BuffPos++;
|
||||
BitFile->ByteBitOff--;
|
||||
}
|
||||
|
||||
return BuffPos;
|
||||
}
|
||||
|
||||
|
||||
// Not implemented yet.
|
||||
/*ILint bwrite(void *Buffer, ILuint Size, ILuint Number, BITFILE *BitFile)
|
||||
{
|
||||
|
||||
|
||||
return 0;
|
||||
}*/
|
||||
@@ -0,0 +1,736 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 02/14/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_blp.c
|
||||
//
|
||||
// Description: Reads from a Blizzard Texture (.blp).
|
||||
// Specifications were found at http://www.wowwiki.com/BLP_files
|
||||
// for BLP2 and from
|
||||
// http://web.archive.org/web/20080117120549/magos.thejefffiles.com/War3ModelEditor/MagosBlpFormat.txt
|
||||
// for BLP1.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//@TODO: Add support for the BLP1 format as well.
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_BLP
|
||||
#include "il_dds.h"
|
||||
|
||||
|
||||
typedef struct BLP1HEAD
|
||||
{
|
||||
ILubyte Sig[4];
|
||||
ILuint Compression; // Texture type: 0 = JPG, 1 = Paletted
|
||||
ILuint Flags; // #8 - Uses alpha channel (?)
|
||||
ILuint Width; // Image width in pixels
|
||||
ILuint Height; // Image height in pixels
|
||||
ILuint PictureType; // 3 - Uncompressed index list + alpha list
|
||||
// 4 - Uncompressed index list + alpha list
|
||||
// 5 - Uncompressed index list
|
||||
ILuint PictureSubType; // 1 - ???
|
||||
ILuint MipOffsets[16]; // The file offsets of each mipmap, 0 for unused
|
||||
ILuint MipLengths[16]; // The length of each mipmap data block
|
||||
} BLP1HEAD;
|
||||
|
||||
typedef struct BLP2HEAD
|
||||
{
|
||||
ILubyte Sig[4]; // "BLP2" signature
|
||||
ILuint Type; // Texture type: 0 = JPG, 1 = DXTC
|
||||
ILubyte Compression; // Compression mode: 1 = raw, 2 = DXTC
|
||||
ILubyte AlphaBits; // 0, 1, or 8
|
||||
ILubyte AlphaType; // 0, 1, 7 or 8
|
||||
ILubyte HasMips; // 0 = no mips levels, 1 = has mips (number of levels determined by image size)
|
||||
ILuint Width; // Image width in pixels
|
||||
ILuint Height; // Image height in pixels
|
||||
ILuint MipOffsets[16]; // The file offsets of each mipmap, 0 for unused
|
||||
ILuint MipLengths[16]; // The length of each mipmap data block
|
||||
} BLP2HEAD;
|
||||
|
||||
// Data formats
|
||||
#define BLP_TYPE_JPG 0
|
||||
#define BLP_TYPE_DXTC_RAW 1
|
||||
#define BLP_RAW 1
|
||||
#define BLP_DXTC 2
|
||||
|
||||
#define BLP_RAW_PLUS_ALPHA1 3
|
||||
#define BLP_RAW_PLUS_ALPHA2 4
|
||||
#define BLP_RAW_NO_ALPHA 5
|
||||
|
||||
|
||||
ILboolean iIsValidBlp2(void);
|
||||
ILboolean iCheckBlp2(BLP2HEAD *Header);
|
||||
ILboolean iLoadBlpInternal(void);
|
||||
ILboolean iLoadBlp1(void);
|
||||
ILboolean iCheckBlp1(BLP1HEAD *Header);
|
||||
ILboolean iGetBlp1Head(BLP1HEAD *Header);
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid BLP file.
|
||||
ILboolean ilIsValidBlp(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE BlpFile;
|
||||
ILboolean bBlp = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("blp"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bBlp;
|
||||
}
|
||||
|
||||
BlpFile = iopenr(FileName);
|
||||
if (BlpFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bBlp;
|
||||
}
|
||||
|
||||
bBlp = ilIsValidBlpF(BlpFile);
|
||||
icloser(BlpFile);
|
||||
|
||||
return bBlp;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid BLP file at the current position.
|
||||
ILboolean ilIsValidBlpF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidBlp2();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid BLP lump.
|
||||
ILboolean ilIsValidBlpL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidBlp2();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the BLP header from the current file.
|
||||
ILboolean iGetBlp2Head(BLP2HEAD *Header)
|
||||
{
|
||||
ILuint i;
|
||||
|
||||
iread(Header->Sig, 1, 4);
|
||||
Header->Type = GetLittleUInt();
|
||||
Header->Compression = igetc();
|
||||
Header->AlphaBits = igetc();
|
||||
Header->AlphaType = igetc();
|
||||
Header->HasMips = igetc();
|
||||
Header->Width = GetLittleUInt();
|
||||
Header->Height = GetLittleUInt();
|
||||
for (i = 0; i < 16; i++)
|
||||
Header->MipOffsets[i] = GetLittleUInt();
|
||||
for (i = 0; i < 16; i++)
|
||||
Header->MipLengths[i] = GetLittleUInt();
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidBlp2(void)
|
||||
{
|
||||
BLP2HEAD Header;
|
||||
|
||||
if (!iGetBlp2Head(&Header))
|
||||
return IL_FALSE;
|
||||
iseek(-148, IL_SEEK_CUR);
|
||||
|
||||
return iCheckBlp2(&Header);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid BLP header.
|
||||
ILboolean iCheckBlp2(BLP2HEAD *Header)
|
||||
{
|
||||
// The file signature is 'BLP2'.
|
||||
if (strncmp(Header->Sig, "BLP2", 4))
|
||||
return IL_FALSE;
|
||||
// Valid types are JPEG and DXTC. JPEG is not common, though.
|
||||
// WoW only uses DXTC.
|
||||
if (Header->Type != BLP_TYPE_JPG && Header->Type != BLP_TYPE_DXTC_RAW)
|
||||
return IL_FALSE;
|
||||
// For BLP_TYPE_DXTC_RAW, we can have RAW and DXTC compression.
|
||||
if (Header->Compression != BLP_RAW && Header->Compression != BLP_DXTC)
|
||||
return IL_FALSE;
|
||||
// Alpha bits can only be 0, 1 and 8.
|
||||
if (Header->AlphaBits != 0 && Header->AlphaBits != 1 && Header->AlphaBits != 8)
|
||||
return IL_FALSE;
|
||||
// Alpha type can only be 0, 1, 7 and 8.
|
||||
if (Header->AlphaType != 0 && Header->AlphaType != 1 && Header->AlphaType != 7 && Header->AlphaType != 8)
|
||||
return IL_FALSE;
|
||||
// Width or height of 0 makes no sense.
|
||||
if (Header->Width == 0 || Header->Height == 0)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a BLP file
|
||||
ILboolean ilLoadBlp(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE BlpFile;
|
||||
ILboolean bBlp = IL_FALSE;
|
||||
|
||||
BlpFile = iopenr(FileName);
|
||||
if (BlpFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bBlp;
|
||||
}
|
||||
|
||||
bBlp = ilLoadBlpF(BlpFile);
|
||||
icloser(BlpFile);
|
||||
|
||||
return bBlp;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened BLP file
|
||||
ILboolean ilLoadBlpF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadBlpInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a BLP
|
||||
ILboolean ilLoadBlpL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadBlpInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the BLP.
|
||||
ILboolean iLoadBlpInternal(void)
|
||||
{
|
||||
BLP2HEAD Header;
|
||||
ILubyte *CompData;
|
||||
ILimage *Image;
|
||||
ILuint Mip, j, x, CompSize, AlphaSize, AlphaOff;
|
||||
ILint y;
|
||||
ILboolean BaseCreated = IL_FALSE;
|
||||
ILubyte *DataAndAlpha = NULL, *Palette = NULL, AlphaMask; //, *JpegHeader, *JpegData;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!iGetBlp2Head(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (!iCheckBlp2(&Header)) {
|
||||
goto check_blp1;
|
||||
}
|
||||
|
||||
//@TODO: Remove this!
|
||||
if (Header.Type != BLP_TYPE_DXTC_RAW)
|
||||
return IL_FALSE;
|
||||
|
||||
switch (Header.Compression)
|
||||
{
|
||||
case BLP_RAW:
|
||||
for (Mip = 0; Mip < 16; Mip++) { // Possible maximum of 16 mipmaps
|
||||
if (BaseCreated) {
|
||||
if (Header.HasMips == 0) // Does not have mipmaps, so we are done.
|
||||
break;
|
||||
if (Image->Width == 1 && Image->Height == 1) // Already at the smallest mipmap (1x1), so we are done.
|
||||
break;
|
||||
if (Header.MipOffsets[Mip] == 0 || Header.MipLengths == 0) // No more mipmaps in the file.
|
||||
break;
|
||||
}
|
||||
|
||||
switch (Header.AlphaBits)
|
||||
{
|
||||
case 0:
|
||||
if (!BaseCreated) { // Have not created the base image yet, so use ilTexImage.
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
Image = iCurImage;
|
||||
BaseCreated = IL_TRUE;
|
||||
|
||||
Image->Pal.Palette = (ILubyte*)ialloc(256 * 4); // 256 entries of ARGB8888 values (1024).
|
||||
if (Image->Pal.Palette == NULL)
|
||||
return IL_FALSE;
|
||||
Image->Pal.PalSize = 1024;
|
||||
Image->Pal.PalType = IL_PAL_BGRA32; //@TODO: Find out if this is really BGRA data.
|
||||
if (iread(Image->Pal.Palette, 1, 1024) != 1024) // Read in the palette.
|
||||
return IL_FALSE;
|
||||
}
|
||||
else {
|
||||
Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL);
|
||||
if (Image->Mipmaps == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
// Copy the palette from the first image before we change our Image pointer.
|
||||
iCopyPalette(&Image->Mipmaps->Pal, &Image->Pal);
|
||||
// Move to the next mipmap in the linked list.
|
||||
Image = Image->Mipmaps;
|
||||
}
|
||||
// The origin should be in the upper left.
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
// These two should be the same (tells us how much data is in the file for this mipmap level).
|
||||
if (Header.MipLengths[Mip] != Image->SizeOfData) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
// Finally read in the image data.
|
||||
iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
|
||||
if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData)
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (!BaseCreated) { // Have not created the base image yet, so use ilTexImage.
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
Image = iCurImage;
|
||||
BaseCreated = IL_TRUE;
|
||||
|
||||
Palette = (ILubyte*)ialloc(256 * 4);
|
||||
if (Palette == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
// Read in the palette.
|
||||
if (iread(Palette, 1, 1024) != 1024) {
|
||||
ifree(Palette);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// We only allocate this once and reuse this buffer with every mipmap (since successive ones are smaller).
|
||||
DataAndAlpha = (ILubyte*)ialloc(Image->Width * Image->Height);
|
||||
if (DataAndAlpha == NULL) {
|
||||
ifree(DataAndAlpha);
|
||||
ifree(Palette);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
|
||||
if (Image->Mipmaps == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
// Move to the next mipmap in the linked list.
|
||||
Image = Image->Mipmaps;
|
||||
}
|
||||
// The origin should be in the upper left.
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
// Determine the size of the alpha data following the color indices.
|
||||
AlphaSize = Image->Width * Image->Height / 8;
|
||||
if (AlphaSize == 0)
|
||||
AlphaSize = 1; // Should never be 0.
|
||||
// These two should be the same (tells us how much data is in the file for this mipmap level).
|
||||
if (Header.MipLengths[Mip] != Image->SizeOfData / 4 + AlphaSize) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Seek to the data and read it.
|
||||
iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
|
||||
if (iread(DataAndAlpha, Image->Width * Image->Height, 1) != 1) {
|
||||
ifree(DataAndAlpha);
|
||||
ifree(Palette);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Convert the color-indexed data to BGRX.
|
||||
for (j = 0; j < Image->Width * Image->Height; j++) {
|
||||
Image->Data[j*4] = Palette[DataAndAlpha[j]*4];
|
||||
Image->Data[j*4+1] = Palette[DataAndAlpha[j]*4+1];
|
||||
Image->Data[j*4+2] = Palette[DataAndAlpha[j]*4+2];
|
||||
}
|
||||
|
||||
// Read in the alpha list.
|
||||
if (iread(DataAndAlpha, AlphaSize, 1) != 1) {
|
||||
ifree(DataAndAlpha);
|
||||
ifree(Palette);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
AlphaMask = 0x01; // Lowest bit
|
||||
AlphaOff = 0;
|
||||
// The really strange thing about this alpha data is that it is upside-down when compared to the
|
||||
// regular color-indexed data, so we have to flip it.
|
||||
for (y = Image->Height - 1; y >= 0; y--) {
|
||||
for (x = 0; x < Image->Width; x++) {
|
||||
if (AlphaMask == 0) { // Shifting it past the highest bit makes it 0, since we only have 1 byte.
|
||||
AlphaOff++; // Move along the alpha buffer.
|
||||
AlphaMask = 0x01; // Reset the alpha mask.
|
||||
}
|
||||
// This is just 1-bit alpha, so it is either on or off.
|
||||
Image->Data[Image->Bps * y + x * 4 + 3] = DataAndAlpha[AlphaOff] & AlphaMask ? 0xFF : 0x00;
|
||||
AlphaMask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
//@TODO: Accept any other alpha values?
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Done, so we can finally free these two.
|
||||
ifree(DataAndAlpha);
|
||||
ifree(Palette);
|
||||
|
||||
break;
|
||||
|
||||
case BLP_DXTC:
|
||||
for (Mip = 0; Mip < 16; Mip++) { // Possible maximum of 16 mipmaps
|
||||
//@TODO: Other formats
|
||||
//if (Header.AlphaBits == 0)
|
||||
// if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
|
||||
// return IL_FALSE;
|
||||
if (!BaseCreated) { // Have not created the base image yet, so use ilTexImage.
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
Image = iCurImage;
|
||||
BaseCreated = IL_TRUE;
|
||||
}
|
||||
else {
|
||||
if (Header.HasMips == 0) // Does not have mipmaps, so we are done.
|
||||
break;
|
||||
if (Image->Width == 1 && Image->Height == 1) // Already at the smallest mipmap (1x1), so we are done.
|
||||
break;
|
||||
if (Header.MipOffsets[Mip] == 0 || Header.MipLengths[Mip] == 0) // No more mipmaps in the file.
|
||||
break;
|
||||
|
||||
//@TODO: Other formats
|
||||
// ilNewImageFull automatically changes widths and heights of 0 to 1, so we do not have to worry about it.
|
||||
Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
|
||||
if (Image->Mipmaps == NULL)
|
||||
return IL_FALSE;
|
||||
Image = Image->Mipmaps;
|
||||
}
|
||||
// The origin should be in the upper left.
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
//@TODO: Only do the allocation once.
|
||||
CompData = (ILubyte*)ialloc(Header.MipLengths[Mip]);
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
// Read in the compressed mipmap data.
|
||||
iseek(Header.MipOffsets[Mip], IL_SEEK_SET);
|
||||
if (iread(CompData, 1, Header.MipLengths[Mip]) != Header.MipLengths[Mip]) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
switch (Header.AlphaBits)
|
||||
{
|
||||
case 0: // DXT1 without alpha
|
||||
case 1: // DXT1 with alpha
|
||||
// Check to make sure that the MipLength reported is the size needed, so that
|
||||
// DecompressDXT1 does not crash.
|
||||
CompSize = ((Image->Width + 3) / 4) * ((Image->Height + 3) / 4) * 8;
|
||||
if (CompSize != Header.MipLengths[Mip]) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (!DecompressDXT1(Image, CompData)) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
// Check to make sure that the MipLength reported is the size needed, so that
|
||||
// DecompressDXT3/5 do not crash.
|
||||
CompSize = ((Image->Width + 3) / 4) * ((Image->Height + 3) / 4) * 16;
|
||||
if (CompSize != Header.MipLengths[Mip]) {
|
||||
ifree(CompData);
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
switch (Header.AlphaType)
|
||||
{
|
||||
case 0: // All three of
|
||||
case 1: // these refer to
|
||||
case 8: // DXT3...
|
||||
if (!DecompressDXT3(Image, CompData)) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: // DXT5 compression
|
||||
if (!DecompressDXT5(Image, CompData)) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
//default: // Should already be checked by iCheckBlp2.
|
||||
}
|
||||
break;
|
||||
//default: // Should already be checked by iCheckBlp2.
|
||||
}
|
||||
//@TODO: Save DXTC data.
|
||||
ifree(CompData);
|
||||
}
|
||||
break;
|
||||
//default:
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
|
||||
check_blp1:
|
||||
iseek(-148, IL_SEEK_CUR); // Go back the size of the BLP2 header, since we tried reading it.
|
||||
return iLoadBlp1();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iGetBlp1Head(BLP1HEAD *Header)
|
||||
{
|
||||
ILuint i;
|
||||
|
||||
iread(Header->Sig, 1, 4);
|
||||
Header->Compression = GetLittleUInt();
|
||||
Header->Flags = GetLittleUInt();
|
||||
Header->Width = GetLittleUInt();
|
||||
Header->Height = GetLittleUInt();
|
||||
Header->PictureType = GetLittleUInt();
|
||||
Header->PictureSubType = GetLittleUInt();
|
||||
for (i = 0; i < 16; i++)
|
||||
Header->MipOffsets[i] = GetLittleUInt();
|
||||
for (i = 0; i < 16; i++)
|
||||
Header->MipLengths[i] = GetLittleUInt();
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean iCheckBlp1(BLP1HEAD *Header)
|
||||
{
|
||||
// The file signature is 'BLP1'.
|
||||
if (strncmp(Header->Sig, "BLP1", 4))
|
||||
return IL_FALSE;
|
||||
// Valid types are JPEG and RAW. JPEG is not common, though.
|
||||
if (Header->Compression != BLP_TYPE_JPG && Header->Compression != BLP_RAW)
|
||||
return IL_FALSE;
|
||||
//@TODO: Find out what Flags is for.
|
||||
|
||||
// PictureType determines whether this has an alpha list.
|
||||
if (Header->PictureType != BLP_RAW_PLUS_ALPHA1 && Header->PictureType != BLP_RAW_PLUS_ALPHA2
|
||||
&& Header->PictureType != BLP_RAW_NO_ALPHA)
|
||||
return IL_FALSE;
|
||||
// Width or height of 0 makes no sense.
|
||||
if (Header->Width == 0 || Header->Height == 0)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadBlp1()
|
||||
{
|
||||
BLP1HEAD Header;
|
||||
ILubyte *DataAndAlpha, *Palette;
|
||||
ILuint i;
|
||||
ILimage *Image = iCurImage;
|
||||
ILboolean BaseCreated = IL_FALSE;
|
||||
#ifndef IL_NO_JPG
|
||||
ILubyte *JpegHeader, *JpegData;
|
||||
ILuint JpegHeaderSize;
|
||||
#endif//IL_NO_JPG
|
||||
|
||||
if (!iGetBlp1Head(&Header))
|
||||
return IL_FALSE;
|
||||
if (!iCheckBlp1(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
//@TODO: Remove this.
|
||||
i = 0;
|
||||
|
||||
switch (Header.Compression)
|
||||
{
|
||||
case BLP_TYPE_JPG:
|
||||
#ifdef IL_NO_JPG
|
||||
// We can only do the Jpeg decoding if we do not have IL_NO_JPEG defined.
|
||||
return IL_FALSE;
|
||||
#else
|
||||
JpegHeaderSize = GetLittleUInt();
|
||||
JpegHeader = (ILubyte*)ialloc(JpegHeaderSize);
|
||||
if (JpegHeader == NULL)
|
||||
return IL_FALSE;
|
||||
// Read the shared Jpeg header.
|
||||
if (iread(JpegHeader, 1, JpegHeaderSize) != JpegHeaderSize) {
|
||||
ifree(JpegHeader);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
//for (i = 0; i < 16; i++) { // Possible maximum of 16 mipmaps
|
||||
//@TODO: Check return value?
|
||||
iseek(Header.MipOffsets[i], IL_SEEK_SET);
|
||||
JpegData = (ILubyte*)ialloc(JpegHeaderSize + Header.MipLengths[i]);
|
||||
if (JpegData == NULL) {
|
||||
ifree(JpegHeader);
|
||||
return IL_FALSE;
|
||||
}
|
||||
memcpy(JpegData, JpegHeader, JpegHeaderSize);
|
||||
if (iread(JpegData + JpegHeaderSize, Header.MipLengths[i], 1) != 1)
|
||||
return IL_FALSE;
|
||||
|
||||
// Just send the data straight to the Jpeg loader.
|
||||
if (!ilLoadJpegL(JpegData, JpegHeaderSize + Header.MipLengths[i]))
|
||||
return IL_FALSE;
|
||||
|
||||
// The image data is in BGR(A) order, even though it is Jpeg-compressed.
|
||||
if (Image->Format == IL_RGBA)
|
||||
Image->Format = IL_BGRA;
|
||||
if (Image->Format == IL_RGB)
|
||||
Image->Format = IL_BGR;
|
||||
|
||||
ifree(JpegData);
|
||||
//}
|
||||
ifree(JpegHeader);
|
||||
#endif//IL_NO_JPG
|
||||
break;
|
||||
|
||||
case BLP_RAW:
|
||||
switch (Header.PictureType)
|
||||
{
|
||||
// There is no alpha list, so we just read like a normal indexed image.
|
||||
case BLP_RAW_NO_ALPHA:
|
||||
for (i = 0; i < 16; i++) { // Possible maximum of 16 mipmaps
|
||||
if (!BaseCreated) { // Have not created the base image yet, so use ilTexImage.
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
Image = iCurImage;
|
||||
BaseCreated = IL_TRUE;
|
||||
|
||||
// We have a BGRA palette.
|
||||
Image->Pal.Palette = (ILubyte*)ialloc(256 * 4);
|
||||
if (Image->Pal.Palette == NULL)
|
||||
return IL_FALSE;
|
||||
Image->Pal.PalSize = 1024;
|
||||
Image->Pal.PalType = IL_PAL_BGRA32;
|
||||
|
||||
// Read in the palette ...
|
||||
if (iread(Image->Pal.Palette, 1, 1024) != 1024)
|
||||
return IL_FALSE;
|
||||
}
|
||||
else {
|
||||
if (Image->Width == 1 && Image->Height == 1) // Already at the smallest mipmap (1x1), so we are done.
|
||||
break;
|
||||
if (Header.MipOffsets[i] == 0 || Header.MipLengths[i] == 0) // No more mipmaps in the file.
|
||||
break;
|
||||
|
||||
Image->Mipmaps = ilNewImageFull(Image->Width >> 1, Image->Height >> 1, 1, 1, IL_COLOR_INDEX, IL_UNSIGNED_BYTE, NULL);
|
||||
if (Image->Mipmaps == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
// Copy the palette from the first image before we change our Image pointer.
|
||||
Image->Mipmaps->Pal.Palette = (ILubyte*)ialloc(256 * 4);
|
||||
if (Image->Mipmaps->Pal.Palette == NULL)
|
||||
return IL_FALSE;
|
||||
Image->Mipmaps->Pal.PalSize = 1024;
|
||||
Image->Mipmaps->Pal.PalType = IL_PAL_BGRA32;
|
||||
memcpy(Image->Mipmaps->Pal.Palette, Image->Pal.Palette, 1024);
|
||||
|
||||
// Move to the next mipmap in the linked list.
|
||||
Image = Image->Mipmaps;
|
||||
}
|
||||
// The origin should be in the upper left.
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
// Seek to the data and read it.
|
||||
iseek(Header.MipOffsets[i], IL_SEEK_SET);
|
||||
if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData)
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
// These cases are identical and have an alpha list following the image data.
|
||||
case BLP_RAW_PLUS_ALPHA1:
|
||||
case BLP_RAW_PLUS_ALPHA2:
|
||||
// Create the image.
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
|
||||
DataAndAlpha = (ILubyte*)ialloc(Header.Width * Header.Height);
|
||||
Palette = (ILubyte*)ialloc(256 * 4);
|
||||
if (DataAndAlpha == NULL || Palette == NULL) {
|
||||
ifree(DataAndAlpha);
|
||||
ifree(Palette);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Read in the data and the palette.
|
||||
if (iread(Palette, 1, 1024) != 1024) {
|
||||
ifree(Palette);
|
||||
return IL_FALSE;
|
||||
}
|
||||
// Seek to the data and read it.
|
||||
iseek(Header.MipOffsets[i], IL_SEEK_SET);
|
||||
if (iread(DataAndAlpha, Header.Width * Header.Height, 1) != 1) {
|
||||
ifree(DataAndAlpha);
|
||||
ifree(Palette);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Convert the color-indexed data to BGRX.
|
||||
for (i = 0; i < Header.Width * Header.Height; i++) {
|
||||
Image->Data[i*4] = Palette[DataAndAlpha[i]*4];
|
||||
Image->Data[i*4+1] = Palette[DataAndAlpha[i]*4+1];
|
||||
Image->Data[i*4+2] = Palette[DataAndAlpha[i]*4+2];
|
||||
}
|
||||
|
||||
// Read in the alpha list.
|
||||
if (iread(DataAndAlpha, Header.Width * Header.Height, 1) != 1) {
|
||||
ifree(DataAndAlpha);
|
||||
ifree(Palette);
|
||||
return IL_FALSE;
|
||||
}
|
||||
// Finally put the alpha data into the image data.
|
||||
for (i = 0; i < Header.Width * Header.Height; i++) {
|
||||
Image->Data[i*4+3] = DataAndAlpha[i];
|
||||
}
|
||||
|
||||
ifree(DataAndAlpha);
|
||||
ifree(Palette);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
//default: // Should already be checked by iCheckBlp1.
|
||||
}
|
||||
|
||||
// Set the origin (always upper left).
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_BLP
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2008 by Denton Woods
|
||||
// Last modified: 10/10/2006
|
||||
//
|
||||
// Filename: src-IL/src/il_cut.c
|
||||
//
|
||||
// Description: Reads a Dr. Halo .cut file
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_CUT
|
||||
#include "il_manip.h"
|
||||
#include "il_pal.h"
|
||||
#include "il_bits.h"
|
||||
|
||||
|
||||
// Wrap it just in case...
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, packed_struct, 1)
|
||||
#endif
|
||||
typedef struct CUT_HEAD
|
||||
{
|
||||
ILushort Width;
|
||||
ILushort Height;
|
||||
ILint Dummy;
|
||||
} IL_PACKSTRUCT CUT_HEAD;
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop, packed_struct)
|
||||
#endif
|
||||
|
||||
ILboolean iLoadCutInternal();
|
||||
|
||||
//! Reads a .cut file
|
||||
ILboolean ilLoadCut(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE CutFile;
|
||||
ILboolean bCut = IL_FALSE;
|
||||
|
||||
CutFile = iopenr(FileName);
|
||||
if (CutFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bCut;
|
||||
}
|
||||
|
||||
bCut = ilLoadCutF(CutFile);
|
||||
icloser(CutFile);
|
||||
|
||||
return bCut;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .cut file
|
||||
ILboolean ilLoadCutF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadCutInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a .cut
|
||||
ILboolean ilLoadCutL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadCutInternal();
|
||||
}
|
||||
|
||||
|
||||
// Note: .Cut support has not been tested yet!
|
||||
// A .cut can only have 1 bpp.
|
||||
// We need to add support for the .pal's PSP outputs with these...
|
||||
ILboolean iLoadCutInternal()
|
||||
{
|
||||
CUT_HEAD Header;
|
||||
ILuint Size, i = 0, j;
|
||||
ILubyte Count, Run;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Header.Width = GetLittleShort();
|
||||
Header.Height = GetLittleShort();
|
||||
Header.Dummy = GetLittleInt();
|
||||
|
||||
if (Header.Width == 0 || Header.Height == 0) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) { // always 1 bpp
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
|
||||
Size = Header.Width * Header.Height;
|
||||
|
||||
while (i < Size) {
|
||||
Count = igetc();
|
||||
if (Count == 0) { // end of row
|
||||
igetc(); // Not supposed to be here, but
|
||||
igetc(); // PSP is putting these two bytes here...WHY?!
|
||||
continue;
|
||||
}
|
||||
if (Count & BIT_7) { // rle-compressed
|
||||
ClearBits(Count, BIT_7);
|
||||
Run = igetc();
|
||||
for (j = 0; j < Count; j++) {
|
||||
iCurImage->Data[i++] = Run;
|
||||
}
|
||||
}
|
||||
else { // run of pixels
|
||||
for (j = 0; j < Count; j++) {
|
||||
iCurImage->Data[i++] = igetc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT; // Not sure
|
||||
|
||||
/*iCurImage->Pal.Palette = SharedPal.Palette;
|
||||
iCurImage->Pal.PalSize = SharedPal.PalSize;
|
||||
iCurImage->Pal.PalType = SharedPal.PalType;*/
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
/* ?????????
|
||||
void ilPopToast() {
|
||||
ILstring flipCode = IL_TEXT("#flipCode and www.flipCode.com rule you all.");
|
||||
flipCode[0] = flipCode[0];
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#endif//IL_NO_CUT
|
||||
@@ -0,0 +1,486 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_dcx.c
|
||||
//
|
||||
// Description: Reads from a .dcx file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_DCX
|
||||
#include "il_dcx.h"
|
||||
#include "il_manip.h"
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid .dcx file.
|
||||
ILboolean ilIsValidDcx(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE DcxFile;
|
||||
ILboolean bDcx = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("dcx"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bDcx;
|
||||
}
|
||||
|
||||
DcxFile = iopenr(FileName);
|
||||
if (DcxFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bDcx;
|
||||
}
|
||||
|
||||
bDcx = ilIsValidDcxF(DcxFile);
|
||||
icloser(DcxFile);
|
||||
|
||||
return bDcx;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid .dcx file at the current position.
|
||||
ILboolean ilIsValidDcxF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidDcx();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid .dcx lump.
|
||||
ILboolean ilIsValidDcxL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidDcx();
|
||||
}
|
||||
|
||||
|
||||
// Internal function obtain the .dcx header from the current file.
|
||||
ILboolean iGetDcxHead(DCXHEAD *Head)
|
||||
{
|
||||
Head->Xmin = GetLittleUShort();
|
||||
Head->Ymin = GetLittleUShort();
|
||||
Head->Xmax = GetLittleUShort();
|
||||
Head->Ymax = GetLittleUShort();
|
||||
Head->HDpi = GetLittleUShort();
|
||||
Head->VDpi = GetLittleUShort();
|
||||
Head->Bps = GetLittleUShort();
|
||||
Head->PaletteInfo = GetLittleUShort();
|
||||
Head->HScreenSize = GetLittleUShort();
|
||||
Head->VScreenSize = GetLittleUShort();
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidDcx()
|
||||
{
|
||||
ILuint Signature;
|
||||
|
||||
if (iread(&Signature, 1, 4) != 4)
|
||||
return IL_FALSE;
|
||||
iseek(-4, IL_SEEK_CUR);
|
||||
|
||||
return (Signature == 987654321);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid .dcx header.
|
||||
// Should we also do a check on Header->Bpp?
|
||||
ILboolean iCheckDcx(DCXHEAD *Header)
|
||||
{
|
||||
ILuint Test, i;
|
||||
|
||||
// There are other versions, but I am not supporting them as of yet.
|
||||
// Got rid of the Reserved check, because I've seen some .dcx files with invalid values in it.
|
||||
if (Header->Manufacturer != 10 || Header->Version != 5 || Header->Encoding != 1/* || Header->Reserved != 0*/)
|
||||
return IL_FALSE;
|
||||
|
||||
// See if the padding size is correct
|
||||
Test = Header->Xmax - Header->Xmin + 1;
|
||||
/*if (Header->Bpp >= 8) {
|
||||
if (Test & 1) {
|
||||
if (Header->Bps != Test + 1)
|
||||
return IL_FALSE;
|
||||
}
|
||||
else {
|
||||
if (Header->Bps != Test) // No padding
|
||||
return IL_FALSE;
|
||||
}
|
||||
}*/
|
||||
|
||||
for (i = 0; i < 54; i++) {
|
||||
if (Header->Filler[i] != 0)
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a .dcx file
|
||||
ILboolean ilLoadDcx(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE DcxFile;
|
||||
ILboolean bDcx = IL_FALSE;
|
||||
|
||||
DcxFile = iopenr(FileName);
|
||||
if (DcxFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bDcx;
|
||||
}
|
||||
|
||||
bDcx = ilLoadDcxF(DcxFile);
|
||||
icloser(DcxFile);
|
||||
|
||||
return bDcx;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .dcx file
|
||||
ILboolean ilLoadDcxF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadDcxInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a .dcx
|
||||
ILboolean ilLoadDcxL(const void *Lump, ILuint Size) {
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadDcxInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the .dcx.
|
||||
ILboolean iLoadDcxInternal()
|
||||
{
|
||||
DCXHEAD Header;
|
||||
ILuint Signature, i, Entries[1024], Num = 0;
|
||||
ILimage *Image, *Base;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!iIsValidDcx())
|
||||
return IL_FALSE;
|
||||
iread(&Signature, 1, 4);
|
||||
|
||||
do {
|
||||
if (iread(&Entries[Num], 1, 4) != 4)
|
||||
return IL_FALSE;
|
||||
Num++;
|
||||
} while (Entries[Num-1] != 0);
|
||||
|
||||
for (i = 0; i < Num; i++) {
|
||||
iseek(Entries[i], IL_SEEK_SET);
|
||||
iGetDcxHead(&Header);
|
||||
/*if (!iCheckDcx(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}*/
|
||||
|
||||
Image = iUncompressDcx(&Header);
|
||||
if (Image == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
if (i == 0) {
|
||||
ilTexImage(Image->Width, Image->Height, 1, Image->Bpp, Image->Format, Image->Type, Image->Data);
|
||||
Base = iCurImage;
|
||||
Base->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
ilCloseImage(Image);
|
||||
}
|
||||
else {
|
||||
iCurImage->Next = Image;
|
||||
iCurImage = iCurImage->Next;
|
||||
}
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
// Internal function to uncompress the .dcx (all .dcx files are rle compressed)
|
||||
ILimage *iUncompressDcx(DCXHEAD *Header)
|
||||
{
|
||||
ILubyte ByteHead, Colour, *ScanLine = NULL /* Only one plane */;
|
||||
ILuint c, i, x, y;//, Read = 0;
|
||||
ILimage *Image = NULL;
|
||||
|
||||
if (Header->Bpp < 8) {
|
||||
/*ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;*/
|
||||
return iUncompressDcxSmall(Header);
|
||||
}
|
||||
|
||||
Image = ilNewImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 1);
|
||||
if (Image == NULL)
|
||||
return NULL;
|
||||
/*if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 0, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}*/
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
ScanLine = (ILubyte*)ialloc(Header->Bps);
|
||||
if (ScanLine == NULL)
|
||||
goto dcx_error;
|
||||
|
||||
switch (Image->Bpp)
|
||||
{
|
||||
case 1:
|
||||
Image->Format = IL_COLOUR_INDEX;
|
||||
Image->Pal.PalType = IL_PAL_RGB24;
|
||||
Image->Pal.PalSize = 256 * 3; // Need to find out for sure...
|
||||
Image->Pal.Palette = (ILubyte*)ialloc(Image->Pal.PalSize);
|
||||
if (Image->Pal.Palette == NULL)
|
||||
goto dcx_error;
|
||||
break;
|
||||
//case 2: // No 16-bit images in the dcx format!
|
||||
case 3:
|
||||
Image->Format = IL_RGB;
|
||||
Image->Pal.Palette = NULL;
|
||||
Image->Pal.PalSize = 0;
|
||||
Image->Pal.PalType = IL_PAL_NONE;
|
||||
break;
|
||||
case 4:
|
||||
Image->Format = IL_RGBA;
|
||||
Image->Pal.Palette = NULL;
|
||||
Image->Pal.PalSize = 0;
|
||||
Image->Pal.PalType = IL_PAL_NONE;
|
||||
break;
|
||||
|
||||
default:
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
goto dcx_error;
|
||||
}
|
||||
|
||||
|
||||
/*StartPos = itell();
|
||||
Compressed = (ILubyte*)ialloc(Image->SizeOfData * 4 / 3);
|
||||
iread(Compressed, 1, Image->SizeOfData * 4 / 3);
|
||||
|
||||
for (y = 0; y < Image->Height; y++) {
|
||||
for (c = 0; c < Image->Bpp; c++) {
|
||||
x = 0;
|
||||
while (x < Header->Bps) {
|
||||
ByteHead = Compressed[Read++];
|
||||
if ((ByteHead & 0xC0) == 0xC0) {
|
||||
ByteHead &= 0x3F;
|
||||
Colour = Compressed[Read++];
|
||||
for (i = 0; i < ByteHead; i++) {
|
||||
ScanLine[x++] = Colour;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ScanLine[x++] = ByteHead;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < Image->Width; x++) { // 'Cleverly' ignores the pad bytes ;)
|
||||
Image->Data[y * Image->Bps + x * Image->Bpp + c] = ScanLine[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ifree(Compressed);
|
||||
iseek(StartPos + Read, IL_SEEK_SET);*/
|
||||
|
||||
//changed 2003-09-01
|
||||
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
|
||||
iPreCache(iCurImage->SizeOfData);
|
||||
|
||||
//TODO: because the .pcx-code was broken this
|
||||
//code is probably broken, too
|
||||
for (y = 0; y < Image->Height; y++) {
|
||||
for (c = 0; c < Image->Bpp; c++) {
|
||||
x = 0;
|
||||
while (x < Header->Bps) {
|
||||
if (iread(&ByteHead, 1, 1) != 1) {
|
||||
iUnCache();
|
||||
goto dcx_error;
|
||||
}
|
||||
if ((ByteHead & 0xC0) == 0xC0) {
|
||||
ByteHead &= 0x3F;
|
||||
if (iread(&Colour, 1, 1) != 1) {
|
||||
iUnCache();
|
||||
goto dcx_error;
|
||||
}
|
||||
for (i = 0; i < ByteHead; i++) {
|
||||
ScanLine[x++] = Colour;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ScanLine[x++] = ByteHead;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < Image->Width; x++) { // 'Cleverly' ignores the pad bytes ;)
|
||||
Image->Data[y * Image->Bps + x * Image->Bpp + c] = ScanLine[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iUnCache();
|
||||
|
||||
|
||||
ifree(ScanLine);
|
||||
|
||||
// Read in the palette
|
||||
if (Image->Bpp == 1) {
|
||||
ByteHead = igetc(); // the value 12, because it signals there's a palette for some reason...
|
||||
// We should do a check to make certain it's 12...
|
||||
if (ByteHead != 12)
|
||||
iseek(-1, IL_SEEK_CUR);
|
||||
if (iread(Image->Pal.Palette, 1, Image->Pal.PalSize) != Image->Pal.PalSize) {
|
||||
ilCloseImage(Image);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return Image;
|
||||
|
||||
dcx_error:
|
||||
ifree(ScanLine);
|
||||
ilCloseImage(Image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ILimage *iUncompressDcxSmall(DCXHEAD *Header)
|
||||
{
|
||||
ILuint i = 0, j, k, c, d, x, y, Bps;
|
||||
ILubyte HeadByte, Colour, Data = 0, *ScanLine = NULL;
|
||||
ILimage *Image;
|
||||
|
||||
Image = ilNewImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 1);
|
||||
if (Image == NULL)
|
||||
return NULL;
|
||||
|
||||
/*if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, 1, 0, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}*/
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
switch (Header->NumPlanes)
|
||||
{
|
||||
case 1:
|
||||
Image->Format = IL_LUMINANCE;
|
||||
break;
|
||||
case 4:
|
||||
Image->Format = IL_COLOUR_INDEX;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
ilCloseImage(Image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (Header->NumPlanes == 1) {
|
||||
for (j = 0; j < Image->Height; j++) {
|
||||
i = 0;
|
||||
while (i < Image->Width) {
|
||||
if (iread(&HeadByte, 1, 1) != 1)
|
||||
goto file_read_error;
|
||||
if (HeadByte >= 192) {
|
||||
HeadByte -= 192;
|
||||
if (iread(&Data, 1, 1) != 1)
|
||||
goto file_read_error;
|
||||
|
||||
for (c = 0; c < HeadByte; c++) {
|
||||
k = 128;
|
||||
for (d = 0; d < 8 && i < Image->Width; d++) {
|
||||
Image->Data[j * Image->Width + i++] = (!!(Data & k) == 1 ? 255 : 0);
|
||||
k >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
k = 128;
|
||||
for (c = 0; c < 8 && i < Image->Width; c++) {
|
||||
Image->Data[j * Image->Width + i++] = (!!(HeadByte & k) == 1 ? 255 : 0);
|
||||
k >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Data != 0)
|
||||
igetc(); // Skip pad byte if last byte not a 0
|
||||
}
|
||||
}
|
||||
else { // 4-bit images
|
||||
Bps = Header->Bps * Header->NumPlanes * 2;
|
||||
Image->Pal.Palette = (ILubyte*)ialloc(16 * 3); // Size of palette always (48 bytes).
|
||||
Image->Pal.PalSize = 16 * 3;
|
||||
Image->Pal.PalType = IL_PAL_RGB24;
|
||||
ScanLine = (ILubyte*)ialloc(Bps);
|
||||
if (Image->Pal.Palette == NULL || ScanLine == NULL) {
|
||||
ifree(ScanLine);
|
||||
ilCloseImage(Image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(Image->Pal.Palette, Header->ColMap, 16 * 3);
|
||||
imemclear(Image->Data, Image->SizeOfData); // Since we do a += later.
|
||||
|
||||
for (y = 0; y < Image->Height; y++) {
|
||||
for (c = 0; c < Header->NumPlanes; c++) {
|
||||
x = 0;
|
||||
while (x < Bps) {
|
||||
if (iread(&HeadByte, 1, 1) != 1)
|
||||
goto file_read_error;
|
||||
if ((HeadByte & 0xC0) == 0xC0) {
|
||||
HeadByte &= 0x3F;
|
||||
if (iread(&Colour, 1, 1) != 1)
|
||||
goto file_read_error;
|
||||
for (i = 0; i < HeadByte; i++) {
|
||||
k = 128;
|
||||
for (j = 0; j < 8; j++) {
|
||||
ScanLine[x++] = !!(Colour & k);
|
||||
k >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
k = 128;
|
||||
for (j = 0; j < 8; j++) {
|
||||
ScanLine[x++] = !!(HeadByte & k);
|
||||
k >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < Image->Width; x++) { // 'Cleverly' ignores the pad bytes. ;)
|
||||
Image->Data[y * Image->Width + x] += ScanLine[x] << c;
|
||||
}
|
||||
}
|
||||
}
|
||||
ifree(ScanLine);
|
||||
}
|
||||
|
||||
return Image;
|
||||
|
||||
file_read_error:
|
||||
ifree(ScanLine);
|
||||
ilCloseImage(Image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif//IL_NO_DCX
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,606 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 02/14/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_dicom.c
|
||||
//
|
||||
// Description: Reads from a Digital Imaging and Communications in Medicine
|
||||
// (DICOM) file. Specifications can be found at
|
||||
// http://en.wikipedia.org/wiki/Dicom.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_DICOM
|
||||
|
||||
typedef struct DICOMHEAD
|
||||
{
|
||||
ILubyte Signature[4];
|
||||
ILuint Version;
|
||||
ILuint Width;
|
||||
ILuint Height;
|
||||
ILuint Depth;
|
||||
ILuint Samples;
|
||||
ILuint BitsAllocated;
|
||||
ILuint BitsStored;
|
||||
ILuint DataLen;
|
||||
ILboolean BigEndian;
|
||||
ILenum Encoding;
|
||||
|
||||
// For DevIL use only
|
||||
ILenum Format;
|
||||
ILenum Type;
|
||||
} DICOMHEAD;
|
||||
|
||||
ILboolean iIsValidDicom(void);
|
||||
ILboolean iCheckDicom(DICOMHEAD *Header);
|
||||
ILboolean iLoadDicomInternal(void);
|
||||
ILboolean iGetDicomHead(DICOMHEAD *Header);
|
||||
ILboolean SkipElement(DICOMHEAD *Header, ILushort GroupNum, ILushort ElementNum);
|
||||
ILboolean GetNumericValue(DICOMHEAD *Header, ILushort GroupNum, ILuint *Number);
|
||||
ILboolean GetUID(ILubyte *UID);
|
||||
ILuint GetGroupNum(DICOMHEAD *Header);
|
||||
ILuint GetShort(DICOMHEAD *Header, ILushort GroupNum);
|
||||
ILuint GetInt(DICOMHEAD *Header, ILushort GroupNum);
|
||||
ILfloat GetFloat(DICOMHEAD *Header, ILushort GroupNum);
|
||||
|
||||
//! Checks if the file specified in FileName is a valid DICOM file.
|
||||
ILboolean ilIsValidDicom(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE DicomFile;
|
||||
ILboolean bDicom = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("dicom")) && !iCheckExtension(FileName, IL_TEXT("dcm"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bDicom;
|
||||
}
|
||||
|
||||
DicomFile = iopenr(FileName);
|
||||
if (DicomFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bDicom;
|
||||
}
|
||||
|
||||
bDicom = ilIsValidDicomF(DicomFile);
|
||||
icloser(DicomFile);
|
||||
|
||||
return bDicom;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid DICOM file at the current position.
|
||||
ILboolean ilIsValidDicomF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidDicom();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid DICOM lump.
|
||||
ILboolean ilIsValidDicomL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidDicom();
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidDicom(void)
|
||||
{
|
||||
DICOMHEAD Header;
|
||||
ILuint Pos = itell();
|
||||
|
||||
// Clear the header to all 0s to make checks later easier.
|
||||
memset(&Header, 0, sizeof(DICOMHEAD));
|
||||
if (!iGetDicomHead(&Header))
|
||||
return IL_FALSE;
|
||||
// The length of the header varies, so we just go back to the original position.
|
||||
iseek(Pos, IL_SEEK_CUR);
|
||||
|
||||
return iCheckDicom(&Header);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the DICOM header from the current file.
|
||||
ILboolean iGetDicomHead(DICOMHEAD *Header)
|
||||
{
|
||||
ILushort GroupNum, ElementNum;
|
||||
ILboolean ReachedData = IL_FALSE;
|
||||
ILubyte Var2, UID[65];
|
||||
|
||||
// Signature should be "DICM" at position 128.
|
||||
iseek(128, IL_SEEK_SET);
|
||||
if (iread(Header->Signature, 1, 4) != 4)
|
||||
return IL_FALSE;
|
||||
|
||||
//@TODO: What about the case when we are reading an image with Big Endian data?
|
||||
|
||||
do {
|
||||
GroupNum = GetGroupNum(Header);
|
||||
ElementNum = GetShort(Header, GroupNum);;
|
||||
|
||||
switch (GroupNum)
|
||||
{
|
||||
case 0x02:
|
||||
switch (ElementNum)
|
||||
{
|
||||
/*case 0x01: // Version number
|
||||
if (!GetNumericValue(&Header->Version))
|
||||
return IL_FALSE;
|
||||
if (Header->Version != 0x0100)
|
||||
return IL_FALSE;
|
||||
break;*/
|
||||
|
||||
case 0x10:
|
||||
//@TODO: Look at pg. 60 of 07_05pu.pdf (PS 3.5) for more UIDs.
|
||||
if (!GetUID(UID))
|
||||
return IL_FALSE;
|
||||
if (!strncmp(UID, "1.2.840.10008.1.2.2", 64)) // Explicit big endian
|
||||
Header->BigEndian = IL_TRUE;
|
||||
else if (!strncmp(UID, "1.2.840.10008.1.2.1", 64)) // Explicit little endian
|
||||
Header->BigEndian = IL_FALSE;
|
||||
else if (!strncmp(UID, "1.2.840.10008.1.2", 64)) // Implicit little endian
|
||||
Header->BigEndian = IL_FALSE;
|
||||
else
|
||||
return IL_FALSE; // Unrecognized UID.
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!SkipElement(Header, GroupNum, ElementNum)) // We do not understand this entry, so we just skip it.
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x28:
|
||||
switch (ElementNum)
|
||||
{
|
||||
case 0x02: // Samples per pixel
|
||||
if (!GetNumericValue(Header, GroupNum, &Header->Samples))
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case 0x08: // Number of frames, or depth
|
||||
if (!GetNumericValue(Header, GroupNum, &Header->Depth))
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case 0x10: // The number of rows
|
||||
if (!GetNumericValue(Header, GroupNum, &Header->Height))
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case 0x11: // The number of columns
|
||||
if (!GetNumericValue(Header, GroupNum, &Header->Width))
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case 0x100: // Bits allocated per sample
|
||||
if (!GetNumericValue(Header, GroupNum, &Header->BitsAllocated))
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case 0x101: // Bits stored per sample - Do we really need this information?
|
||||
if (!GetNumericValue(Header, GroupNum, &Header->BitsStored))
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!SkipElement(Header, GroupNum, ElementNum)) // We do not understand this entry, so we just skip it.
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7FE0:
|
||||
switch (ElementNum)
|
||||
{
|
||||
case 0x10: // This element is the actual pixel data. We are done with the header here.
|
||||
if (igetc() != 'O') // @TODO: Can we assume that this is always 'O'?
|
||||
return IL_FALSE;
|
||||
Var2 = igetc();
|
||||
if (Var2 != 'B' && Var2 != 'W' && Var2 != 'F') // 'OB', 'OW' and 'OF' accepted for this element.
|
||||
return IL_FALSE;
|
||||
GetLittleUShort(); // Skip the 2 reserved bytes.
|
||||
Header->DataLen = GetInt(Header, GroupNum);//GetLittleUInt();
|
||||
ReachedData = IL_TRUE;
|
||||
break;
|
||||
default:
|
||||
if (!SkipElement(Header, GroupNum, ElementNum)) // We do not understand this entry, so we just skip it.
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!SkipElement(Header, GroupNum, ElementNum)) // We do not understand this entry, so we just skip it.
|
||||
return IL_FALSE;
|
||||
}
|
||||
} while (!ieof() && !ReachedData);
|
||||
|
||||
if (ieof())
|
||||
return IL_FALSE;
|
||||
|
||||
// Some DICOM images do not have the depth (number of frames) field.
|
||||
if (Header->Depth == 0)
|
||||
Header->Depth = 1;
|
||||
|
||||
switch (Header->BitsAllocated)
|
||||
{
|
||||
case 8:
|
||||
Header->Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case 16:
|
||||
Header->Type = IL_UNSIGNED_SHORT;
|
||||
break;
|
||||
case 32:
|
||||
Header->Type = IL_FLOAT; //@TODO: Is this ever an integer?
|
||||
break;
|
||||
default: //@TODO: Any other types we can deal with?
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Cannot handle more than 4 channels in an image.
|
||||
if (Header->Samples > 4)
|
||||
return IL_FALSE;
|
||||
Header->Format = ilGetFormatBpp(Header->Samples);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean SkipElement(DICOMHEAD *Header, ILushort GroupNum, ILushort ElementNum)
|
||||
{
|
||||
ILubyte VR1, VR2;
|
||||
ILuint ValLen;
|
||||
|
||||
// 2 byte character string telling what type this element is ('OB', 'UI', etc.)
|
||||
VR1 = igetc();
|
||||
VR2 = igetc();
|
||||
|
||||
if ((VR1 == 'O' && VR2 == 'B') || (VR1 == 'O' && VR2 == 'W') || (VR1 == 'O' && VR2 == 'F') ||
|
||||
(VR1 == 'S' && VR2 == 'Q') || (VR1 == 'U' && VR2 == 'T') || (VR1 == 'U' && VR2 == 'N')) {
|
||||
// These all have a different format than the other formats, since they can be up to 32 bits long.
|
||||
GetLittleUShort(); // Values reserved, we do not care about them.
|
||||
ValLen = GetInt(Header, GroupNum);//GetLittleUInt(); // Length of the rest of the element
|
||||
if (ValLen % 2) // This length must be even, according to the specs.
|
||||
return IL_FALSE;
|
||||
if (ElementNum != 0x00) // Element numbers of 0 tell the size of the full group, so we do not skip this.
|
||||
// @TODO: We could use this to skip groups that we do not care about.
|
||||
if (iseek(ValLen, IL_SEEK_CUR))
|
||||
return IL_FALSE;
|
||||
}
|
||||
else {
|
||||
// These have a length of 16 bits.
|
||||
ValLen = GetShort(Header, GroupNum);//GetLittleUShort();
|
||||
//if (ValLen % 2) // This length must be even, according to the specs.
|
||||
// ValLen++; // Add the extra byte to seek.
|
||||
//if (ElementNum != 0x00) // Element numbers of 0 tell the size of the full group, so we do not skip this.
|
||||
// @TODO: We could use this to skip groups that we do not care about.
|
||||
if (iseek(ValLen, IL_SEEK_CUR))
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILuint GetGroupNum(DICOMHEAD *Header)
|
||||
{
|
||||
ILushort GroupNum;
|
||||
|
||||
iread(&GroupNum, 1, 2);
|
||||
// The 0x02 group is always little endian.
|
||||
if (GroupNum == 0x02) {
|
||||
UShort(&GroupNum);
|
||||
return GroupNum;
|
||||
}
|
||||
// Now we have to swizzle it if it is not 0x02.
|
||||
if (Header->BigEndian)
|
||||
BigUShort(&GroupNum);
|
||||
else
|
||||
UShort(&GroupNum);
|
||||
|
||||
return GroupNum;
|
||||
}
|
||||
|
||||
|
||||
ILuint GetShort(DICOMHEAD *Header, ILushort GroupNum)
|
||||
{
|
||||
ILushort Num;
|
||||
|
||||
iread(&Num, 1, 2);
|
||||
// The 0x02 group is always little endian.
|
||||
if (GroupNum == 0x02) {
|
||||
UShort(&Num);
|
||||
return Num;
|
||||
}
|
||||
// Now we have to swizzle it if it is not 0x02.
|
||||
if (Header->BigEndian)
|
||||
BigUShort(&Num);
|
||||
else
|
||||
UShort(&Num);
|
||||
|
||||
return Num;
|
||||
}
|
||||
|
||||
|
||||
ILuint GetInt(DICOMHEAD *Header, ILushort GroupNum)
|
||||
{
|
||||
ILuint Num;
|
||||
|
||||
iread(&Num, 1, 4);
|
||||
// The 0x02 group is always little endian.
|
||||
if (GroupNum == 0x02) {
|
||||
UInt(&Num);
|
||||
return Num;
|
||||
}
|
||||
// Now we have to swizzle it if it is not 0x02.
|
||||
if (Header->BigEndian)
|
||||
BigUInt(&Num);
|
||||
else
|
||||
UInt(&Num);
|
||||
|
||||
return Num;
|
||||
}
|
||||
|
||||
|
||||
ILfloat GetFloat(DICOMHEAD *Header, ILushort GroupNum)
|
||||
{
|
||||
ILfloat Num;
|
||||
|
||||
iread(&Num, 1, 4);
|
||||
// The 0x02 group is always little endian.
|
||||
if (GroupNum == 0x02) {
|
||||
Float(&Num);
|
||||
return Num;
|
||||
}
|
||||
// Now we have to swizzle it if it is not 0x02.
|
||||
if (Header->BigEndian)
|
||||
BigFloat(&Num);
|
||||
else
|
||||
Float(&Num);
|
||||
|
||||
return Num;
|
||||
}
|
||||
|
||||
|
||||
ILboolean GetNumericValue(DICOMHEAD *Header, ILushort GroupNum, ILuint *Number)
|
||||
{
|
||||
ILubyte VR1, VR2;
|
||||
ILushort ValLen;
|
||||
|
||||
// 2 byte character string telling what type this element is ('OB', 'UI', etc.)
|
||||
VR1 = igetc();
|
||||
VR2 = igetc();
|
||||
|
||||
if (VR1 == 'U' && VR2 == 'S') { // Unsigned short
|
||||
ValLen = GetShort(Header, GroupNum);//GetLittleUShort();
|
||||
if (ValLen != 2) // Must always be 2 for short ('US')
|
||||
return IL_FALSE;
|
||||
*((ILushort*)Number) = GetShort(Header, GroupNum);//GetLittleUShort();
|
||||
return IL_TRUE;
|
||||
}
|
||||
if (VR1 == 'U' && VR2 == 'L') { // Unsigned long
|
||||
ValLen = GetInt(Header, GroupNum);//GetLittleUInt();
|
||||
if (ValLen != 4) // Must always be 4 for long ('UL')
|
||||
return IL_FALSE;
|
||||
*Number = GetInt(Header, GroupNum);
|
||||
return IL_TRUE;
|
||||
}
|
||||
if (VR1 == 'S' && VR2 == 'S') { // Signed short
|
||||
ValLen = GetShort(Header, GroupNum);
|
||||
if (ValLen != 2) // Must always be 2 for short ('US')
|
||||
return IL_FALSE;
|
||||
*((ILshort*)Number) = GetShort(Header, GroupNum);
|
||||
return IL_TRUE;
|
||||
}
|
||||
if (VR1 == 'S' && VR2 == 'L') { // Signed long
|
||||
ValLen = GetInt(Header, GroupNum);
|
||||
if (ValLen != 4) // Must always be 4 for long ('UL')
|
||||
return IL_FALSE;
|
||||
*((ILint*)Number) = GetInt(Header, GroupNum);
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean GetUID(ILubyte *UID)
|
||||
{
|
||||
ILubyte VR1, VR2;
|
||||
ILushort ValLen;
|
||||
|
||||
// 2 byte character string telling what type this element is ('OB', 'UI', etc.)
|
||||
VR1 = igetc();
|
||||
VR2 = igetc();
|
||||
|
||||
if (VR1 != 'U' || VR2 != 'I') // 'UI' == UID
|
||||
return IL_FALSE;
|
||||
|
||||
ValLen = GetLittleUShort();
|
||||
if (iread(UID, ValLen, 1) != 1)
|
||||
return IL_FALSE;
|
||||
UID[64] = 0; // Just to make sure that our string is terminated.
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
// Internal function used to check if the HEADER is a valid DICOM header.
|
||||
ILboolean iCheckDicom(DICOMHEAD *Header)
|
||||
{
|
||||
// Always has the signature "DICM" at position 0x80.
|
||||
if (strncmp(Header->Signature, "DICM", 4))
|
||||
return IL_FALSE;
|
||||
// Does not make sense to have any dimension = 0.
|
||||
if (Header->Width == 0 || Header->Height == 0 || Header->Depth == 0)
|
||||
return IL_FALSE;
|
||||
// We can only deal with images that have byte-aligned data.
|
||||
//@TODO: Take care of any others?
|
||||
if (Header->BitsAllocated % 8)
|
||||
return IL_FALSE;
|
||||
// Check for an invalid format being set (or not set at all).
|
||||
if (ilGetBppFormat(Header->Format) == 0)
|
||||
return IL_FALSE;
|
||||
// Check for an invalid type being set (or not set at all).
|
||||
if (ilGetBpcType(Header->Type) == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a DICOM file
|
||||
ILboolean ilLoadDicom(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE DicomFile;
|
||||
ILboolean bDicom = IL_FALSE;
|
||||
|
||||
DicomFile = iopenr(FileName);
|
||||
if (DicomFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bDicom;
|
||||
}
|
||||
|
||||
bDicom = ilLoadDicomF(DicomFile);
|
||||
icloser(DicomFile);
|
||||
|
||||
return bDicom;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened DICOM file
|
||||
ILboolean ilLoadDicomF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadDicomInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a DICOM
|
||||
ILboolean ilLoadDicomL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadDicomInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the DICOM.
|
||||
ILboolean iLoadDicomInternal(void)
|
||||
{
|
||||
DICOMHEAD Header;
|
||||
ILuint i;
|
||||
ILushort TempS, *ShortPtr;
|
||||
ILfloat TempF, *FloatPtr;
|
||||
ILboolean Swizzle = IL_FALSE;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Clear the header to all 0s to make checks later easier.
|
||||
memset(&Header, 0, sizeof(DICOMHEAD));
|
||||
if (!iGetDicomHead(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (!iCheckDicom(&Header))
|
||||
return IL_FALSE;
|
||||
|
||||
if (!ilTexImage(Header.Width, Header.Height, Header.Depth, ilGetBppFormat(Header.Format), Header.Format, Header.Type, NULL))
|
||||
return IL_FALSE;
|
||||
//@TODO: Find out if the origin is always in the upper left.
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
// Header.DataLen may be larger than SizeOfData, since it has to be padded with a NULL if it is not an even length,
|
||||
// so we just test to make sure it is at least large enough.
|
||||
//@TODO: Do this check before ilTexImage call.
|
||||
if (Header.DataLen < iCurImage->SizeOfData) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// We may have to swap the order of the data.
|
||||
#ifdef __BIG_ENDIAN__
|
||||
if (!Header.BigEndian) {
|
||||
if (Header.Format == IL_RGB)
|
||||
Header.Format = IL_BGR;
|
||||
else if (Header.Format == IL_RGBA)
|
||||
Swizzle = IL_TRUE;
|
||||
}
|
||||
#else // Little endian
|
||||
if (Header.BigEndian) {
|
||||
if (Header.Format == IL_RGB)
|
||||
Header.Format = IL_BGR;
|
||||
if (Header.Format == IL_RGBA)
|
||||
Swizzle = IL_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (Header.Type)
|
||||
{
|
||||
case IL_UNSIGNED_BYTE:
|
||||
if (iread(iCurImage->Data, iCurImage->SizeOfData, 1) != 1)
|
||||
return IL_FALSE;
|
||||
|
||||
// Swizzle the data from ABGR to RGBA.
|
||||
if (Swizzle) {
|
||||
for (i = 0; i < iCurImage->SizeOfData; i += 4) {
|
||||
iSwapUInt((ILuint*)(iCurImage->Data + i));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IL_UNSIGNED_SHORT:
|
||||
for (i = 0; i < iCurImage->SizeOfData; i += 2) {
|
||||
*((ILushort*)(iCurImage->Data + i)) = GetShort(&Header, 0);//GetLittleUShort();
|
||||
}
|
||||
|
||||
// Swizzle the data from ABGR to RGBA.
|
||||
if (Swizzle) {
|
||||
ShortPtr = (ILushort*)iCurImage->Data;
|
||||
for (i = 0; i < iCurImage->SizeOfData / 2; i += 4) {
|
||||
TempS = ShortPtr[i];
|
||||
ShortPtr[i] = ShortPtr[i+3];
|
||||
ShortPtr[i+3] = TempS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IL_FLOAT:
|
||||
for (i = 0; i < iCurImage->SizeOfData; i += 4) {
|
||||
*((ILfloat*)(iCurImage->Data + i)) = GetFloat(&Header, 0);//GetLittleFloat();
|
||||
}
|
||||
|
||||
// Swizzle the data from ABGR to RGBA.
|
||||
if (Swizzle) {
|
||||
FloatPtr = (ILfloat*)iCurImage->Data;
|
||||
for (i = 0; i < iCurImage->SizeOfData / 4; i += 4) {
|
||||
TempF = FloatPtr[i];
|
||||
FloatPtr[i] = FloatPtr[i+3];
|
||||
FloatPtr[i+3] = TempF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif//IL_NO_DICOM
|
||||
@@ -0,0 +1,272 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_doom.c
|
||||
//
|
||||
// Description: Reads Doom textures and flats
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_DOOM
|
||||
#include "il_manip.h"
|
||||
#include "il_pal.h"
|
||||
#include "il_doompal.h"
|
||||
|
||||
|
||||
ILboolean iLoadDoomInternal(void);
|
||||
ILboolean iLoadDoomFlatInternal(void);
|
||||
|
||||
|
||||
//
|
||||
// READ A DOOM IMAGE
|
||||
//
|
||||
|
||||
//! Reads a Doom file
|
||||
ILboolean ilLoadDoom(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE DoomFile;
|
||||
ILboolean bDoom = IL_FALSE;
|
||||
|
||||
// Not sure of any kind of specified extension...maybe .lmp?
|
||||
/*if (!iCheckExtension(FileName, "")) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return NULL;
|
||||
}*/
|
||||
|
||||
DoomFile = iopenr(FileName);
|
||||
if (DoomFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bDoom;
|
||||
}
|
||||
|
||||
bDoom = ilLoadDoomF(DoomFile);
|
||||
icloser(DoomFile);
|
||||
|
||||
return bDoom;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened Doom file
|
||||
ILboolean ilLoadDoomF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadDoomInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a Doom texture
|
||||
ILboolean ilLoadDoomL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadDoomInternal();
|
||||
}
|
||||
|
||||
|
||||
// From the DTE sources (mostly by Denton Woods with corrections by Randy Heit)
|
||||
ILboolean iLoadDoomInternal()
|
||||
{
|
||||
ILshort width, height, graphic_header[2], column_loop, row_loop;
|
||||
ILint column_offset, pointer_position, first_pos;
|
||||
ILubyte post, topdelta, length;
|
||||
ILubyte *NewData;
|
||||
ILuint i;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
first_pos = itell(); // Needed to go back to the offset table
|
||||
width = GetLittleShort();
|
||||
height = GetLittleShort();
|
||||
graphic_header[0] = GetLittleShort(); // Not even used
|
||||
graphic_header[1] = GetLittleShort(); // Not even used
|
||||
|
||||
if (!ilTexImage(width, height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
iCurImage->Pal.Palette = (ILubyte*)ialloc(IL_DOOMPAL_SIZE);
|
||||
if (iCurImage->Pal.Palette == NULL) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Pal.PalSize = IL_DOOMPAL_SIZE;
|
||||
iCurImage->Pal.PalType = IL_PAL_RGB24;
|
||||
memcpy(iCurImage->Pal.Palette, ilDefaultDoomPal, IL_DOOMPAL_SIZE);
|
||||
|
||||
// 247 is always the transparent colour (usually cyan)
|
||||
memset(iCurImage->Data, 247, iCurImage->SizeOfData);
|
||||
|
||||
for (column_loop = 0; column_loop < width; column_loop++) {
|
||||
column_offset = GetLittleInt();
|
||||
pointer_position = itell();
|
||||
iseek(first_pos + column_offset, IL_SEEK_SET);
|
||||
|
||||
while (1) {
|
||||
if (iread(&topdelta, 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
if (topdelta == 255)
|
||||
break;
|
||||
if (iread(&length, 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
if (iread(&post, 1, 1) != 1)
|
||||
return IL_FALSE; // Skip extra byte for scaling
|
||||
|
||||
for (row_loop = 0; row_loop < length; row_loop++) {
|
||||
if (iread(&post, 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
if (row_loop + topdelta < height)
|
||||
iCurImage->Data[(row_loop+topdelta) * width + column_loop] = post;
|
||||
}
|
||||
iread(&post, 1, 1); // Skip extra scaling byte
|
||||
}
|
||||
|
||||
iseek(pointer_position, IL_SEEK_SET);
|
||||
}
|
||||
|
||||
// Converts palette entry 247 (cyan) to transparent.
|
||||
if (ilGetBoolean(IL_CONV_PAL) == IL_TRUE) {
|
||||
NewData = (ILubyte*)ialloc(iCurImage->SizeOfData * 4);
|
||||
if (NewData == NULL) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < iCurImage->SizeOfData; i++) {
|
||||
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
|
||||
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
|
||||
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
|
||||
NewData[i * 4 + 3] = iCurImage->Data[i] != 247 ? 255 : 0;
|
||||
}
|
||||
|
||||
if (!ilTexImage(iCurImage->Width, iCurImage->Height, iCurImage->Depth,
|
||||
4, IL_RGBA, iCurImage->Type, NewData)) {
|
||||
ifree(NewData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
ifree(NewData);
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// READ A DOOM FLAT
|
||||
//
|
||||
|
||||
//! Reads a Doom flat file
|
||||
ILboolean ilLoadDoomFlat(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE FlatFile;
|
||||
ILboolean bFlat = IL_FALSE;
|
||||
|
||||
// Not sure of any kind of specified extension...maybe .lmp?
|
||||
/*if (!iCheckExtension(FileName, "")) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return NULL;
|
||||
}*/
|
||||
|
||||
FlatFile = iopenr(FileName);
|
||||
if (FlatFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bFlat;
|
||||
}
|
||||
|
||||
bFlat = ilLoadDoomF(FlatFile);
|
||||
icloser(FlatFile);
|
||||
|
||||
return bFlat;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened Doom flat file
|
||||
ILboolean ilLoadDoomFlatF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadDoomFlatInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a Doom flat
|
||||
ILboolean ilLoadDoomFlatL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadDoomFlatInternal();
|
||||
}
|
||||
|
||||
|
||||
// Basically just ireads 4096 bytes and copies the palette
|
||||
ILboolean iLoadDoomFlatInternal()
|
||||
{
|
||||
ILubyte *NewData;
|
||||
ILuint i;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!ilTexImage(64, 64, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
iCurImage->Pal.Palette = (ILubyte*)ialloc(IL_DOOMPAL_SIZE);
|
||||
if (iCurImage->Pal.Palette == NULL) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Pal.PalSize = IL_DOOMPAL_SIZE;
|
||||
iCurImage->Pal.PalType = IL_PAL_RGB24;
|
||||
memcpy(iCurImage->Pal.Palette, ilDefaultDoomPal, IL_DOOMPAL_SIZE);
|
||||
|
||||
if (iread(iCurImage->Data, 1, 4096) != 4096)
|
||||
return IL_FALSE;
|
||||
|
||||
if (ilGetBoolean(IL_CONV_PAL) == IL_TRUE) {
|
||||
NewData = (ILubyte*)ialloc(iCurImage->SizeOfData * 4);
|
||||
if (NewData == NULL) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < iCurImage->SizeOfData; i++) {
|
||||
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
|
||||
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
|
||||
NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
|
||||
NewData[i * 4 + 3] = iCurImage->Data[i] != 247 ? 255 : 0;
|
||||
}
|
||||
|
||||
if (!ilTexImage(iCurImage->Width, iCurImage->Height, iCurImage->Depth,
|
||||
4, IL_RGBA, iCurImage->Type, NewData)) {
|
||||
ifree(NewData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
ifree(NewData);
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,325 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 02/26/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_dpx.c
|
||||
//
|
||||
// Description: Reads from a Digital Picture Exchange (.dpx) file.
|
||||
// Specifications for this format were found at
|
||||
// http://www.cineon.com/ff_draft.php and
|
||||
// http://www.fileformat.info/format/dpx/.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_DPX
|
||||
#include "il_dpx.h"
|
||||
#include "il_bits.h"
|
||||
|
||||
ILboolean iLoadDpxInternal(void);
|
||||
|
||||
|
||||
//! Reads a DPX file
|
||||
ILboolean ilLoadDpx(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE DpxFile;
|
||||
ILboolean bDpx = IL_FALSE;
|
||||
|
||||
DpxFile = iopenr(FileName);
|
||||
if (DpxFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bDpx;
|
||||
}
|
||||
|
||||
bDpx = ilLoadDpxF(DpxFile);
|
||||
icloser(DpxFile);
|
||||
|
||||
return bDpx;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened DPX file
|
||||
ILboolean ilLoadDpxF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadDpxInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a DPX
|
||||
ILboolean ilLoadDpxL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadDpxInternal();
|
||||
}
|
||||
|
||||
|
||||
ILboolean DpxGetFileInfo(DPX_FILE_INFO *FileInfo)
|
||||
{
|
||||
//if (iread(FileInfo, 768, 1) != 1)
|
||||
// return IL_FALSE;
|
||||
|
||||
FileInfo->MagicNum = GetBigUInt();
|
||||
FileInfo->Offset = GetBigUInt();
|
||||
iread(FileInfo->Vers, 8, 1);
|
||||
FileInfo->FileSize = GetBigUInt();
|
||||
FileInfo->DittoKey = GetBigUInt();
|
||||
FileInfo->GenHdrSize = GetBigUInt();
|
||||
FileInfo->IndHdrSize = GetBigUInt();
|
||||
FileInfo->UserDataSize = GetBigUInt();
|
||||
iread(FileInfo->FileName, 100, 1);
|
||||
iread(FileInfo->CreateTime, 24, 1);
|
||||
iread(FileInfo->Creator, 100, 1);
|
||||
iread(FileInfo->Project, 200, 1);
|
||||
if (iread(FileInfo->Copyright, 200, 1) != 1)
|
||||
return IL_FALSE;
|
||||
FileInfo->Key = GetBigUInt();
|
||||
iseek(104, IL_SEEK_CUR); // Skip reserved section.
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean GetImageElement(DPX_IMAGE_ELEMENT *ImageElement)
|
||||
{
|
||||
ImageElement->DataSign = GetBigUInt();
|
||||
ImageElement->RefLowData = GetBigUInt();
|
||||
iread(&ImageElement->RefLowQuantity, 1, 4);
|
||||
ImageElement->RefHighData = GetBigUInt();
|
||||
iread(&ImageElement->RefHighQuantity, 1, 4);
|
||||
ImageElement->Descriptor = igetc();
|
||||
ImageElement->Transfer = igetc();
|
||||
ImageElement->Colorimetric = igetc();
|
||||
ImageElement->BitSize = igetc();
|
||||
ImageElement->Packing = GetBigUShort();
|
||||
ImageElement->Encoding = GetBigUShort();
|
||||
ImageElement->DataOffset = GetBigUInt();
|
||||
ImageElement->EolPadding = GetBigUInt();
|
||||
ImageElement->EoImagePadding = GetBigUInt();
|
||||
if (iread(ImageElement->Description, 32, 1) != 1)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean DpxGetImageInfo(DPX_IMAGE_INFO *ImageInfo)
|
||||
{
|
||||
ILuint i;
|
||||
|
||||
//if (iread(ImageInfo, sizeof(DPX_IMAGE_INFO), 1) != 1)
|
||||
// return IL_FALSE;
|
||||
ImageInfo->Orientation = GetBigUShort();
|
||||
ImageInfo->NumElements = GetBigUShort();
|
||||
ImageInfo->Width = GetBigUInt();
|
||||
ImageInfo->Height = GetBigUInt();
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
GetImageElement(&ImageInfo->ImageElement[i]);
|
||||
}
|
||||
|
||||
iseek(52, IL_SEEK_CUR); // Skip padding bytes.
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean DpxGetImageOrient(DPX_IMAGE_ORIENT *ImageOrient)
|
||||
{
|
||||
ImageOrient->XOffset = GetBigUInt();
|
||||
ImageOrient->YOffset = GetBigUInt();
|
||||
iread(&ImageOrient->XCenter, 4, 1);
|
||||
iread(&ImageOrient->YCenter, 4, 1);
|
||||
ImageOrient->XOrigSize = GetBigUInt();
|
||||
ImageOrient->YOrigSize = GetBigUInt();
|
||||
iread(ImageOrient->FileName, 100, 1);
|
||||
iread(ImageOrient->CreationTime, 24, 1);
|
||||
iread(ImageOrient->InputDev, 32, 1);
|
||||
if (iread(ImageOrient->InputSerial, 32, 1) != 1)
|
||||
return IL_FALSE;
|
||||
ImageOrient->Border[0] = GetBigUShort();
|
||||
ImageOrient->Border[1] = GetBigUShort();
|
||||
ImageOrient->Border[2] = GetBigUShort();
|
||||
ImageOrient->Border[3] = GetBigUShort();
|
||||
ImageOrient->PixelAspect[0] = GetBigUInt();
|
||||
ImageOrient->PixelAspect[1] = GetBigUInt();
|
||||
iseek(28, IL_SEEK_CUR); // Skip reserved bytes.
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the DPX.
|
||||
ILboolean iLoadDpxInternal(void)
|
||||
{
|
||||
DPX_FILE_INFO FileInfo;
|
||||
DPX_IMAGE_INFO ImageInfo;
|
||||
DPX_IMAGE_ORIENT ImageOrient;
|
||||
// BITFILE *File;
|
||||
ILuint i, NumElements, CurElem = 0;
|
||||
ILushort Val, *ShortData;
|
||||
ILubyte Data[8];
|
||||
ILenum Format = 0;
|
||||
ILubyte NumChans = 0;
|
||||
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!DpxGetFileInfo(&FileInfo))
|
||||
return IL_FALSE;
|
||||
if (!DpxGetImageInfo(&ImageInfo))
|
||||
return IL_FALSE;
|
||||
if (!DpxGetImageOrient(&ImageOrient))
|
||||
return IL_FALSE;
|
||||
|
||||
iseek(ImageInfo.ImageElement[CurElem].DataOffset, IL_SEEK_SET);
|
||||
|
||||
//@TODO: Deal with different origins!
|
||||
|
||||
switch (ImageInfo.ImageElement[CurElem].Descriptor)
|
||||
{
|
||||
case 6: // Luminance data
|
||||
Format = IL_LUMINANCE;
|
||||
NumChans = 1;
|
||||
break;
|
||||
case 50: // RGB data
|
||||
Format = IL_RGB;
|
||||
NumChans = 3;
|
||||
break;
|
||||
case 51: // RGBA data
|
||||
Format = IL_RGBA;
|
||||
NumChans = 4;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// These are all on nice word boundaries.
|
||||
switch (ImageInfo.ImageElement[CurElem].BitSize)
|
||||
{
|
||||
case 8:
|
||||
case 16:
|
||||
case 32:
|
||||
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, NumChans, Format, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
if (iread(iCurImage->Data, iCurImage->SizeOfData, 1) != 1)
|
||||
return IL_FALSE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// The rest of these do not end on word boundaries.
|
||||
if (ImageInfo.ImageElement[CurElem].Packing == 1) {
|
||||
// Here we have it padded out to a word boundary, so the extra bits are filler.
|
||||
switch (ImageInfo.ImageElement[CurElem].BitSize)
|
||||
{
|
||||
case 10:
|
||||
//@TODO: Support other formats!
|
||||
/*if (Format != IL_RGB) {
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}*/
|
||||
switch (Format)
|
||||
{
|
||||
case IL_LUMINANCE:
|
||||
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_SHORT, NULL))
|
||||
return IL_FALSE;
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
ShortData = (ILushort*)iCurImage->Data;
|
||||
NumElements = iCurImage->SizeOfData / 2;
|
||||
|
||||
for (i = 0; i < NumElements;) {
|
||||
iread(Data, 1, 2);
|
||||
Val = ((Data[0] << 2) + ((Data[1] & 0xC0) >> 6)) << 6; // Use the first 10 bits of the word-aligned data.
|
||||
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits.
|
||||
}
|
||||
break;
|
||||
|
||||
case IL_RGB:
|
||||
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 3, IL_RGB, IL_UNSIGNED_SHORT, NULL))
|
||||
return IL_FALSE;
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
ShortData = (ILushort*)iCurImage->Data;
|
||||
NumElements = iCurImage->SizeOfData / 2;
|
||||
|
||||
for (i = 0; i < NumElements;) {
|
||||
iread(Data, 1, 4);
|
||||
Val = ((Data[0] << 2) + ((Data[1] & 0xC0) >> 6)) << 6; // Use the first 10 bits of the word-aligned data.
|
||||
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits.
|
||||
Val = (((Data[1] & 0x3F) << 4) + ((Data[2] & 0xF0) >> 4)) << 6; // Use the next 10 bits.
|
||||
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Same fill
|
||||
Val = (((Data[2] & 0x0F) << 6) + ((Data[3] & 0xFC) >> 2)) << 6; // And finally use the last 10 bits (ignores the last 2 bits).
|
||||
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Same fill
|
||||
}
|
||||
break;
|
||||
|
||||
case IL_RGBA: // Is this even a possibility? There is a ton of wasted space here!
|
||||
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 4, IL_RGBA, IL_UNSIGNED_SHORT, NULL))
|
||||
return IL_FALSE;
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
ShortData = (ILushort*)iCurImage->Data;
|
||||
NumElements = iCurImage->SizeOfData / 2;
|
||||
|
||||
for (i = 0; i < NumElements;) {
|
||||
iread(Data, 1, 8);
|
||||
Val = (Data[0] << 2) + ((Data[1] & 0xC0) >> 6); // Use the first 10 bits of the word-aligned data.
|
||||
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits.
|
||||
Val = ((Data[1] & 0x3F) << 4) + ((Data[2] & 0xF0) >> 4); // Use the next 10 bits.
|
||||
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Same fill
|
||||
Val = ((Data[2] & 0x0F) << 6) + ((Data[3] & 0xFC) >> 2); // Use the next 10 bits.
|
||||
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Same fill
|
||||
Val = ((Data[3] & 0x03) << 8) + Data[4]; // And finally use the last 10 relevant bits (skips 3 whole bytes worth of padding!).
|
||||
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Last fill
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
//case 1:
|
||||
//case 12:
|
||||
default:
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
else if (ImageInfo.ImageElement[0].Packing == 0) {
|
||||
// Here we have the data packed so that it is never aligned on a word boundary.
|
||||
/*File = bfile(iGetFile());
|
||||
if (File == NULL)
|
||||
return IL_FALSE; //@TODO: Error?
|
||||
ShortData = (ILushort*)iCurImage->Data;
|
||||
NumElements = iCurImage->SizeOfData / 2;
|
||||
for (i = 0; i < NumElements; i++) {
|
||||
//bread(&Val, 1, 10, File);
|
||||
Val = breadVal(10, File);
|
||||
ShortData[i] = (Val << 6) | (Val >> 4);
|
||||
}
|
||||
bclose(File);*/
|
||||
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}
|
||||
else {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE; //@TODO: Take care of this in an iCheckDpx* function.
|
||||
}
|
||||
|
||||
finish:
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
#endif//IL_NO_DPX
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Last modified: 12/06/2006
|
||||
//
|
||||
// Filename: src-IL/src/il_endian.c
|
||||
//
|
||||
// Description: Takes care of endian issues
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#define IL_ENDIAN_C
|
||||
|
||||
#include "il_endian.h"
|
||||
|
||||
void EndianSwapData(void *_Image)
|
||||
{
|
||||
ILuint i;
|
||||
ILubyte *temp, *s, *d;
|
||||
ILushort *ShortS, *ShortD;
|
||||
ILuint *IntS, *IntD;
|
||||
ILfloat *FltS, *FltD;
|
||||
ILdouble *DblS, *DblD;
|
||||
|
||||
ILimage *Image = (ILimage*)_Image;
|
||||
|
||||
switch (Image->Type) {
|
||||
case IL_BYTE:
|
||||
case IL_UNSIGNED_BYTE:
|
||||
switch (Image->Bpp) {
|
||||
case 3:
|
||||
temp = (ILubyte*)ialloc(Image->SizeOfData);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
s = Image->Data;
|
||||
d = temp;
|
||||
|
||||
for( i = Image->Width * Image->Height; i > 0; i-- ) {
|
||||
*d++ = *(s+2);
|
||||
*d++ = *(s+1);
|
||||
*d++ = *s;
|
||||
s += 3;
|
||||
}
|
||||
|
||||
ifree(Image->Data);
|
||||
Image->Data = temp;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
temp = (ILubyte*)ialloc(Image->SizeOfData);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
s = Image->Data;
|
||||
d = temp;
|
||||
|
||||
for (i = Image->Width * Image->Height; i > 0; i--) {
|
||||
*d++ = *(s+3);
|
||||
*d++ = *(s+2);
|
||||
*d++ = *(s+1);
|
||||
*d++ = *s;
|
||||
s += 4;
|
||||
}
|
||||
|
||||
ifree(Image->Data);
|
||||
Image->Data = temp;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IL_SHORT:
|
||||
case IL_UNSIGNED_SHORT:
|
||||
switch (Image->Bpp) {
|
||||
case 3:
|
||||
temp = (ILubyte*)ialloc(Image->SizeOfData);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
ShortS = (ILushort*)Image->Data;
|
||||
ShortD = (ILushort*)temp;
|
||||
|
||||
for (i = Image->Width * Image->Height; i > 0; i--) {
|
||||
*ShortD = *ShortS++; iSwapUShort(ShortD++);
|
||||
*ShortD = *ShortS++; iSwapUShort(ShortD++);
|
||||
*ShortD = *ShortS++; iSwapUShort(ShortD++);
|
||||
}
|
||||
|
||||
ifree(Image->Data);
|
||||
Image->Data = temp;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
temp = (ILubyte*)ialloc(Image->SizeOfData);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
ShortS = (ILushort*)Image->Data;
|
||||
ShortD = (ILushort*)temp;
|
||||
|
||||
for (i = Image->Width * Image->Height; i > 0; i--) {
|
||||
*ShortD = *ShortS++; iSwapUShort(ShortD++);
|
||||
*ShortD = *ShortS++; iSwapUShort(ShortD++);
|
||||
*ShortD = *ShortS++; iSwapUShort(ShortD++);
|
||||
*ShortD = *ShortS++; iSwapUShort(ShortD++);
|
||||
}
|
||||
|
||||
ifree(Image->Data);
|
||||
Image->Data = temp;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IL_INT:
|
||||
case IL_UNSIGNED_INT:
|
||||
switch (Image->Bpp)
|
||||
{
|
||||
case 3:
|
||||
temp = (ILubyte*)ialloc(Image->SizeOfData);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
IntS = (ILuint*)Image->Data;
|
||||
IntD = (ILuint*)temp;
|
||||
|
||||
for (i = Image->Width * Image->Height; i > 0; i--) {
|
||||
*IntD = *IntS++; iSwapUInt(IntD++);
|
||||
*IntD = *IntS++; iSwapUInt(IntD++);
|
||||
*IntD = *IntS++; iSwapUInt(IntD++);
|
||||
}
|
||||
|
||||
ifree(Image->Data);
|
||||
Image->Data = temp;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
temp = (ILubyte*)ialloc(Image->SizeOfData);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
IntS = (ILuint*)Image->Data;
|
||||
IntD = (ILuint*)temp;
|
||||
|
||||
for (i = Image->Width * Image->Height; i > 0; i--) {
|
||||
*IntD = *IntS++; iSwapUInt(IntD++);
|
||||
*IntD = *IntS++; iSwapUInt(IntD++);
|
||||
*IntD = *IntS++; iSwapUInt(IntD++);
|
||||
*IntD = *IntS++; iSwapUInt(IntD++);
|
||||
}
|
||||
|
||||
ifree(Image->Data);
|
||||
Image->Data = temp;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IL_FLOAT:
|
||||
switch (Image->Bpp)
|
||||
{
|
||||
case 3:
|
||||
temp = (ILubyte*)ialloc(Image->SizeOfData);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
FltS = (ILfloat*)Image->Data;
|
||||
FltD = (ILfloat*)temp;
|
||||
|
||||
for (i = Image->Width * Image->Height; i > 0; i--) {
|
||||
*FltD = *FltS++; iSwapFloat(FltD++);
|
||||
*FltD = *FltS++; iSwapFloat(FltD++);
|
||||
*FltD = *FltS++; iSwapFloat(FltD++);
|
||||
}
|
||||
|
||||
ifree(Image->Data);
|
||||
Image->Data = temp;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
temp = (ILubyte*)ialloc(Image->SizeOfData);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
FltS = (ILfloat*)Image->Data;
|
||||
FltD = (ILfloat*)temp;
|
||||
|
||||
for (i = Image->Width * Image->Height; i > 0; i--) {
|
||||
*FltD = *FltS++; iSwapFloat(FltD++);
|
||||
*FltD = *FltS++; iSwapFloat(FltD++);
|
||||
*FltD = *FltS++; iSwapFloat(FltD++);
|
||||
*FltD = *FltS++; iSwapFloat(FltD++);
|
||||
}
|
||||
|
||||
ifree(Image->Data);
|
||||
Image->Data = temp;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IL_DOUBLE:
|
||||
switch (Image->Bpp)
|
||||
{
|
||||
case 3:
|
||||
temp = (ILubyte*)ialloc(Image->SizeOfData);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
DblS = (ILdouble*)Image->Data;
|
||||
DblD = (ILdouble*)temp;
|
||||
|
||||
for (i = Image->Width * Image->Height; i > 0; i--) {
|
||||
*DblD = *DblS++; iSwapDouble(DblD++);
|
||||
*DblD = *DblS++; iSwapDouble(DblD++);
|
||||
*DblD = *DblS++; iSwapDouble(DblD++);
|
||||
}
|
||||
|
||||
ifree(Image->Data);
|
||||
Image->Data = temp;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
temp = (ILubyte*)ialloc(Image->SizeOfData);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
DblS = (ILdouble*)Image->Data;
|
||||
DblD = (ILdouble*)temp;
|
||||
|
||||
for (i = Image->Width * Image->Height; i > 0; i--) {
|
||||
*DblD = *DblS++; iSwapDouble(DblD++);
|
||||
*DblD = *DblS++; iSwapDouble(DblD++);
|
||||
*DblD = *DblS++; iSwapDouble(DblD++);
|
||||
*DblD = *DblS++; iSwapDouble(DblD++);
|
||||
}
|
||||
|
||||
ifree(Image->Data);
|
||||
Image->Data = temp;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if( iCurImage->Format == IL_COLOUR_INDEX ) {
|
||||
switch (iCurImage->Pal.PalType) {
|
||||
case IL_PAL_RGB24:
|
||||
case IL_PAL_BGR24:
|
||||
temp = (ILubyte*)ialloc(Image->Pal.PalSize);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
s = Image->Pal.Palette;
|
||||
d = temp;
|
||||
|
||||
for (i = Image->Pal.PalSize / 3; i > 0; i--) {
|
||||
*d++ = *(s+2);
|
||||
*d++ = *(s+1);
|
||||
*d++ = *s;
|
||||
s += 3;
|
||||
}
|
||||
|
||||
ifree(Image->Pal.Palette);
|
||||
Image->Pal.Palette = temp;
|
||||
break;
|
||||
|
||||
case IL_PAL_RGBA32:
|
||||
case IL_PAL_RGB32:
|
||||
case IL_PAL_BGRA32:
|
||||
case IL_PAL_BGR32:
|
||||
temp = (ILubyte*)ialloc(Image->Pal.PalSize);
|
||||
if (temp == NULL)
|
||||
return;
|
||||
s = Image->Pal.Palette;
|
||||
d = temp;
|
||||
|
||||
for (i = Image->Pal.PalSize / 4; i > 0; i--) {
|
||||
*d++ = *(s+3);
|
||||
*d++ = *(s+2);
|
||||
*d++ = *(s+1);
|
||||
*d++ = *s;
|
||||
s += 4;
|
||||
}
|
||||
|
||||
ifree(Image->Pal.Palette);
|
||||
Image->Pal.Palette = temp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2008 by Denton Woods
|
||||
// Last modified: 06/02/2007
|
||||
//
|
||||
// Filename: src-IL/src/il_error.c
|
||||
//
|
||||
// Description: The error functions
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
|
||||
|
||||
#define IL_ERROR_STACK_SIZE 32 // Needed elsewhere?
|
||||
|
||||
|
||||
ILenum ilErrorNum[IL_ERROR_STACK_SIZE];
|
||||
ILint ilErrorPlace = (-1);
|
||||
|
||||
|
||||
// Sets the current error
|
||||
// If you go past the stack size for this, it cycles the errors, almost like a LRU algo.
|
||||
ILAPI void ILAPIENTRY ilSetError(ILenum Error)
|
||||
{
|
||||
ILuint i;
|
||||
|
||||
ilErrorPlace++;
|
||||
if (ilErrorPlace >= IL_ERROR_STACK_SIZE) {
|
||||
for (i = 0; i < IL_ERROR_STACK_SIZE - 2; i++) {
|
||||
ilErrorNum[i] = ilErrorNum[i+1];
|
||||
}
|
||||
ilErrorPlace = IL_ERROR_STACK_SIZE - 1;
|
||||
}
|
||||
ilErrorNum[ilErrorPlace] = Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! Gets the last error on the error stack
|
||||
ILenum ILAPIENTRY ilGetError(void)
|
||||
{
|
||||
ILenum ilReturn;
|
||||
|
||||
if (ilErrorPlace >= 0) {
|
||||
ilReturn = ilErrorNum[ilErrorPlace];
|
||||
ilErrorPlace--;
|
||||
}
|
||||
else
|
||||
ilReturn = IL_NO_ERROR;
|
||||
|
||||
return ilReturn;
|
||||
}
|
||||
@@ -0,0 +1,435 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_exr.cpp
|
||||
//
|
||||
// Description: Reads from an OpenEXR (.exr) file using the OpenEXR library.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_EXR
|
||||
|
||||
#ifndef HAVE_CONFIG_H // We are probably on a Windows box .
|
||||
//#define OPENEXR_DLL
|
||||
#define HALF_EXPORTS
|
||||
#endif //HAVE_CONFIG_H
|
||||
|
||||
#include "il_exr.h"
|
||||
#include <ImfRgba.h>
|
||||
#include <ImfArray.h>
|
||||
#include <ImfRgbaFile.h>
|
||||
//#include <ImfTiledRgbaFile.h>
|
||||
//#include <ImfInputFile.h>
|
||||
//#include <ImfTiledInputFile.h>
|
||||
//#include <ImfPreviewImage.h>
|
||||
//#include <ImfChannelList.h>
|
||||
|
||||
|
||||
|
||||
#if (defined(_WIN32) || defined(_WIN64)) && defined(IL_USE_PRAGMA_LIBS)
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#ifndef _DEBUG
|
||||
#pragma comment(lib, "openexr.lib")
|
||||
#else
|
||||
#pragma comment(lib, "openexr-d.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid EXR file.
|
||||
ILboolean ilIsValidExr(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE ExrFile;
|
||||
ILboolean bExr = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("exr"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bExr;
|
||||
}
|
||||
|
||||
ExrFile = iopenr(FileName);
|
||||
if (ExrFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bExr;
|
||||
}
|
||||
|
||||
bExr = ilIsValidExrF(ExrFile);
|
||||
icloser(ExrFile);
|
||||
|
||||
return bExr;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid EXR file at the current position.
|
||||
ILboolean ilIsValidExrF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidExr();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid EXR lump.
|
||||
ILboolean ilIsValidExrL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidExr();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the EXR header from the current file.
|
||||
ILboolean iGetExrHead(EXRHEAD *Header)
|
||||
{
|
||||
Header->MagicNumber = GetLittleUInt();
|
||||
Header->Version = GetLittleUInt();
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidExr()
|
||||
{
|
||||
EXRHEAD Head;
|
||||
|
||||
if (!iGetExrHead(&Head))
|
||||
return IL_FALSE;
|
||||
iseek(-8, IL_SEEK_CUR);
|
||||
|
||||
return iCheckExr(&Head);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid EXR header.
|
||||
ILboolean iCheckExr(EXRHEAD *Header)
|
||||
{
|
||||
// The file magic number (signature) is 0x76, 0x2f, 0x31, 0x01
|
||||
if (Header->MagicNumber != 0x01312F76)
|
||||
return IL_FALSE;
|
||||
// The only valid version so far is version 2. The upper value has
|
||||
// to do with tiling.
|
||||
if (Header->Version != 0x002 && Header->Version != 0x202)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Nothing to do here in the constructor.
|
||||
ilIStream::ilIStream() : Imf::IStream("N/A")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool ilIStream::read(char c[], int n)
|
||||
{
|
||||
if (iread(c, 1, n) != n)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//@TODO: Make this work with 64-bit values.
|
||||
Imf::Int64 ilIStream::tellg()
|
||||
{
|
||||
Imf::Int64 Pos;
|
||||
|
||||
// itell only returns a 32-bit value!
|
||||
Pos = itell();
|
||||
|
||||
return Pos;
|
||||
}
|
||||
|
||||
|
||||
// Note that there is no return value here, even though there probably should be.
|
||||
//@TODO: Make this work with 64-bit values.
|
||||
void ilIStream::seekg(Imf::Int64 Pos)
|
||||
{
|
||||
// iseek only uses a 32-bit value!
|
||||
iseek((ILint)Pos, IL_SEEK_SET); // I am assuming this is seeking from the beginning.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void ilIStream::clear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an .exr file.
|
||||
ILboolean ilLoadExr(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE ExrFile;
|
||||
ILboolean bExr = IL_FALSE;
|
||||
|
||||
ExrFile = iopenr(FileName);
|
||||
if (ExrFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bExr;
|
||||
}
|
||||
|
||||
bExr = ilLoadExrF(ExrFile);
|
||||
icloser(ExrFile);
|
||||
|
||||
return bExr;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .exr file
|
||||
ILboolean ilLoadExrF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadExrInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains an .exr
|
||||
ILboolean ilLoadExrL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadExrInternal();
|
||||
}
|
||||
|
||||
|
||||
using namespace Imath;
|
||||
using namespace Imf;
|
||||
using namespace std;
|
||||
|
||||
|
||||
ILboolean iLoadExrInternal()
|
||||
{
|
||||
Array<Rgba> pixels;
|
||||
Box2i dataWindow;
|
||||
float pixelAspectRatio;
|
||||
ILfloat *FloatData;
|
||||
|
||||
ilIStream File;
|
||||
RgbaInputFile in(File);
|
||||
|
||||
Rgba a;
|
||||
dataWindow = in.dataWindow();
|
||||
pixelAspectRatio = in.pixelAspectRatio();
|
||||
|
||||
int dw, dh, dx, dy;
|
||||
|
||||
dw = dataWindow.max.x - dataWindow.min.x + 1;
|
||||
dh = dataWindow.max.y - dataWindow.min.y + 1;
|
||||
dx = dataWindow.min.x;
|
||||
dy = dataWindow.min.y;
|
||||
|
||||
pixels.resizeErase (dw * dh);
|
||||
in.setFrameBuffer (pixels - dx - dy * dw, 1, dw);
|
||||
|
||||
try
|
||||
{
|
||||
in.readPixels (dataWindow.min.y, dataWindow.max.y);
|
||||
}
|
||||
catch (const exception &e)
|
||||
{
|
||||
// If some of the pixels in the file cannot be read,
|
||||
// print an error message, and return a partial image
|
||||
// to the caller.
|
||||
ilSetError(IL_LIB_EXR_ERROR); // Could I use something a bit more descriptive based on e?
|
||||
e; // Prevent the compiler from yelling at us about this being unused.
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
//if (ilTexImage(dw, dh, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL) == IL_FALSE)
|
||||
//if (ilTexImage(dw, dh, 1, 4, IL_RGBA, IL_UNSIGNED_SHORT, NULL) == IL_FALSE)
|
||||
if (ilTexImage(dw, dh, 1, 4, IL_RGBA, IL_FLOAT, NULL) == IL_FALSE)
|
||||
return IL_FALSE;
|
||||
|
||||
// Determine where the origin is in the original file.
|
||||
if (in.lineOrder() == INCREASING_Y)
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
else
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
|
||||
// Better to access FloatData instead of recasting everytime.
|
||||
FloatData = (ILfloat*)iCurImage->Data;
|
||||
|
||||
for (int i = 0; i < dw * dh; i++)
|
||||
{
|
||||
// Too much data lost
|
||||
//iCurImage->Data[i * 4 + 0] = (ILubyte)(pixels[i].r.bits() >> 8);
|
||||
//iCurImage->Data[i * 4 + 1] = (ILubyte)(pixels[i].g.bits() >> 8);
|
||||
//iCurImage->Data[i * 4 + 2] = (ILubyte)(pixels[i].b.bits() >> 8);
|
||||
//iCurImage->Data[i * 4 + 3] = (ILubyte)(pixels[i].a.bits() >> 8);
|
||||
|
||||
// The images look kind of washed out with this.
|
||||
//((ILshort*)(iCurImage->Data))[i * 4 + 0] = pixels[i].r.bits();
|
||||
//((ILshort*)(iCurImage->Data))[i * 4 + 1] = pixels[i].g.bits();
|
||||
//((ILshort*)(iCurImage->Data))[i * 4 + 2] = pixels[i].b.bits();
|
||||
//((ILshort*)(iCurImage->Data))[i * 4 + 3] = pixels[i].a.bits();
|
||||
|
||||
// This gives the best results, since no data is lost.
|
||||
FloatData[i * 4] = pixels[i].r;
|
||||
FloatData[i * 4 + 1] = pixels[i].g;
|
||||
FloatData[i * 4 + 2] = pixels[i].b;
|
||||
FloatData[i * 4 + 3] = pixels[i].a;
|
||||
}
|
||||
|
||||
// Converts the image to predefined type, format and/or origin if needed.
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Nothing to do here in the constructor.
|
||||
ilOStream::ilOStream() : Imf::OStream("N/A")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void ilOStream::write(const char c[], int n)
|
||||
{
|
||||
iwrite(c, 1, n); //@TODO: Throw an exception here.
|
||||
return;
|
||||
}
|
||||
|
||||
//@TODO: Make this work with 64-bit values.
|
||||
Imf::Int64 ilOStream::tellp()
|
||||
{
|
||||
Imf::Int64 Pos;
|
||||
|
||||
// itellw only returns a 32-bit value!
|
||||
Pos = itellw();
|
||||
|
||||
return Pos;
|
||||
}
|
||||
|
||||
// Note that there is no return value here, even though there probably should be.
|
||||
//@TODO: Make this work with 64-bit values.
|
||||
void ilOStream::seekp(Imf::Int64 Pos)
|
||||
{
|
||||
// iseekw only uses a 32-bit value!
|
||||
iseekw((ILint)Pos, IL_SEEK_SET); // I am assuming this is seeking from the beginning.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Exr file
|
||||
ILboolean ilSaveExr(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE ExrFile;
|
||||
ILuint ExrSize;
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
ExrFile = iopenw(FileName);
|
||||
if (ExrFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
ExrSize = ilSaveExrF(ExrFile);
|
||||
iclosew(ExrFile);
|
||||
|
||||
if (ExrSize == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Exr to an already-opened file
|
||||
ILuint ilSaveExrF(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputFile(File);
|
||||
Pos = itellw();
|
||||
if (iSaveExrInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Exr to a memory "lump"
|
||||
ILuint ilSaveExrL(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos = itellw();
|
||||
iSetOutputLump(Lump, Size);
|
||||
if (iSaveExrInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
ILboolean iSaveExrInternal()
|
||||
{
|
||||
Imath::Box2i DataWindow(Imath::V2i(0, 0), Imath::V2i(iCurImage->Width-1, iCurImage->Height-1));
|
||||
Imf::LineOrder Order;
|
||||
if (iCurImage->Origin == IL_ORIGIN_LOWER_LEFT)
|
||||
Order = DECREASING_Y;
|
||||
else
|
||||
Order = INCREASING_Y;
|
||||
Imf::Header Head(iCurImage->Width, iCurImage->Height, DataWindow, 1, Imath::V2f (0, 0), 1, Order);
|
||||
|
||||
ilOStream File;
|
||||
Imf::RgbaOutputFile Out(File, Head);
|
||||
ILimage *TempImage = iCurImage;
|
||||
|
||||
//@TODO: Can we always assume that Rgba is packed the same?
|
||||
Rgba *HalfData = (Rgba*)ialloc(TempImage->Width * TempImage->Height * sizeof(Rgba));
|
||||
if (HalfData == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
if (iCurImage->Format != IL_RGBA || iCurImage->Type != IL_FLOAT) {
|
||||
TempImage = iConvertImage(iCurImage, IL_RGBA, IL_FLOAT);
|
||||
if (TempImage == NULL) {
|
||||
ifree(HalfData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
ILuint Offset = 0;
|
||||
ILfloat *FloatPtr = (ILfloat*)TempImage->Data;
|
||||
for (unsigned int y = 0; y < TempImage->Height; y++) {
|
||||
for (unsigned int x = 0; x < TempImage->Width; x++) {
|
||||
HalfData[y * TempImage->Width + x].r = FloatPtr[Offset];
|
||||
HalfData[y * TempImage->Width + x].g = FloatPtr[Offset + 1];
|
||||
HalfData[y * TempImage->Width + x].b = FloatPtr[Offset + 2];
|
||||
HalfData[y * TempImage->Width + x].a = FloatPtr[Offset + 3];
|
||||
Offset += 4; // 4 floats
|
||||
}
|
||||
}
|
||||
|
||||
Out.setFrameBuffer(HalfData, 1, TempImage->Width);
|
||||
Out.writePixels(TempImage->Height); //@TODO: Do each scanline separately to keep from using so much memory.
|
||||
|
||||
// Free our half data.
|
||||
ifree(HalfData);
|
||||
// Destroy our temporary image if we used one.
|
||||
if (TempImage != iCurImage)
|
||||
ilCloseImage(TempImage);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
#endif //IL_NO_EXR
|
||||
@@ -0,0 +1,290 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2008 by Denton Woods
|
||||
// Last modified: 07/07/2006
|
||||
//
|
||||
// Filename: src-IL/src/il_fastconv.c
|
||||
//
|
||||
// Description: Converts between several image formats
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifdef ALTIVEC_GCC
|
||||
#include "altivec_typeconversion.h"
|
||||
#endif
|
||||
|
||||
ILboolean iFastConvert(ILenum DestFormat)
|
||||
{
|
||||
ILubyte *BytePtr = iCurImage->Data;
|
||||
ILushort *ShortPtr = (ILushort*)iCurImage->Data;
|
||||
ILuint *IntPtr = (ILuint*)iCurImage->Data;
|
||||
ILfloat *FloatPtr = (ILfloat*)iCurImage->Data;
|
||||
ILdouble *DblPtr = (ILdouble*)iCurImage->Data;
|
||||
|
||||
#ifndef ALTIVEC_GCC
|
||||
ILuint SizeOfData, i=0;
|
||||
ILubyte TempByte = 0;
|
||||
ILushort TempShort = 0;
|
||||
ILuint TempInt = 0;
|
||||
ILfloat TempFloat = 0;
|
||||
ILdouble TempDbl = 0;
|
||||
#endif
|
||||
|
||||
switch (DestFormat)
|
||||
{
|
||||
case IL_RGB:
|
||||
case IL_BGR:
|
||||
if (iCurImage->Format != IL_RGB && iCurImage->Format != IL_BGR)
|
||||
return IL_FALSE;
|
||||
|
||||
switch (iCurImage->Type)
|
||||
{
|
||||
case IL_BYTE:
|
||||
case IL_UNSIGNED_BYTE:
|
||||
#ifdef ALTIVEC_GCC
|
||||
abc2cba_byte(BytePtr,iCurImage->SizeOfData,BytePtr);
|
||||
#else
|
||||
SizeOfData = iCurImage->SizeOfData / 3;
|
||||
#ifdef USE_WIN32_ASM
|
||||
__asm
|
||||
{
|
||||
mov ebx, BytePtr
|
||||
mov ecx, SizeOfData
|
||||
L1:
|
||||
mov al,[ebx+0]
|
||||
xchg al,[ebx+2]
|
||||
mov [ebx+0],al
|
||||
add ebx,3
|
||||
loop L1
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < SizeOfData; i++) {
|
||||
TempByte = BytePtr[0];
|
||||
BytePtr[0] = BytePtr[2];
|
||||
BytePtr[2] = TempByte;
|
||||
BytePtr += 3;
|
||||
}
|
||||
#endif//USE_WIN32_ASM
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
|
||||
case IL_SHORT:
|
||||
case IL_UNSIGNED_SHORT:
|
||||
#ifdef ALTIVEC_GCC
|
||||
abc2cba_short(ShortPtr,iCurImage->SizeOfData,ShortPtr);
|
||||
#else
|
||||
SizeOfData = iCurImage->SizeOfData / 6; // 3*2
|
||||
#ifdef USE_WIN32_ASM
|
||||
__asm
|
||||
{
|
||||
mov ebx, ShortPtr
|
||||
mov ecx, SizeOfData
|
||||
L2:
|
||||
mov ax,[ebx+0]
|
||||
xchg ax,[ebx+4]
|
||||
mov [ebx+0],ax
|
||||
add ebx,6
|
||||
loop L2
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < SizeOfData; i++) {
|
||||
TempShort = ShortPtr[0];
|
||||
ShortPtr[0] = ShortPtr[2];
|
||||
ShortPtr[2] = TempShort;
|
||||
ShortPtr += 3;
|
||||
}
|
||||
#endif//USE_WIN32_ASM
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
|
||||
case IL_INT:
|
||||
case IL_UNSIGNED_INT:
|
||||
#ifdef ALTIVEC_GCC
|
||||
abc2cba_int(IntPtr,iCurImage->SizeOfData,IntPtr);
|
||||
#else
|
||||
SizeOfData = iCurImage->SizeOfData / 12; // 3*4
|
||||
#ifdef USE_WIN32_ASM
|
||||
__asm
|
||||
{
|
||||
mov ebx, IntPtr
|
||||
mov ecx, SizeOfData
|
||||
L3:
|
||||
mov eax,[ebx+0]
|
||||
xchg eax,[ebx+8]
|
||||
mov [ebx+0],ax
|
||||
add ebx,12
|
||||
loop L3
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < SizeOfData; i++) {
|
||||
TempInt = IntPtr[0];
|
||||
IntPtr[0] = IntPtr[2];
|
||||
IntPtr[2] = TempInt;
|
||||
IntPtr += 3;
|
||||
}
|
||||
#endif//USE_WIN32_ASM
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
|
||||
case IL_FLOAT:
|
||||
#ifdef ALTIVEC_GCC
|
||||
abc2cba_float(FloatPtr,iCurImage->SizeOfData,FloatPtr);
|
||||
#else
|
||||
SizeOfData = iCurImage->SizeOfData / 12; // 3*4
|
||||
for (i = 0; i < SizeOfData; i++) {
|
||||
TempFloat = FloatPtr[0];
|
||||
FloatPtr[0] = FloatPtr[2];
|
||||
FloatPtr[2] = TempFloat;
|
||||
FloatPtr += 3;
|
||||
}
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
|
||||
case IL_DOUBLE:
|
||||
#ifdef ALTIVEC_GCC
|
||||
abc2cba_double(DblPtr,iCurImage->SizeOfData,DblPtr);
|
||||
#else
|
||||
SizeOfData = iCurImage->SizeOfData / 24; // 3*8
|
||||
for (i = 0; i < SizeOfData; i++) {
|
||||
TempDbl = DblPtr[0];
|
||||
DblPtr[0] = DblPtr[2];
|
||||
DblPtr[2] = TempDbl;
|
||||
DblPtr += 3;
|
||||
}
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case IL_RGBA:
|
||||
case IL_BGRA:
|
||||
if (iCurImage->Format != IL_RGBA && iCurImage->Format != IL_BGRA)
|
||||
return IL_FALSE;
|
||||
|
||||
switch (iCurImage->Type)
|
||||
{
|
||||
case IL_BYTE:
|
||||
case IL_UNSIGNED_BYTE:
|
||||
#ifdef ALTIVEC_GCC
|
||||
abcd2cbad_byte(BytePtr,iCurImage->SizeOfData,BytePtr);
|
||||
#else
|
||||
SizeOfData = iCurImage->SizeOfData / 4;
|
||||
#ifdef USE_WIN32_ASM
|
||||
__asm
|
||||
{
|
||||
mov ebx, BytePtr
|
||||
mov ecx, SizeOfData
|
||||
L4:
|
||||
mov eax,[ebx]
|
||||
bswap eax
|
||||
ror eax,8
|
||||
mov [ebx], eax
|
||||
add ebx,4
|
||||
loop L4
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < SizeOfData; i++) {
|
||||
TempByte = BytePtr[0];
|
||||
BytePtr[0] = BytePtr[2];
|
||||
BytePtr[2] = TempByte;
|
||||
BytePtr += 4;
|
||||
}
|
||||
#endif//USE_WIN32_ASM
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
|
||||
case IL_SHORT:
|
||||
case IL_UNSIGNED_SHORT:
|
||||
#ifdef ALTIVEC_GCC
|
||||
abcd2cbad_short(ShortPtr,iCurImage->SizeOfData,ShortPtr);
|
||||
#else
|
||||
SizeOfData = iCurImage->SizeOfData / 8; // 4*2
|
||||
#ifdef USE_WIN32_ASM
|
||||
__asm
|
||||
{
|
||||
mov ebx, ShortPtr
|
||||
mov ecx, SizeOfData
|
||||
L5:
|
||||
mov ax,[ebx+0]
|
||||
xchg ax,[ebx+4]
|
||||
mov [ebx+0],ax
|
||||
add ebx,8
|
||||
loop L5
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < SizeOfData; i++) {
|
||||
TempShort = ShortPtr[0];
|
||||
ShortPtr[0] = ShortPtr[2];
|
||||
ShortPtr[2] = TempShort;
|
||||
ShortPtr += 4;
|
||||
}
|
||||
#endif//USE_WIN32_ASM
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
|
||||
case IL_INT:
|
||||
case IL_UNSIGNED_INT:
|
||||
#ifdef ALTIVEC_GCC
|
||||
abcd2cbad_int(IntPtr,iCurImage->SizeOfData,IntPtr);
|
||||
#else
|
||||
SizeOfData = iCurImage->SizeOfData / 16; // 4*4
|
||||
#ifdef USE_WIN32_ASM
|
||||
__asm
|
||||
{
|
||||
mov ebx, IntPtr
|
||||
mov ecx, SizeOfData
|
||||
L6:
|
||||
mov eax,[ebx+0]
|
||||
xchg eax,[ebx+8]
|
||||
mov [ebx+0],ax
|
||||
add ebx,16
|
||||
loop L6
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < SizeOfData; i++) {
|
||||
TempInt = IntPtr[0];
|
||||
IntPtr[0] = IntPtr[2];
|
||||
IntPtr[2] = TempInt;
|
||||
IntPtr += 4;
|
||||
}
|
||||
#endif//USE_WIN32_ASM
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
|
||||
case IL_FLOAT:
|
||||
#ifdef ALTIVEC_GCC
|
||||
abcd2cbad_float(FloatPtr,iCurImage->SizeOfData,FloatPtr);
|
||||
#else
|
||||
SizeOfData = iCurImage->SizeOfData / 16; // 4*4
|
||||
for (i = 0; i < SizeOfData; i++) {
|
||||
TempFloat = FloatPtr[0];
|
||||
FloatPtr[0] = FloatPtr[2];
|
||||
FloatPtr[2] = TempFloat;
|
||||
FloatPtr += 4;
|
||||
}
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
|
||||
case IL_DOUBLE:
|
||||
#ifdef ALTIVEC_GCC
|
||||
abcd2cbad_double(DblPtr,iCurImage->SizeOfData,DblPtr);
|
||||
#else
|
||||
SizeOfData = iCurImage->SizeOfData / 32; // 4*8
|
||||
for (i = 0; i < SizeOfData; i++) {
|
||||
TempDbl = DblPtr[0];
|
||||
DblPtr[0] = DblPtr[2];
|
||||
DblPtr[2] = TempDbl;
|
||||
DblPtr += 4;
|
||||
}
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,773 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 01/04/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_files.c
|
||||
//
|
||||
// Description: File handling for DevIL
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#define __FILES_C
|
||||
#include "il_internal.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
// All specific to the next set of functions
|
||||
ILboolean ILAPIENTRY iEofFile(void);
|
||||
ILboolean ILAPIENTRY iEofLump(void);
|
||||
ILint ILAPIENTRY iGetcFile(void);
|
||||
ILint ILAPIENTRY iGetcLump(void);
|
||||
ILuint ILAPIENTRY iReadFile(void *Buffer, ILuint Size, ILuint Number);
|
||||
ILuint ILAPIENTRY iReadLump(void *Buffer, const ILuint Size, const ILuint Number);
|
||||
ILint ILAPIENTRY iSeekRFile(ILint Offset, ILuint Mode);
|
||||
ILint ILAPIENTRY iSeekRLump(ILint Offset, ILuint Mode);
|
||||
ILint ILAPIENTRY iSeekWFile(ILint Offset, ILuint Mode);
|
||||
ILint ILAPIENTRY iSeekWLump(ILint Offset, ILuint Mode);
|
||||
ILuint ILAPIENTRY iTellRFile(void);
|
||||
ILuint ILAPIENTRY iTellRLump(void);
|
||||
ILuint ILAPIENTRY iTellWFile(void);
|
||||
ILuint ILAPIENTRY iTellWLump(void);
|
||||
ILint ILAPIENTRY iPutcFile(ILubyte Char);
|
||||
ILint ILAPIENTRY iPutcLump(ILubyte Char);
|
||||
ILint ILAPIENTRY iWriteFile(const void *Buffer, ILuint Size, ILuint Number);
|
||||
ILint ILAPIENTRY iWriteLump(const void *Buffer, ILuint Size, ILuint Number);
|
||||
ILHANDLE FileRead = NULL, FileWrite = NULL;
|
||||
const void *ReadLump = NULL;
|
||||
void *WriteLump = NULL;
|
||||
ILuint ReadLumpPos = 0, ReadLumpSize = 0, ReadFileStart = 0, WriteFileStart = 0;
|
||||
ILuint WriteLumpPos = 0, WriteLumpSize = 0;
|
||||
|
||||
fGetcProc GetcProcCopy;
|
||||
fReadProc ReadProcCopy;
|
||||
fSeekRProc SeekProcCopy;
|
||||
fTellRProc TellProcCopy;
|
||||
ILHANDLE (ILAPIENTRY *iopenCopy)(ILconst_string);
|
||||
void (ILAPIENTRY *icloseCopy)(ILHANDLE);
|
||||
|
||||
fPutcProc PutcProcCopy;
|
||||
fSeekWProc SeekWProcCopy;
|
||||
fTellWProc TellWProcCopy;
|
||||
fWriteProc WriteProcCopy;
|
||||
ILHANDLE (ILAPIENTRY *iopenwCopy)(ILconst_string);
|
||||
void (ILAPIENTRY *iclosewCopy)(ILHANDLE);
|
||||
|
||||
ILboolean UseCache = IL_FALSE;
|
||||
ILubyte *Cache = NULL;
|
||||
ILuint CacheSize, CachePos, CacheStartPos, CacheBytesRead;
|
||||
|
||||
// "Fake" size functions
|
||||
// Definitions are in il_size.c.
|
||||
ILint ILAPIENTRY iSizeSeek(ILint Offset, ILuint Mode);
|
||||
ILuint ILAPIENTRY iSizeTell(void);
|
||||
ILint ILAPIENTRY iSizePutc(ILubyte Char);
|
||||
ILint ILAPIENTRY iSizeWrite(const void *Buffer, ILuint Size, ILuint Number);
|
||||
|
||||
// Just preserves the current read functions and replaces
|
||||
// the current read functions with the default read funcs.
|
||||
void ILAPIENTRY iPreserveReadFuncs()
|
||||
{
|
||||
// Create backups
|
||||
GetcProcCopy = GetcProc;
|
||||
ReadProcCopy = ReadProc;
|
||||
SeekProcCopy = SeekRProc;
|
||||
TellProcCopy = TellRProc;
|
||||
iopenCopy = iopenr;
|
||||
icloseCopy = icloser;
|
||||
|
||||
// Set the standard procs to read
|
||||
ilResetRead();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Restores the read functions - must be used after iPreserveReadFuncs().
|
||||
void ILAPIENTRY iRestoreReadFuncs()
|
||||
{
|
||||
GetcProc = GetcProcCopy;
|
||||
ReadProc = ReadProcCopy;
|
||||
SeekRProc = SeekProcCopy;
|
||||
TellRProc = TellProcCopy;
|
||||
iopenr = iopenCopy;
|
||||
icloser = icloseCopy;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Just preserves the current read functions and replaces
|
||||
// the current read functions with the default read funcs.
|
||||
void ILAPIENTRY iPreserveWriteFuncs()
|
||||
{
|
||||
// Create backups
|
||||
PutcProcCopy = PutcProc;
|
||||
SeekWProcCopy = SeekWProc;
|
||||
TellWProcCopy = TellWProc;
|
||||
WriteProcCopy = WriteProc;
|
||||
iopenwCopy = iopenw;
|
||||
iclosewCopy = iclosew;
|
||||
|
||||
// Set the standard procs to write
|
||||
ilResetWrite();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Restores the read functions - must be used after iPreserveReadFuncs().
|
||||
void ILAPIENTRY iRestoreWriteFuncs()
|
||||
{
|
||||
PutcProc = PutcProcCopy;
|
||||
SeekWProc = SeekWProcCopy;
|
||||
TellWProc = TellWProcCopy;
|
||||
WriteProc = WriteProcCopy;
|
||||
iopenw = iopenwCopy;
|
||||
iclosew = iclosewCopy;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Next 7 functions are the default read functions
|
||||
|
||||
ILHANDLE ILAPIENTRY iDefaultOpenR(ILconst_string FileName)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
return (ILHANDLE)fopen((char*)FileName, "rb");
|
||||
#else
|
||||
// Windows has a different function, _wfopen, to open UTF16 files,
|
||||
// whereas Linux just uses fopen for its UTF8 files.
|
||||
#ifdef _WIN32
|
||||
return (ILHANDLE)_wfopen(FileName, L"rb");
|
||||
#else
|
||||
return (ILHANDLE)fopen((char*)FileName, "rb");
|
||||
#endif
|
||||
#endif//UNICODE
|
||||
}
|
||||
|
||||
|
||||
void ILAPIENTRY iDefaultCloseR(ILHANDLE Handle)
|
||||
{
|
||||
fclose((FILE*)Handle);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ILAPIENTRY iDefaultEof(ILHANDLE Handle)
|
||||
{
|
||||
ILuint OrigPos, FileSize;
|
||||
|
||||
// Find out the filesize for checking for the end of file
|
||||
OrigPos = itell();
|
||||
iseek(0, IL_SEEK_END);
|
||||
FileSize = itell();
|
||||
iseek(OrigPos, IL_SEEK_SET);
|
||||
|
||||
if (itell() >= FileSize)
|
||||
return IL_TRUE;
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iDefaultGetc(ILHANDLE Handle)
|
||||
{
|
||||
ILint Val;
|
||||
|
||||
if (!UseCache) {
|
||||
Val = fgetc((FILE*)Handle);
|
||||
if (Val == IL_EOF)
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
}
|
||||
else {
|
||||
Val = 0;
|
||||
if (iread(&Val, 1, 1) != 1)
|
||||
return IL_EOF;
|
||||
}
|
||||
return Val;
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iDefaultRead(void *Buffer, ILuint Size, ILuint Number, ILHANDLE Handle)
|
||||
{
|
||||
return (ILint)fread(Buffer, Size, Number, (FILE*)Handle);
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iDefaultRSeek(ILHANDLE Handle, ILint Offset, ILint Mode)
|
||||
{
|
||||
return fseek((FILE*)Handle, Offset, Mode);
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iDefaultWSeek(ILHANDLE Handle, ILint Offset, ILint Mode)
|
||||
{
|
||||
return fseek((FILE*)Handle, Offset, Mode);
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iDefaultRTell(ILHANDLE Handle)
|
||||
{
|
||||
return ftell((FILE*)Handle);
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iDefaultWTell(ILHANDLE Handle)
|
||||
{
|
||||
return ftell((FILE*)Handle);
|
||||
}
|
||||
|
||||
|
||||
ILHANDLE ILAPIENTRY iDefaultOpenW(ILconst_string FileName)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
return (ILHANDLE)fopen((char*)FileName, "wb");
|
||||
#else
|
||||
// Windows has a different function, _wfopen, to open UTF16 files,
|
||||
// whereas Linux just uses fopen.
|
||||
#ifdef _WIN32
|
||||
return (ILHANDLE)_wfopen(FileName, L"wb");
|
||||
#else
|
||||
return (ILHANDLE)fopen((char*)FileName, "wb");
|
||||
#endif
|
||||
#endif//UNICODE
|
||||
}
|
||||
|
||||
|
||||
void ILAPIENTRY iDefaultCloseW(ILHANDLE Handle)
|
||||
{
|
||||
fclose((FILE*)Handle);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iDefaultPutc(ILubyte Char, ILHANDLE Handle)
|
||||
{
|
||||
return fputc(Char, (FILE*)Handle);
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iDefaultWrite(const void *Buffer, ILuint Size, ILuint Number, ILHANDLE Handle)
|
||||
{
|
||||
return (ILint)fwrite(Buffer, Size, Number, (FILE*)Handle);
|
||||
}
|
||||
|
||||
|
||||
void ILAPIENTRY ilResetRead()
|
||||
{
|
||||
ilSetRead(iDefaultOpenR, iDefaultCloseR, iDefaultEof, iDefaultGetc,
|
||||
iDefaultRead, iDefaultRSeek, iDefaultRTell);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void ILAPIENTRY ilResetWrite()
|
||||
{
|
||||
ilSetWrite(iDefaultOpenW, iDefaultCloseW, iDefaultPutc,
|
||||
iDefaultWSeek, iDefaultWTell, iDefaultWrite);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! Allows you to override the default file-reading functions.
|
||||
void ILAPIENTRY ilSetRead(fOpenRProc Open, fCloseRProc Close, fEofProc Eof, fGetcProc Getc, fReadProc Read, fSeekRProc Seek, fTellRProc Tell)
|
||||
{
|
||||
iopenr = Open;
|
||||
icloser = Close;
|
||||
EofProc = Eof;
|
||||
GetcProc = Getc;
|
||||
ReadProc = Read;
|
||||
SeekRProc = Seek;
|
||||
TellRProc = Tell;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! Allows you to override the default file-writing functions.
|
||||
void ILAPIENTRY ilSetWrite(fOpenRProc Open, fCloseRProc Close, fPutcProc Putc, fSeekWProc Seek, fTellWProc Tell, fWriteProc Write)
|
||||
{
|
||||
iopenw = Open;
|
||||
iclosew = Close;
|
||||
PutcProc = Putc;
|
||||
WriteProc = Write;
|
||||
SeekWProc = Seek;
|
||||
TellWProc = Tell;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Tells DevIL that we're reading from a file, not a lump
|
||||
void iSetInputFile(ILHANDLE File)
|
||||
{
|
||||
ieof = iEofFile;
|
||||
igetc = iGetcFile;
|
||||
iread = iReadFile;
|
||||
iseek = iSeekRFile;
|
||||
itell = iTellRFile;
|
||||
FileRead = File;
|
||||
ReadFileStart = itell();
|
||||
}
|
||||
|
||||
|
||||
// Tells DevIL that we're reading from a lump, not a file
|
||||
void iSetInputLump(const void *Lump, ILuint Size)
|
||||
{
|
||||
ieof = iEofLump;
|
||||
igetc = iGetcLump;
|
||||
iread = iReadLump;
|
||||
iseek = iSeekRLump;
|
||||
itell = iTellRLump;
|
||||
ReadLump = Lump;
|
||||
ReadLumpPos = 0;
|
||||
ReadLumpSize = Size;
|
||||
}
|
||||
|
||||
|
||||
// Tells DevIL that we're writing to a file, not a lump
|
||||
void iSetOutputFile(ILHANDLE File)
|
||||
{
|
||||
// Helps with ilGetLumpPos().
|
||||
WriteLump = NULL;
|
||||
WriteLumpPos = 0;
|
||||
WriteLumpSize = 0;
|
||||
|
||||
iputc = iPutcFile;
|
||||
iseekw = iSeekWFile;
|
||||
itellw = iTellWFile;
|
||||
iwrite = iWriteFile;
|
||||
FileWrite = File;
|
||||
}
|
||||
|
||||
|
||||
// This is only called by ilDetermineSize. Associates iputc, etc. with
|
||||
// "fake" writing functions in il_size.c.
|
||||
void iSetOutputFake(void)
|
||||
{
|
||||
iputc = iSizePutc;
|
||||
iseekw = iSizeSeek;
|
||||
itellw = iSizeTell;
|
||||
iwrite = iSizeWrite;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Tells DevIL that we're writing to a lump, not a file
|
||||
void iSetOutputLump(void *Lump, ILuint Size)
|
||||
{
|
||||
// In this case, ilDetermineSize is currently trying to determine the
|
||||
// output buffer size. It already has the write functions it needs.
|
||||
if (Lump == NULL)
|
||||
return;
|
||||
|
||||
iputc = iPutcLump;
|
||||
iseekw = iSeekWLump;
|
||||
itellw = iTellWLump;
|
||||
iwrite = iWriteLump;
|
||||
WriteLump = Lump;
|
||||
WriteLumpPos = 0;
|
||||
WriteLumpSize = Size;
|
||||
}
|
||||
|
||||
|
||||
ILuint ILAPIENTRY ilGetLumpPos()
|
||||
{
|
||||
if (WriteLump)
|
||||
return WriteLumpPos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ILuint ILAPIENTRY ilprintf(const char *Line, ...)
|
||||
{
|
||||
char Buffer[2048]; // Hope this is large enough
|
||||
va_list VaLine;
|
||||
ILuint i;
|
||||
|
||||
va_start(VaLine, Line);
|
||||
vsprintf(Buffer, Line, VaLine);
|
||||
va_end(VaLine);
|
||||
|
||||
i = ilCharStrLen(Buffer);
|
||||
iwrite(Buffer, 1, i);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
// To pad zeros where needed...
|
||||
void ipad(ILuint NumZeros)
|
||||
{
|
||||
ILuint i = 0;
|
||||
for (; i < NumZeros; i++)
|
||||
iputc(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// The rest of the functions following in this file are quite
|
||||
// self-explanatory, except where commented.
|
||||
//
|
||||
|
||||
// Next 12 functions are the default write functions
|
||||
|
||||
ILboolean ILAPIENTRY iEofFile(void)
|
||||
{
|
||||
return EofProc((FILE*)FileRead);
|
||||
}
|
||||
|
||||
|
||||
ILboolean ILAPIENTRY iEofLump(void)
|
||||
{
|
||||
if (ReadLumpSize)
|
||||
return (ReadLumpPos >= ReadLumpSize);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iGetcFile(void)
|
||||
{
|
||||
if (!UseCache) {
|
||||
return GetcProc(FileRead);
|
||||
}
|
||||
if (CachePos >= CacheSize) {
|
||||
iPreCache(CacheSize);
|
||||
}
|
||||
|
||||
CacheBytesRead++;
|
||||
return Cache[CachePos++];
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iGetcLump(void)
|
||||
{
|
||||
// If ReadLumpSize is 0, don't even check to see if we've gone past the bounds.
|
||||
if (ReadLumpSize > 0) {
|
||||
if (ReadLumpPos + 1 > ReadLumpSize) {
|
||||
ReadLumpPos--;
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return IL_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
return *((ILubyte*)ReadLump + ReadLumpPos++);
|
||||
}
|
||||
|
||||
|
||||
ILuint ILAPIENTRY iReadFile(void *Buffer, ILuint Size, ILuint Number)
|
||||
{
|
||||
ILuint TotalBytes = 0, BytesCopied;
|
||||
ILuint BuffSize = Size * Number;
|
||||
ILuint NumRead;
|
||||
|
||||
if (!UseCache) {
|
||||
NumRead = ReadProc(Buffer, Size, Number, FileRead);
|
||||
if (NumRead != Number)
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return NumRead;
|
||||
}
|
||||
|
||||
/*if (Cache == NULL || CacheSize == 0) { // Shouldn't happen, but we check anyway.
|
||||
return ReadProc(Buffer, Size, Number, FileRead);
|
||||
}*/
|
||||
|
||||
if (BuffSize < CacheSize - CachePos) {
|
||||
memcpy(Buffer, Cache + CachePos, BuffSize);
|
||||
CachePos += BuffSize;
|
||||
CacheBytesRead += BuffSize;
|
||||
if (Size != 0)
|
||||
BuffSize /= Size;
|
||||
return BuffSize;
|
||||
}
|
||||
else {
|
||||
while (TotalBytes < BuffSize) {
|
||||
// If loop through more than once, after first, CachePos is 0.
|
||||
if (TotalBytes + CacheSize - CachePos > BuffSize)
|
||||
BytesCopied = BuffSize - TotalBytes;
|
||||
else
|
||||
BytesCopied = CacheSize - CachePos;
|
||||
|
||||
memcpy((ILubyte*)Buffer + TotalBytes, Cache + CachePos, BytesCopied);
|
||||
TotalBytes += BytesCopied;
|
||||
CachePos += BytesCopied;
|
||||
if (TotalBytes < BuffSize) {
|
||||
iPreCache(CacheSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DW: Changed on 12-27-2008. Was causing the position to go too far if the
|
||||
// cache was smaller than the buffer.
|
||||
//CacheBytesRead += TotalBytes;
|
||||
CacheBytesRead = CachePos;
|
||||
if (Size != 0)
|
||||
TotalBytes /= Size;
|
||||
if (TotalBytes != Number)
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return TotalBytes;
|
||||
}
|
||||
|
||||
|
||||
ILuint ILAPIENTRY iReadLump(void *Buffer, const ILuint Size, const ILuint Number)
|
||||
{
|
||||
ILuint i, ByteSize = IL_MIN( Size*Number, ReadLumpSize-ReadLumpPos);
|
||||
|
||||
for (i = 0; i < ByteSize; i++) {
|
||||
*((ILubyte*)Buffer + i) = *((ILubyte*)ReadLump + ReadLumpPos + i);
|
||||
if (ReadLumpSize > 0) { // ReadLumpSize is too large to care about apparently
|
||||
if (ReadLumpPos + i > ReadLumpSize) {
|
||||
ReadLumpPos += i;
|
||||
if (i != Number)
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReadLumpPos += i;
|
||||
if (Size != 0)
|
||||
i /= Size;
|
||||
if (i != Number)
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
ILboolean iPreCache(ILuint Size)
|
||||
{
|
||||
// Reading from a memory lump, so don't cache.
|
||||
if (iread == iReadLump) {
|
||||
//iUnCache(); // DW: Removed 06-10-2002.
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
if (Cache) {
|
||||
ifree(Cache);
|
||||
}
|
||||
|
||||
if (Size == 0) {
|
||||
Size = 1;
|
||||
}
|
||||
|
||||
Cache = (ILubyte*)ialloc(Size);
|
||||
if (Cache == NULL) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
UseCache = IL_FALSE;
|
||||
CacheStartPos = itell();
|
||||
CacheSize = iread(Cache, 1, Size);
|
||||
if (CacheSize != Size)
|
||||
ilGetError(); // Get rid of the IL_FILE_READ_ERROR.
|
||||
|
||||
//2003-09-09: uncommented the following line to prevent
|
||||
//an infinite loop in ilPreCache()
|
||||
CacheSize = Size;
|
||||
CachePos = 0;
|
||||
UseCache = IL_TRUE;
|
||||
CacheBytesRead = 0;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
void iUnCache()
|
||||
{
|
||||
//changed 2003-09-01:
|
||||
//make iUnCache smart enough to return if
|
||||
//no cache is used
|
||||
if (!UseCache)
|
||||
return;
|
||||
|
||||
if (iread == iReadLump)
|
||||
return;
|
||||
|
||||
CacheSize = 0;
|
||||
CachePos = 0;
|
||||
if (Cache) {
|
||||
ifree(Cache);
|
||||
Cache = NULL;
|
||||
}
|
||||
UseCache = IL_FALSE;
|
||||
|
||||
iseek(CacheStartPos + CacheBytesRead, IL_SEEK_SET);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iSeekRFile(ILint Offset, ILuint Mode)
|
||||
{
|
||||
if (Mode == IL_SEEK_SET)
|
||||
Offset += ReadFileStart; // This allows us to use IL_SEEK_SET in the middle of a file.
|
||||
return SeekRProc(FileRead, Offset, Mode);
|
||||
}
|
||||
|
||||
|
||||
// Returns 1 on error, 0 on success
|
||||
ILint ILAPIENTRY iSeekRLump(ILint Offset, ILuint Mode)
|
||||
{
|
||||
switch (Mode)
|
||||
{
|
||||
case IL_SEEK_SET:
|
||||
if (Offset > (ILint)ReadLumpSize)
|
||||
return 1;
|
||||
ReadLumpPos = Offset;
|
||||
break;
|
||||
|
||||
case IL_SEEK_CUR:
|
||||
if (ReadLumpPos + Offset > ReadLumpSize)
|
||||
return 1;
|
||||
ReadLumpPos += Offset;
|
||||
break;
|
||||
|
||||
case IL_SEEK_END:
|
||||
if (Offset > 0)
|
||||
return 1;
|
||||
// Should we use >= instead?
|
||||
if (abs(Offset) > (ILint)ReadLumpSize) // If ReadLumpSize == 0, too bad
|
||||
return 1;
|
||||
ReadLumpPos = ReadLumpSize + Offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ILuint ILAPIENTRY iTellRFile(void)
|
||||
{
|
||||
return TellRProc(FileRead);
|
||||
}
|
||||
|
||||
|
||||
ILuint ILAPIENTRY iTellRLump(void)
|
||||
{
|
||||
return ReadLumpPos;
|
||||
}
|
||||
|
||||
|
||||
ILHANDLE ILAPIENTRY iGetFile(void)
|
||||
{
|
||||
return FileRead;
|
||||
}
|
||||
|
||||
|
||||
const ILubyte* ILAPIENTRY iGetLump(void) {
|
||||
return (ILubyte*)ReadLump;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Next 4 functions are the default write functions
|
||||
|
||||
ILint ILAPIENTRY iPutcFile(ILubyte Char)
|
||||
{
|
||||
return PutcProc(Char, FileWrite);
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iPutcLump(ILubyte Char)
|
||||
{
|
||||
if (WriteLumpPos >= WriteLumpSize)
|
||||
return IL_EOF; // IL_EOF
|
||||
*((ILubyte*)(WriteLump) + WriteLumpPos++) = Char;
|
||||
return Char;
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iWriteFile(const void *Buffer, ILuint Size, ILuint Number)
|
||||
{
|
||||
ILuint NumWritten;
|
||||
NumWritten = WriteProc(Buffer, Size, Number, FileWrite);
|
||||
if (NumWritten != Number) {
|
||||
ilSetError(IL_FILE_WRITE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
return NumWritten;
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iWriteLump(const void *Buffer, ILuint Size, ILuint Number)
|
||||
{
|
||||
ILuint SizeBytes = Size * Number;
|
||||
ILuint i = 0;
|
||||
|
||||
for (; i < SizeBytes; i++) {
|
||||
if (WriteLumpSize > 0) {
|
||||
if (WriteLumpPos + i >= WriteLumpSize) { // Should we use > instead?
|
||||
ilSetError(IL_FILE_WRITE_ERROR);
|
||||
WriteLumpPos += i;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
*((ILubyte*)WriteLump + WriteLumpPos + i) = *((ILubyte*)Buffer + i);
|
||||
}
|
||||
|
||||
WriteLumpPos += SizeBytes;
|
||||
|
||||
return SizeBytes;
|
||||
}
|
||||
|
||||
|
||||
ILint ILAPIENTRY iSeekWFile(ILint Offset, ILuint Mode)
|
||||
{
|
||||
if (Mode == IL_SEEK_SET)
|
||||
Offset += WriteFileStart; // This allows us to use IL_SEEK_SET in the middle of a file.
|
||||
return SeekWProc(FileWrite, Offset, Mode);
|
||||
}
|
||||
|
||||
|
||||
// Returns 1 on error, 0 on success
|
||||
ILint ILAPIENTRY iSeekWLump(ILint Offset, ILuint Mode)
|
||||
{
|
||||
switch (Mode)
|
||||
{
|
||||
case IL_SEEK_SET:
|
||||
if (Offset > (ILint)WriteLumpSize)
|
||||
return 1;
|
||||
WriteLumpPos = Offset;
|
||||
break;
|
||||
|
||||
case IL_SEEK_CUR:
|
||||
if (WriteLumpPos + Offset > WriteLumpSize)
|
||||
return 1;
|
||||
WriteLumpPos += Offset;
|
||||
break;
|
||||
|
||||
case IL_SEEK_END:
|
||||
if (Offset > 0)
|
||||
return 1;
|
||||
// Should we use >= instead?
|
||||
if (abs(Offset) > (ILint)WriteLumpSize) // If WriteLumpSize == 0, too bad
|
||||
return 1;
|
||||
WriteLumpPos = WriteLumpSize + Offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ILuint ILAPIENTRY iTellWFile(void)
|
||||
{
|
||||
return TellWProc(FileWrite);
|
||||
}
|
||||
|
||||
|
||||
ILuint ILAPIENTRY iTellWLump(void)
|
||||
{
|
||||
return WriteLumpPos;
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 02/14/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_fits.c
|
||||
//
|
||||
// Description: Reads from a Flexible Image Transport System (.fits) file.
|
||||
// Specifications were found at
|
||||
// http://www.fileformat.info/format/fits.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_FITS
|
||||
|
||||
typedef struct FITSHEAD
|
||||
{
|
||||
ILboolean IsSimple;
|
||||
ILint BitsPixel;
|
||||
ILint NumAxes; // Number of dimensions / axes
|
||||
ILint Width;
|
||||
ILint Height;
|
||||
ILint Depth;
|
||||
ILint NumChans;
|
||||
|
||||
// Not in the header, but it keeps everything together.
|
||||
ILenum Type;
|
||||
ILenum Format;
|
||||
|
||||
} FITSHEAD;
|
||||
|
||||
enum {
|
||||
CARD_READ_FAIL = -1,
|
||||
CARD_END = 1,
|
||||
CARD_SIMPLE,
|
||||
CARD_NOT_SIMPLE,
|
||||
CARD_BITPIX,
|
||||
CARD_NUMAXES,
|
||||
CARD_AXIS,
|
||||
CARD_SKIP
|
||||
};
|
||||
|
||||
ILboolean iIsValidFits(void);
|
||||
ILboolean iCheckFits(FITSHEAD *Header);
|
||||
ILboolean iLoadFitsInternal(void);
|
||||
ILenum GetCardImage(FITSHEAD *Header);
|
||||
ILboolean GetCardInt(char *Buffer, ILint *Val);
|
||||
|
||||
//! Checks if the file specified in FileName is a valid FITS file.
|
||||
ILboolean ilIsValidFits(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE FitsFile;
|
||||
ILboolean bFits = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("fits")) && !iCheckExtension(FileName, IL_TEXT("fit"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bFits;
|
||||
}
|
||||
|
||||
FitsFile = iopenr(FileName);
|
||||
if (FitsFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bFits;
|
||||
}
|
||||
|
||||
bFits = ilIsValidFitsF(FitsFile);
|
||||
icloser(FitsFile);
|
||||
|
||||
return bFits;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid FITS file at the current position.
|
||||
ILboolean ilIsValidFitsF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidFits();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid FITS lump.
|
||||
ILboolean ilIsValidFitsL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidFits();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the FITS header from the current file.
|
||||
ILboolean iGetFitsHead(FITSHEAD *Header)
|
||||
{
|
||||
ILenum CardKey;
|
||||
|
||||
//@TODO: Use something other than memset?
|
||||
memset(Header, 0, sizeof(Header)); // Clear the header to all 0s first.
|
||||
|
||||
do {
|
||||
CardKey = GetCardImage(Header);
|
||||
if (CardKey == CARD_END) // End of the header
|
||||
break;
|
||||
if (CardKey == CARD_READ_FAIL)
|
||||
return IL_FALSE;
|
||||
if (CardKey == CARD_NOT_SIMPLE)
|
||||
return IL_FALSE;
|
||||
} while (!ieof());
|
||||
|
||||
// The header should never reach the end of the file.
|
||||
if (ieof())
|
||||
return IL_FALSE; // Error needed?
|
||||
|
||||
// The header must always be a multiple of 2880, so we skip the padding bytes (spaces).
|
||||
iseek((2880 - (itell() % 2880)) % 2880, IL_SEEK_CUR);
|
||||
|
||||
switch (Header->BitsPixel)
|
||||
{
|
||||
case 8:
|
||||
Header->Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case 16:
|
||||
Header->Type = IL_SHORT;
|
||||
break;
|
||||
case 32:
|
||||
Header->Type = IL_INT;
|
||||
break;
|
||||
case -32:
|
||||
Header->Type = IL_FLOAT;
|
||||
break;
|
||||
case -64:
|
||||
Header->Type = IL_DOUBLE;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
switch (Header->NumAxes)
|
||||
{
|
||||
case 1: // Just a 1D image
|
||||
Header->Format = IL_LUMINANCE;
|
||||
Header->Height = 1;
|
||||
Header->Depth = 1;
|
||||
Header->NumChans = 1;
|
||||
break;
|
||||
|
||||
case 2: // Assuming it is a 2D image (width+height)
|
||||
Header->Format = IL_LUMINANCE;
|
||||
Header->Depth = 1;
|
||||
Header->NumChans = 1;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// We cannot deal with more than 3 channels in an image.
|
||||
Header->Format = IL_LUMINANCE;
|
||||
Header->NumChans = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidFits(void)
|
||||
{
|
||||
FITSHEAD Header;
|
||||
ILuint Pos = itell();
|
||||
|
||||
if (!iGetFitsHead(&Header))
|
||||
return IL_FALSE;
|
||||
// The length of the header varies, so we just go back to the original position.
|
||||
iseek(Pos, IL_SEEK_CUR);
|
||||
|
||||
return iCheckFits(&Header);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid FITS header.
|
||||
ILboolean iCheckFits(FITSHEAD *Header)
|
||||
{
|
||||
switch (Header->BitsPixel)
|
||||
{
|
||||
case 8: // These are the only values accepted.
|
||||
case 16:
|
||||
case 32:
|
||||
case -32:
|
||||
case -64:
|
||||
break;
|
||||
default:
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
switch (Header->NumAxes)
|
||||
{
|
||||
case 1: // Just a 1D image
|
||||
case 2: // Assuming it is a 2D image (width+height)
|
||||
case 3: // 3D image (with depth)
|
||||
break;
|
||||
default:
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Possibility that one of these values is returned as <= 0 by atoi, which we cannot use.
|
||||
if (Header->Width <= 0 || Header->Height <= 0 || Header->Depth <= 0) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a FITS file
|
||||
ILboolean ilLoadFits(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE FitsFile;
|
||||
ILboolean bFits = IL_FALSE;
|
||||
|
||||
FitsFile = iopenr(FileName);
|
||||
if (FitsFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bFits;
|
||||
}
|
||||
|
||||
bFits = ilLoadFitsF(FitsFile);
|
||||
icloser(FitsFile);
|
||||
|
||||
return bFits;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened FITS file
|
||||
ILboolean ilLoadFitsF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadFitsInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a FITS
|
||||
ILboolean ilLoadFitsL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadFitsInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the FITS.
|
||||
ILboolean iLoadFitsInternal(void)
|
||||
{
|
||||
FITSHEAD Header;
|
||||
ILuint i, NumPix;
|
||||
ILfloat MaxF = 0.0f;
|
||||
ILdouble MaxD = 0.0f;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!iGetFitsHead(&Header))
|
||||
return IL_FALSE;
|
||||
if (!iCheckFits(&Header))
|
||||
return IL_FALSE;
|
||||
|
||||
if (!ilTexImage(Header.Width, Header.Height, Header.Depth, Header.NumChans, Header.Format, Header.Type, NULL))
|
||||
return IL_FALSE;
|
||||
|
||||
/*if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData)
|
||||
return IL_FALSE;*/
|
||||
|
||||
NumPix = Header.Width * Header.Height * Header.Depth;
|
||||
//@TODO: Do some checks while reading to see if we have hit the end of the file.
|
||||
switch (Header.Type)
|
||||
{
|
||||
case IL_UNSIGNED_BYTE:
|
||||
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData)
|
||||
return IL_FALSE;
|
||||
break;
|
||||
case IL_SHORT:
|
||||
for (i = 0; i < NumPix; i++) {
|
||||
((ILshort*)iCurImage->Data)[i] = GetBigShort();
|
||||
}
|
||||
break;
|
||||
case IL_INT:
|
||||
for (i = 0; i < NumPix; i++) {
|
||||
((ILint*)iCurImage->Data)[i] = GetBigInt();
|
||||
}
|
||||
break;
|
||||
case IL_FLOAT:
|
||||
for (i = 0; i < NumPix; i++) {
|
||||
((ILfloat*)iCurImage->Data)[i] = GetBigFloat();
|
||||
if (((ILfloat*)iCurImage->Data)[i] > MaxF)
|
||||
MaxF = ((ILfloat*)iCurImage->Data)[i];
|
||||
}
|
||||
|
||||
// Renormalize to [0..1].
|
||||
for (i = 0; i < NumPix; i++) {
|
||||
// Change all negative numbers to 0.
|
||||
if (((ILfloat*)iCurImage->Data)[i] < 0.0f)
|
||||
((ILfloat*)iCurImage->Data)[i] = 0.0f;
|
||||
// Do the renormalization now, dividing by the maximum value.
|
||||
((ILfloat*)iCurImage->Data)[i] = ((ILfloat*)iCurImage->Data)[i] / MaxF;
|
||||
}
|
||||
break;
|
||||
case IL_DOUBLE:
|
||||
for (i = 0; i < NumPix; i++) {
|
||||
((ILdouble*)iCurImage->Data)[i] = GetBigDouble();
|
||||
if (((ILdouble*)iCurImage->Data)[i] > MaxD)
|
||||
MaxD = ((ILdouble*)iCurImage->Data)[i];
|
||||
}
|
||||
|
||||
// Renormalize to [0..1].
|
||||
for (i = 0; i < NumPix; i++) {
|
||||
// Change all negative numbers to 0.
|
||||
if (((ILdouble*)iCurImage->Data)[i] < 0.0f)
|
||||
((ILdouble*)iCurImage->Data)[i] = 0.0f;
|
||||
// Do the renormalization now, dividing by the maximum value.
|
||||
((ILdouble*)iCurImage->Data)[i] = ((ILdouble*)iCurImage->Data)[i] / MaxD;
|
||||
} break;
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
//@TODO: NAXISx have to come in order. Check this!
|
||||
ILenum GetCardImage(FITSHEAD *Header)
|
||||
{
|
||||
char Buffer[80];
|
||||
|
||||
if (iread(Buffer, 1, 80) != 80) // Each card image is exactly 80 bytes long.
|
||||
return CARD_READ_FAIL;
|
||||
|
||||
//@TODO: Use something other than !strncmp?
|
||||
if (!strncmp(Buffer, "END ", 4))
|
||||
return CARD_END;
|
||||
|
||||
else if (!strncmp(Buffer, "SIMPLE ", 7)) {
|
||||
// The true value 'T' is always in the 30th position.
|
||||
if (Buffer[29] != 'T') {
|
||||
// We cannot support FITS files that do not correspond to the standard.
|
||||
Header->IsSimple = IL_FALSE; //@TODO: Does this even need to be set? Should exit loading anyway.
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return CARD_NOT_SIMPLE;
|
||||
}
|
||||
Header->IsSimple = IL_TRUE;
|
||||
return CARD_SIMPLE;
|
||||
}
|
||||
|
||||
else if (!strncmp(Buffer, "BITPIX ", 7)) {
|
||||
// The specs state that BITPIX has to come after SIMPLE.
|
||||
if (Header->IsSimple != IL_TRUE) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return CARD_READ_FAIL;
|
||||
}
|
||||
if (GetCardInt(Buffer, &Header->BitsPixel) != IL_TRUE)
|
||||
return CARD_READ_FAIL;
|
||||
//@TODO: Should I do this check from the calling function? Does it really matter?
|
||||
if (Header->BitsPixel == 0) {
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return CARD_READ_FAIL;
|
||||
}
|
||||
return CARD_BITPIX;
|
||||
}
|
||||
|
||||
// Needs the space after NAXIS so that it does not get this confused with NAXIS1, NAXIS2, etc.
|
||||
else if (!strncmp(Buffer, "NAXIS ", 6)) {
|
||||
if (GetCardInt(Buffer, &Header->NumAxes) != IL_TRUE)
|
||||
return CARD_READ_FAIL;
|
||||
//@TODO: Should I do this check from the calling function? Does it really matter?
|
||||
if (Header->NumAxes < 1 || Header->NumAxes > 3) {
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return CARD_READ_FAIL;
|
||||
}
|
||||
return CARD_NUMAXES;
|
||||
}
|
||||
|
||||
else if (!strncmp(Buffer, "NAXIS1 ", 7)) {
|
||||
if (Header->NumAxes == 0) { // Has not been initialized, and it has to come first.
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return CARD_READ_FAIL;
|
||||
}
|
||||
// First one will always be the width.
|
||||
if (GetCardInt(Buffer, &Header->Width) != IL_TRUE)
|
||||
return CARD_READ_FAIL;
|
||||
return CARD_AXIS;
|
||||
}
|
||||
|
||||
else if (!strncmp(Buffer, "NAXIS2 ", 7)) {
|
||||
if (Header->NumAxes == 0) { // Has not been initialized, and it has to come first.
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return CARD_READ_FAIL;
|
||||
}
|
||||
// Cannot have a 2nd axis for 0 or 1.
|
||||
if (Header->NumAxes == 0 || Header->NumAxes == 1) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return CARD_READ_FAIL;
|
||||
}
|
||||
|
||||
//@TODO: We are assuming that this is the height right now. Could it just be a
|
||||
// 1D image with multiple bytes per pixel?
|
||||
if (GetCardInt(Buffer, &Header->Height) != IL_TRUE)
|
||||
return CARD_READ_FAIL;
|
||||
return CARD_AXIS;
|
||||
}
|
||||
|
||||
else if (!strncmp(Buffer, "NAXIS3 ", 7)) {
|
||||
if (Header->NumAxes == 0) { // Has not been initialized, and it has to come first.
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return CARD_READ_FAIL;
|
||||
}
|
||||
// Cannot have a 3rd axis for 0, 1 and 2.
|
||||
if (Header->NumAxes < 3) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return CARD_READ_FAIL;
|
||||
}
|
||||
|
||||
if (GetCardInt(Buffer, &Header->Depth) != IL_TRUE)
|
||||
return CARD_READ_FAIL;
|
||||
return CARD_AXIS;
|
||||
}
|
||||
|
||||
return CARD_SKIP; // This is a card that we do not recognize, so skip it.
|
||||
}
|
||||
|
||||
|
||||
ILboolean GetCardInt(char *Buffer, ILint *Val)
|
||||
{
|
||||
ILuint i;
|
||||
char ValString[22];
|
||||
|
||||
if (Buffer[7] != '=' && Buffer[8] != '=')
|
||||
return IL_FALSE;
|
||||
for (i = 9; i < 30; i++) {
|
||||
if (Buffer[i] != ' ' && Buffer[i] != 0) // Right-aligned with ' ' or 0, so skip.
|
||||
break;
|
||||
}
|
||||
if (i == 30) // Did not find the integer in positions 10 - 30.
|
||||
return IL_FALSE;
|
||||
|
||||
//@TODO: Safest way to do this?
|
||||
memcpy(ValString, &Buffer[i], 30-i);
|
||||
ValString[30-i] = 0; // Terminate the string.
|
||||
|
||||
//@TODO: Check the return somehow?
|
||||
*Val = atoi(ValString);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
#endif//IL_NO_FITS
|
||||
@@ -0,0 +1,101 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 02/12/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_ftx.c
|
||||
//
|
||||
// Description: Reads from a Heavy Metal: FAKK2 (.ftx) file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_FTX
|
||||
|
||||
ILboolean iLoadFtxInternal(void);
|
||||
|
||||
|
||||
//! Reads a FTX file
|
||||
ILboolean ilLoadFtx(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE FtxFile;
|
||||
ILboolean bFtx = IL_FALSE;
|
||||
|
||||
FtxFile = iopenr(FileName);
|
||||
if (FtxFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bFtx;
|
||||
}
|
||||
|
||||
bFtx = ilLoadFtxF(FtxFile);
|
||||
icloser(FtxFile);
|
||||
|
||||
return bFtx;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened FTX file
|
||||
ILboolean ilLoadFtxF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadFtxInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a FTX
|
||||
ILboolean ilLoadFtxL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadFtxInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the FTX.
|
||||
ILboolean iLoadFtxInternal(void)
|
||||
{
|
||||
ILuint Width, Height, HasAlpha;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Width = GetLittleUInt();
|
||||
Height = GetLittleUInt();
|
||||
HasAlpha = GetLittleUInt(); // Kind of backwards from what I would think...
|
||||
|
||||
//@TODO: Right now, it appears that all images are in RGBA format. See if I can find specs otherwise
|
||||
// or images that load incorrectly like this.
|
||||
//if (HasAlpha == 0) { // RGBA format
|
||||
if (!ilTexImage(Width, Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
//}
|
||||
//else if (HasAlpha == 1) { // RGB format
|
||||
// if (!ilTexImage(Width, Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
|
||||
// return IL_FALSE;
|
||||
//}
|
||||
//else { // Unknown format
|
||||
// ilSetError(IL_INVALID_FILE_HEADER);
|
||||
// return IL_FALSE;
|
||||
//}
|
||||
|
||||
// The origin will always be in the upper left.
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
// All we have to do for this format is read the raw, uncompressed data.
|
||||
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) != iCurImage->SizeOfData)
|
||||
return IL_FALSE;
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
#endif//IL_NO_FTX
|
||||
|
||||
@@ -0,0 +1,755 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2008 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_gif.c
|
||||
//
|
||||
// Description: Reads from a Graphics Interchange Format (.gif) file.
|
||||
//
|
||||
// The LZW decompression code is based on code released to the public domain
|
||||
// by Javier Arevalo and can be found at
|
||||
// http://www.programmersheaven.com/zone10/cat452
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_GIF
|
||||
|
||||
#include "il_gif.h"
|
||||
|
||||
|
||||
ILenum GifType;
|
||||
|
||||
//! Checks if the file specified in FileName is a valid Gif file.
|
||||
ILboolean ilIsValidGif(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE GifFile;
|
||||
ILboolean bGif = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("gif"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bGif;
|
||||
}
|
||||
|
||||
GifFile = iopenr(FileName);
|
||||
if (GifFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bGif;
|
||||
}
|
||||
|
||||
bGif = ilIsValidGifF(GifFile);
|
||||
icloser(GifFile);
|
||||
|
||||
return bGif;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid Gif file at the current position.
|
||||
ILboolean ilIsValidGifF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidGif();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid Gif lump.
|
||||
ILboolean ilIsValidGifL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidGif();
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidGif()
|
||||
{
|
||||
char Header[6];
|
||||
|
||||
if (iread(Header, 1, 6) != 6)
|
||||
return IL_FALSE;
|
||||
iseek(-6, IL_SEEK_CUR);
|
||||
|
||||
if (!strnicmp(Header, "GIF87A", 6))
|
||||
return IL_TRUE;
|
||||
if (!strnicmp(Header, "GIF89A", 6))
|
||||
return IL_TRUE;
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a Gif file
|
||||
ILboolean ilLoadGif(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE GifFile;
|
||||
ILboolean bGif = IL_FALSE;
|
||||
|
||||
GifFile = iopenr(FileName);
|
||||
if (GifFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bGif;
|
||||
}
|
||||
|
||||
bGif = ilLoadGifF(GifFile);
|
||||
icloser(GifFile);
|
||||
|
||||
return bGif;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened Gif file
|
||||
ILboolean ilLoadGifF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadGifInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a Gif
|
||||
ILboolean ilLoadGifL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadGifInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the Gif.
|
||||
ILboolean iLoadGifInternal()
|
||||
{
|
||||
GIFHEAD Header;
|
||||
ILpal GlobalPal;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
GlobalPal.Palette = NULL;
|
||||
GlobalPal.PalSize = 0;
|
||||
|
||||
//read header
|
||||
iread(&Header.Sig, 1, 6);
|
||||
Header.Width = GetLittleUShort();
|
||||
Header.Height = GetLittleUShort();
|
||||
Header.ColourInfo = igetc();
|
||||
Header.Background = igetc();
|
||||
Header.Aspect = igetc();
|
||||
|
||||
if (!strnicmp(Header.Sig, "GIF87A", 6)) {
|
||||
GifType = GIF87A;
|
||||
}
|
||||
else if (!strnicmp(Header.Sig, "GIF89A", 6)) {
|
||||
GifType = GIF89A;
|
||||
}
|
||||
else {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
// Check for a global colour map.
|
||||
if (Header.ColourInfo & (1 << 7)) {
|
||||
if (!iGetPalette(Header.ColourInfo, &GlobalPal, IL_FALSE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!GetImages(&GlobalPal, &Header))
|
||||
return IL_FALSE;
|
||||
|
||||
if (GlobalPal.Palette && GlobalPal.PalSize)
|
||||
ifree(GlobalPal.Palette);
|
||||
GlobalPal.Palette = NULL;
|
||||
GlobalPal.PalSize = 0;
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iGetPalette(ILubyte Info, ILpal *Pal, ILboolean UsePrevPal, ILimage *PrevImage)
|
||||
{
|
||||
ILuint PalSize, PalOffset = 0;
|
||||
|
||||
// If we have a local palette and have to use the previous frame as well,
|
||||
// we have to copy the palette from the previous frame, in addition
|
||||
// to the data, which we copy in GetImages.
|
||||
|
||||
// The ld(palettes bpp - 1) is stored in the lower
|
||||
// 3 bits of Info (weird gif format ... :) )
|
||||
PalSize = (1 << ((Info & 0x7) + 1)) * 3;
|
||||
if (UsePrevPal) {
|
||||
if (PrevImage == NULL) { // Cannot use the previous palette if it does not exist.
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
PalSize = PalSize + PrevImage->Pal.PalSize;
|
||||
PalOffset = PrevImage->Pal.PalSize;
|
||||
}
|
||||
if (PalSize > 256 * 3) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
Pal->PalSize = PalSize;
|
||||
|
||||
Pal->PalType = IL_PAL_RGB24;
|
||||
//Pal->Palette = (ILubyte*)ialloc(Pal->PalSize);
|
||||
Pal->Palette = (ILubyte*)ialloc(256 * 3);
|
||||
if (Pal->Palette == NULL)
|
||||
return IL_FALSE;
|
||||
if (UsePrevPal)
|
||||
memcpy(Pal->Palette, PrevImage->Pal.Palette, PrevImage->Pal.PalSize); // Copy the old palette over.
|
||||
if (iread(Pal->Palette + PalOffset, 1, Pal->PalSize) != Pal->PalSize) { // Read the new palette.
|
||||
ifree(Pal->Palette);
|
||||
Pal->Palette = NULL;
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean GetImages(ILpal *GlobalPal, GIFHEAD *GifHead)
|
||||
{
|
||||
IMAGEDESC ImageDesc, OldImageDesc;
|
||||
GFXCONTROL Gfx;
|
||||
ILboolean BaseImage = IL_TRUE;
|
||||
ILimage *Image = iCurImage, *TempImage = NULL, *PrevImage = NULL;
|
||||
ILuint NumImages = 0, i;
|
||||
ILint input;
|
||||
ILuint PalOffset;
|
||||
|
||||
OldImageDesc.ImageInfo = 0; // to initialize the data with an harmless value
|
||||
Gfx.Used = IL_TRUE;
|
||||
|
||||
while (!ieof()) {
|
||||
ILubyte DisposalMethod = 1;
|
||||
|
||||
i = itell();
|
||||
if (!SkipExtensions(&Gfx))
|
||||
goto error_clean;
|
||||
i = itell();
|
||||
|
||||
if (!Gfx.Used)
|
||||
DisposalMethod = (Gfx.Packed & 0x1C) >> 2;
|
||||
|
||||
//read image descriptor
|
||||
ImageDesc.Separator = igetc();
|
||||
if (ImageDesc.Separator != 0x2C) //end of image
|
||||
break;
|
||||
ImageDesc.OffX = GetLittleUShort();
|
||||
ImageDesc.OffY = GetLittleUShort();
|
||||
ImageDesc.Width = GetLittleUShort();
|
||||
ImageDesc.Height = GetLittleUShort();
|
||||
ImageDesc.ImageInfo = igetc();
|
||||
|
||||
if (ieof()) {
|
||||
ilGetError(); // Gets rid of the IL_FILE_READ_ERROR that inevitably results.
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!BaseImage) {
|
||||
NumImages++;
|
||||
Image->Next = ilNewImage(iCurImage->Width, iCurImage->Height, 1, 1, 1);
|
||||
if (Image->Next == NULL)
|
||||
goto error_clean;
|
||||
//20040612: DisposalMethod controls how the new images data is to be combined
|
||||
//with the old image. 0 means that it doesn't matter how they are combined,
|
||||
//1 means keep the old image, 2 means set to background color, 3 is
|
||||
//load the image that was in place before the current (this is not implemented
|
||||
//here! (TODO?))
|
||||
if (DisposalMethod == 2 || DisposalMethod == 3)
|
||||
//Note that this is actually wrong, too: If the image has a local
|
||||
//color table, we should really search for the best fit of the
|
||||
//background color table and use that index (?). Furthermore,
|
||||
//we should only memset the part of the image that is not read
|
||||
//later (if we are sure that no parts of the read image are transparent).
|
||||
if (!Gfx.Used && Gfx.Packed & 0x1)
|
||||
memset(Image->Next->Data, Gfx.Transparent, Image->SizeOfData);
|
||||
else
|
||||
memset(Image->Next->Data, GifHead->Background, Image->SizeOfData);
|
||||
else if (DisposalMethod == 1 || DisposalMethod == 0)
|
||||
memcpy(Image->Next->Data, Image->Data, Image->SizeOfData);
|
||||
//Interlacing has to be removed after the image was copied (line above)
|
||||
if (OldImageDesc.ImageInfo & (1 << 6)) { // Image is interlaced.
|
||||
if (!RemoveInterlace(Image))
|
||||
goto error_clean;
|
||||
}
|
||||
|
||||
PrevImage = Image;
|
||||
Image = Image->Next;
|
||||
Image->Format = IL_COLOUR_INDEX;
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
} else {
|
||||
BaseImage = IL_FALSE;
|
||||
if (!Gfx.Used && Gfx.Packed & 0x1)
|
||||
memset(Image->Data, Gfx.Transparent, Image->SizeOfData);
|
||||
else
|
||||
memset(Image->Data, GifHead->Background, Image->SizeOfData);
|
||||
}
|
||||
|
||||
Image->OffX = ImageDesc.OffX;
|
||||
Image->OffY = ImageDesc.OffY;
|
||||
PalOffset = 0;
|
||||
|
||||
// Check to see if the image has its own palette.
|
||||
if (ImageDesc.ImageInfo & (1 << 7)) {
|
||||
ILboolean UsePrevPal = IL_FALSE;
|
||||
if (DisposalMethod == 1 && NumImages != 0) { // Cannot be the first image for this.
|
||||
PalOffset = PrevImage->Pal.PalSize;
|
||||
UsePrevPal = IL_TRUE;
|
||||
}
|
||||
if (!iGetPalette(ImageDesc.ImageInfo, &Image->Pal, UsePrevPal, PrevImage)) {
|
||||
goto error_clean;
|
||||
}
|
||||
} else {
|
||||
if (!iCopyPalette(&Image->Pal, GlobalPal)) {
|
||||
goto error_clean;
|
||||
}
|
||||
}
|
||||
|
||||
if (!GifGetData(Image, Image->Data + ImageDesc.OffX + ImageDesc.OffY*Image->Width, Image->SizeOfData,
|
||||
ImageDesc.Width, ImageDesc.Height, Image->Width, PalOffset, &Gfx)) {
|
||||
memset(Image->Data, 0, Image->SizeOfData); //@TODO: Remove this. For debugging purposes right now.
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
goto error_clean;
|
||||
}
|
||||
|
||||
// See if there was a valid graphics control extension.
|
||||
if (!Gfx.Used) {
|
||||
Gfx.Used = IL_TRUE;
|
||||
Image->Duration = Gfx.Delay * 10; // We want it in milliseconds.
|
||||
|
||||
// See if a transparent colour is defined.
|
||||
if (Gfx.Packed & 1) {
|
||||
if (!ConvertTransparent(Image, Gfx.Transparent)) {
|
||||
goto error_clean;
|
||||
}
|
||||
}
|
||||
}
|
||||
i = itell();
|
||||
// Terminates each block.
|
||||
if((input = igetc()) == IL_EOF)
|
||||
goto error_clean;
|
||||
|
||||
if (input != 0x00)
|
||||
iseek(-1, IL_SEEK_CUR);
|
||||
// break;
|
||||
|
||||
OldImageDesc = ImageDesc;
|
||||
}
|
||||
|
||||
//Deinterlace last image
|
||||
if (OldImageDesc.ImageInfo & (1 << 6)) { // Image is interlaced.
|
||||
if (!RemoveInterlace(Image))
|
||||
goto error_clean;
|
||||
}
|
||||
|
||||
if (BaseImage) // Was not able to load any images in...
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
|
||||
error_clean:
|
||||
Image = iCurImage->Next;
|
||||
/* while (Image) {
|
||||
TempImage = Image;
|
||||
Image = Image->Next;
|
||||
ilCloseImage(TempImage);
|
||||
}*/
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean SkipExtensions(GFXCONTROL *Gfx)
|
||||
{
|
||||
ILint Code;
|
||||
ILint Label;
|
||||
ILint Size;
|
||||
|
||||
// DW (06-03-2002): Apparently there can be...
|
||||
//if (GifType == GIF87A)
|
||||
// return IL_TRUE; // No extensions in the GIF87a format.
|
||||
|
||||
do {
|
||||
if((Code = igetc()) == IL_EOF)
|
||||
return IL_FALSE;
|
||||
|
||||
if (Code != 0x21) {
|
||||
iseek(-1, IL_SEEK_CUR);
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
if((Label = igetc()) == IL_EOF)
|
||||
return IL_FALSE;
|
||||
|
||||
switch (Label)
|
||||
{
|
||||
case 0xF9:
|
||||
Gfx->Size = igetc();
|
||||
Gfx->Packed = igetc();
|
||||
Gfx->Delay = GetLittleUShort();
|
||||
Gfx->Transparent = igetc();
|
||||
Gfx->Terminator = igetc();
|
||||
if (ieof())
|
||||
return IL_FALSE;
|
||||
Gfx->Used = IL_FALSE;
|
||||
break;
|
||||
/*case 0xFE:
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
break;*/
|
||||
default:
|
||||
do {
|
||||
if((Size = igetc()) == IL_EOF)
|
||||
return IL_FALSE;
|
||||
iseek(Size, IL_SEEK_CUR);
|
||||
} while (!ieof() && Size != 0);
|
||||
}
|
||||
|
||||
// @TODO: Handle this better.
|
||||
if (ieof()) {
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
#define MAX_CODES 4096
|
||||
|
||||
ILint curr_size, clear, ending, newcodes, top_slot, slot, navail_bytes = 0, nbits_left = 0;
|
||||
ILubyte b1;
|
||||
ILubyte byte_buff[257];
|
||||
ILubyte *pbytes;
|
||||
ILubyte *stack;
|
||||
ILubyte *suffix;
|
||||
ILshort *prefix;
|
||||
|
||||
ILboolean success;
|
||||
|
||||
ILuint code_mask[13] =
|
||||
{
|
||||
0L,
|
||||
0x0001L, 0x0003L,
|
||||
0x0007L, 0x000FL,
|
||||
0x001FL, 0x003FL,
|
||||
0x007FL, 0x00FFL,
|
||||
0x01FFL, 0x03FFL,
|
||||
0x07FFL, 0x0FFFL
|
||||
};
|
||||
|
||||
|
||||
ILint get_next_code(void) {
|
||||
ILint i, t;
|
||||
ILuint ret;
|
||||
|
||||
//20050102: Tests for IL_EOF were added because this function
|
||||
//crashed sometimes if igetc() returned IL_EOF
|
||||
//(for example "table-add-column-before-active.gif" included in the
|
||||
//mozilla source package)
|
||||
|
||||
if (!nbits_left) {
|
||||
if (navail_bytes <= 0) {
|
||||
pbytes = byte_buff;
|
||||
navail_bytes = igetc();
|
||||
|
||||
if(navail_bytes == IL_EOF) {
|
||||
success = IL_FALSE;
|
||||
return ending;
|
||||
}
|
||||
|
||||
if (navail_bytes) {
|
||||
for (i = 0; i < navail_bytes; i++) {
|
||||
if((t = igetc()) == IL_EOF) {
|
||||
success = IL_FALSE;
|
||||
return ending;
|
||||
}
|
||||
byte_buff[i] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
b1 = *pbytes++;
|
||||
nbits_left = 8;
|
||||
navail_bytes--;
|
||||
}
|
||||
|
||||
ret = b1 >> (8 - nbits_left);
|
||||
while (curr_size > nbits_left) {
|
||||
if (navail_bytes <= 0) {
|
||||
pbytes = byte_buff;
|
||||
navail_bytes = igetc();
|
||||
|
||||
if(navail_bytes == IL_EOF) {
|
||||
success = IL_FALSE;
|
||||
return ending;
|
||||
}
|
||||
|
||||
if (navail_bytes) {
|
||||
for (i = 0; i < navail_bytes; i++) {
|
||||
if((t = igetc()) == IL_EOF) {
|
||||
success = IL_FALSE;
|
||||
return ending;
|
||||
}
|
||||
byte_buff[i] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
b1 = *pbytes++;
|
||||
ret |= b1 << nbits_left;
|
||||
nbits_left += 8;
|
||||
navail_bytes--;
|
||||
}
|
||||
nbits_left -= curr_size;
|
||||
|
||||
return (ret & code_mask[curr_size]);
|
||||
}
|
||||
|
||||
static void cleanUpGifLoadState()
|
||||
{
|
||||
ifree(stack);
|
||||
ifree(suffix);
|
||||
ifree(prefix);
|
||||
|
||||
}
|
||||
|
||||
ILboolean GifGetData(ILimage *Image, ILubyte *Data, ILuint ImageSize, ILuint Width, ILuint Height, ILuint Stride, ILuint PalOffset, GFXCONTROL *Gfx)
|
||||
{
|
||||
ILubyte *sp;
|
||||
ILint code, fc, oc;
|
||||
ILubyte DisposalMethod = 0;
|
||||
ILint c, size;
|
||||
ILuint i = 0, Read = 0, j = 0;
|
||||
ILubyte *DataPtr = Data;
|
||||
|
||||
if (!Gfx->Used)
|
||||
DisposalMethod = (Gfx->Packed & 0x1C) >> 2;
|
||||
if((size = igetc()) == IL_EOF)
|
||||
return IL_FALSE;
|
||||
|
||||
if (size < 2 || 9 < size) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
stack = (ILubyte*)ialloc(MAX_CODES + 1);
|
||||
suffix = (ILubyte*)ialloc(MAX_CODES + 1);
|
||||
prefix = (ILshort*)ialloc(sizeof(*prefix) * (MAX_CODES + 1));
|
||||
if (!stack || !suffix || !prefix)
|
||||
{
|
||||
cleanUpGifLoadState();
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
curr_size = size + 1;
|
||||
top_slot = 1 << curr_size;
|
||||
clear = 1 << size;
|
||||
ending = clear + 1;
|
||||
slot = newcodes = ending + 1;
|
||||
navail_bytes = nbits_left = 0;
|
||||
oc = fc = 0;
|
||||
sp = stack;
|
||||
|
||||
while ((c = get_next_code()) != ending && Read < Height) {
|
||||
if (c == clear)
|
||||
{
|
||||
curr_size = size + 1;
|
||||
slot = newcodes;
|
||||
top_slot = 1 << curr_size;
|
||||
while ((c = get_next_code()) == clear);
|
||||
if (c == ending)
|
||||
break;
|
||||
if (c >= slot)
|
||||
c = 0;
|
||||
oc = fc = c;
|
||||
|
||||
if (DisposalMethod == 1 && !Gfx->Used && Gfx->Transparent == c && (Gfx->Packed & 0x1) != 0)
|
||||
i++;
|
||||
else if (i < Width)
|
||||
DataPtr[i++] = c + PalOffset;
|
||||
|
||||
if (i == Width)
|
||||
{
|
||||
DataPtr += Stride;
|
||||
i = 0;
|
||||
Read += 1;
|
||||
++j;
|
||||
if (j >= Height) {
|
||||
cleanUpGifLoadState();
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
code = c;
|
||||
//BG-2007-01-10: several fixes for incomplete GIFs
|
||||
if (code >= slot)
|
||||
{
|
||||
code = oc;
|
||||
if (sp >= stack + MAX_CODES) {
|
||||
cleanUpGifLoadState();
|
||||
return IL_FALSE;
|
||||
}
|
||||
*sp++ = fc;
|
||||
}
|
||||
|
||||
if (code >= MAX_CODES)
|
||||
return IL_FALSE;
|
||||
while (code >= newcodes)
|
||||
{
|
||||
if (sp >= stack + MAX_CODES)
|
||||
{
|
||||
cleanUpGifLoadState();
|
||||
return IL_FALSE;
|
||||
}
|
||||
*sp++ = suffix[code];
|
||||
code = prefix[code];
|
||||
}
|
||||
|
||||
if (sp >= stack + MAX_CODES) {
|
||||
cleanUpGifLoadState();
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
*sp++ = (ILbyte)code;
|
||||
if (slot < top_slot)
|
||||
{
|
||||
fc = code;
|
||||
suffix[slot] = fc;
|
||||
prefix[slot++] = oc;
|
||||
oc = c;
|
||||
}
|
||||
if (slot >= top_slot && curr_size < 12)
|
||||
{
|
||||
top_slot <<= 1;
|
||||
curr_size++;
|
||||
}
|
||||
while (sp > stack)
|
||||
{
|
||||
sp--;
|
||||
if (DisposalMethod == 1 && !Gfx->Used && Gfx->Transparent == *sp && (Gfx->Packed & 0x1) != 0)
|
||||
i++;
|
||||
else if (i < Width)
|
||||
DataPtr[i++] = *sp + PalOffset;
|
||||
|
||||
if (i == Width)
|
||||
{
|
||||
i = 0;
|
||||
Read += 1;
|
||||
j = (j+1) % Height;
|
||||
// Needs to start from Data, not Image->Data.
|
||||
DataPtr = Data + j * Stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanUpGifLoadState();
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*From the GIF spec:
|
||||
|
||||
The rows of an Interlaced images are arranged in the following order:
|
||||
|
||||
Group 1 : Every 8th. row, starting with row 0. (Pass 1)
|
||||
Group 2 : Every 8th. row, starting with row 4. (Pass 2)
|
||||
Group 3 : Every 4th. row, starting with row 2. (Pass 3)
|
||||
Group 4 : Every 2nd. row, starting with row 1. (Pass 4)
|
||||
*/
|
||||
|
||||
ILboolean RemoveInterlace(ILimage *image)
|
||||
{
|
||||
ILubyte *NewData;
|
||||
ILuint i, j = 0;
|
||||
|
||||
NewData = (ILubyte*)ialloc(image->SizeOfData);
|
||||
if (NewData == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
//changed 20041230: images with offsety != 0 were not
|
||||
//deinterlaced correctly before...
|
||||
for (i = 0; i < image->OffY; i++, j++) {
|
||||
memcpy(&NewData[i * image->Bps], &image->Data[j * image->Bps], image->Bps);
|
||||
}
|
||||
|
||||
for (i = 0 + image->OffY; i < image->Height; i += 8, j++) {
|
||||
memcpy(&NewData[i * image->Bps], &image->Data[j * image->Bps], image->Bps);
|
||||
}
|
||||
|
||||
for (i = 4 + image->OffY; i < image->Height; i += 8, j++) {
|
||||
memcpy(&NewData[i * image->Bps], &image->Data[j * image->Bps], image->Bps);
|
||||
}
|
||||
|
||||
for (i = 2 + image->OffY; i < image->Height; i += 4, j++) {
|
||||
memcpy(&NewData[i * image->Bps], &image->Data[j * image->Bps], image->Bps);
|
||||
}
|
||||
|
||||
for (i = 1 + image->OffY; i < image->Height; i += 2, j++) {
|
||||
memcpy(&NewData[i * image->Bps], &image->Data[j * image->Bps], image->Bps);
|
||||
}
|
||||
|
||||
ifree(image->Data);
|
||||
image->Data = NewData;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Uses the transparent colour index to make an alpha channel.
|
||||
ILboolean ConvertTransparent(ILimage *Image, ILubyte TransColour)
|
||||
{
|
||||
ILubyte *Palette;
|
||||
ILuint i, j;
|
||||
|
||||
if (!Image->Pal.Palette || !Image->Pal.PalSize) {
|
||||
ilSetError(IL_INTERNAL_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Palette = (ILubyte*)ialloc(Image->Pal.PalSize / 3 * 4);
|
||||
if (Palette == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
for (i = 0, j = 0; i < Image->Pal.PalSize; i += 3, j += 4) {
|
||||
Palette[j ] = Image->Pal.Palette[i ];
|
||||
Palette[j+1] = Image->Pal.Palette[i+1];
|
||||
Palette[j+2] = Image->Pal.Palette[i+2];
|
||||
if (j/4 == TransColour)
|
||||
Palette[j+3] = 0x00;
|
||||
else
|
||||
Palette[j+3] = 0xFF;
|
||||
}
|
||||
|
||||
ifree(Image->Pal.Palette);
|
||||
Image->Pal.Palette = Palette;
|
||||
Image->Pal.PalSize = Image->Pal.PalSize / 3 * 4;
|
||||
Image->Pal.PalType = IL_PAL_RGBA32;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
#endif //IL_NO_GIF
|
||||
@@ -0,0 +1,659 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2008 by Denton Woods (this file by thakis / Denton)
|
||||
// Last modified: 02/09/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_hdr.c
|
||||
//
|
||||
// Description: Reads/writes a RADIANCE High Dynamic Range Image
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_HDR
|
||||
#include "il_hdr.h"
|
||||
#include "il_endian.h"
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid .hdr file.
|
||||
ILboolean ilIsValidHdr(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE HdrFile;
|
||||
ILboolean bHdr = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("hdr"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bHdr;
|
||||
}
|
||||
|
||||
HdrFile = iopenr(FileName);
|
||||
if (HdrFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bHdr;
|
||||
}
|
||||
|
||||
bHdr = ilIsValidHdrF(HdrFile);
|
||||
icloser(HdrFile);
|
||||
|
||||
return bHdr;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid .hdr file at the current position.
|
||||
ILboolean ilIsValidHdrF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidHdr();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid .hdr lump.
|
||||
ILboolean ilIsValidHdrL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidHdr();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the .hdr header from the current file.
|
||||
ILboolean iGetHdrHead(HDRHEADER *Header)
|
||||
{
|
||||
ILboolean done = IL_FALSE;
|
||||
char a, b;
|
||||
char x[3], y[3]; //changed 20050217: added space for the '\0' char
|
||||
char buff[81]; // 01-19-2009: Added space for the '\0'.
|
||||
ILuint count = 0;
|
||||
|
||||
iread(Header->Signature, 1, 10);
|
||||
|
||||
//skip lines until an empty line is found.
|
||||
//this marks the end of header information,
|
||||
//the next line contains the image's dimension.
|
||||
|
||||
//TODO: read header contents into variables
|
||||
//(EXPOSURE, orientation, xyz correction, ...)
|
||||
|
||||
if (iread(&a, 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
|
||||
while (!done) {
|
||||
if (iread(&b, 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
if (b == '\n' && a == '\n')
|
||||
done = IL_TRUE;
|
||||
else
|
||||
a = b;
|
||||
}
|
||||
|
||||
//read dimensions (note that this assumes a somewhat valid image)
|
||||
if (iread(&a, 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
while (a != '\n') {
|
||||
if (count >= 80) { // Line shouldn't be this long at all.
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
buff[count] = a;
|
||||
if (iread(&a, 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
++count;
|
||||
}
|
||||
buff[count] = '\0';
|
||||
|
||||
//note that this is not the 100% correct way to load hdr images:
|
||||
//in a perfect world we would check if there's a +/- X/Y in front
|
||||
//of width and heigth and mirror + rotate the image after decoding
|
||||
//according to that. But HDRShop doesn't do that either (and that's
|
||||
//my reference program :) ) and it's just a rotate and a mirror,
|
||||
//nothing that really changes the appearance of the loaded image...
|
||||
//(The code as it is now assumes that y contains "-Y" and x contains
|
||||
//"+X" after the following line)
|
||||
|
||||
// The 2 has to be in the %s format specifier to prevent buffer overruns.
|
||||
sscanf(buff, "%2s %d %2s %d", y, &Header->Height, x, &Header->Width);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidHdr()
|
||||
{
|
||||
char Head[10];
|
||||
ILint Read;
|
||||
|
||||
Read = iread(Head, 1, 10);
|
||||
iseek(-Read, IL_SEEK_CUR); // Go ahead and restore to previous state
|
||||
if (Read != 10)
|
||||
return IL_FALSE;
|
||||
|
||||
return
|
||||
strnicmp(Head, "#?RADIANCE", 10) == 0
|
||||
|| strnicmp(Head, "#?RGBE", 6) == 0;
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid .hdr header.
|
||||
ILboolean iCheckHdr(HDRHEADER *Header)
|
||||
{
|
||||
return
|
||||
strnicmp(Header->Signature, "#?RADIANCE", 10) == 0
|
||||
|| strnicmp(Header->Signature, "#?RGBE", 6) == 0;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a .hdr file
|
||||
ILboolean ilLoadHdr(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE HdrFile;
|
||||
ILboolean bHdr = IL_FALSE;
|
||||
|
||||
HdrFile = iopenr(FileName);
|
||||
if (HdrFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bHdr;
|
||||
}
|
||||
|
||||
bHdr = ilLoadHdrF(HdrFile);
|
||||
icloser(HdrFile);
|
||||
|
||||
return bHdr;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .hdr file
|
||||
ILboolean ilLoadHdrF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadHdrInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a .hdr
|
||||
ILboolean ilLoadHdrL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadHdrInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the .hdr.
|
||||
ILboolean iLoadHdrInternal()
|
||||
{
|
||||
HDRHEADER Header;
|
||||
ILfloat *data;
|
||||
ILubyte *scanline;
|
||||
ILuint i, j, e, r, g, b;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!iGetHdrHead(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (!iCheckHdr(&Header)) {
|
||||
//iseek(-(ILint)sizeof(HDRHEAD), IL_SEEK_CUR);
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Update the current image with the new dimensions
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_FLOAT, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
//read image data
|
||||
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
|
||||
iPreCache(iCurImage->Width / 8 * iCurImage->Height);
|
||||
|
||||
data = (ILfloat*)iCurImage->Data;
|
||||
scanline = (ILubyte*)ialloc(Header.Width*4);
|
||||
for (i = 0; i < Header.Height; ++i) {
|
||||
ReadScanline(scanline, Header.Width);
|
||||
|
||||
//convert hdrs internal format to floats
|
||||
for (j = 0; j < 4*Header.Width; j += 4) {
|
||||
ILuint *ee;
|
||||
ILfloat t, *ff;
|
||||
e = scanline[j + 3];
|
||||
r = scanline[j + 0];
|
||||
g = scanline[j + 1];
|
||||
b = scanline[j + 2];
|
||||
|
||||
//t = (float)pow(2.f, ((ILint)e) - 128);
|
||||
if (e != 0)
|
||||
e = (e - 1) << 23;
|
||||
|
||||
// All this just to avoid stric-aliasing warnings...
|
||||
// was: t = *(ILfloat*)&e
|
||||
ee = &e;
|
||||
ff = (ILfloat*)ee;
|
||||
t = *ff;
|
||||
|
||||
data[0] = (r/255.0f)*t;
|
||||
data[1] = (g/255.0f)*t;
|
||||
data[2] = (b/255.0f)*t;
|
||||
data += 3;
|
||||
}
|
||||
}
|
||||
iUnCache();
|
||||
ifree(scanline);
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
void ReadScanline(ILubyte *scanline, ILuint w) {
|
||||
ILubyte *runner;
|
||||
ILuint r, g, b, e, read, shift;
|
||||
|
||||
r = igetc();
|
||||
g = igetc();
|
||||
b = igetc();
|
||||
e = igetc();
|
||||
|
||||
//check if the scanline is in the new format
|
||||
//if so, e, r, g, g are stored separated and are
|
||||
//rle-compressed independently.
|
||||
if (r == 2 && g == 2) {
|
||||
ILuint length = (b << 8) | e;
|
||||
ILuint j, t, k;
|
||||
if (length > w)
|
||||
length = w; //fix broken files
|
||||
for (k = 0; k < 4; ++k) {
|
||||
runner = scanline + k;
|
||||
j = 0;
|
||||
while (j < length) {
|
||||
t = igetc();
|
||||
if (t > 128) { //Run?
|
||||
ILubyte val = igetc();
|
||||
t &= 127;
|
||||
//copy current byte
|
||||
while (t > 0 && j < length) {
|
||||
*runner = val;
|
||||
runner += 4;
|
||||
--t;
|
||||
++j;
|
||||
}
|
||||
}
|
||||
else { //No Run.
|
||||
//read new bytes
|
||||
while (t > 0 && j < length) {
|
||||
*runner = igetc();
|
||||
runner += 4;
|
||||
--t;
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return; //done decoding a scanline in separated format
|
||||
}
|
||||
|
||||
//if we come here, we are dealing with old-style scanlines
|
||||
shift = 0;
|
||||
read = 0;
|
||||
runner = scanline;
|
||||
while (read < w) {
|
||||
if (read != 0) {
|
||||
r = igetc();
|
||||
g = igetc();
|
||||
b = igetc();
|
||||
e = igetc();
|
||||
}
|
||||
|
||||
//if all three mantissas are 1, then this is a rle
|
||||
//count dword
|
||||
if (r == 1 && g == 1 && b == 1) {
|
||||
ILuint length = e;
|
||||
ILuint j;
|
||||
for (j = length << shift; j > 0 && read < w; --j) {
|
||||
memcpy(runner, runner - 4, 4);
|
||||
runner += 4;
|
||||
++read;
|
||||
}
|
||||
//if more than one rle count dword is read
|
||||
//consecutively, they are higher order bytes
|
||||
//of the first read value. shift keeps track of
|
||||
//that.
|
||||
shift += 8;
|
||||
}
|
||||
else {
|
||||
runner[0] = r;
|
||||
runner[1] = g;
|
||||
runner[2] = b;
|
||||
runner[3] = e;
|
||||
|
||||
shift = 0;
|
||||
runner += 4;
|
||||
++read;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Writes a Hdr file
|
||||
ILboolean ilSaveHdr(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE HdrFile;
|
||||
ILuint HdrSize;
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
HdrFile = iopenw(FileName);
|
||||
if (HdrFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
HdrSize = ilSaveHdrF(HdrFile);
|
||||
iclosew(HdrFile);
|
||||
|
||||
if (HdrSize == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Hdr to an already-opened file
|
||||
ILuint ilSaveHdrF(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputFile(File);
|
||||
Pos = itellw();
|
||||
if (iSaveHdrInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Hdr to a memory "lump"
|
||||
ILuint ilSaveHdrL(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputLump(Lump, Size);
|
||||
Pos = itellw();
|
||||
if (iSaveHdrInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Much of the saving code is based on the code by Bruce Walter,
|
||||
// available at http://www.graphics.cornell.edu/online/formats/rgbe/.
|
||||
//
|
||||
// The actual source code file is
|
||||
// http://www.graphics.cornell.edu/online/formats/rgbe/rgbe.c
|
||||
//
|
||||
|
||||
|
||||
/* standard conversion from float pixels to rgbe pixels */
|
||||
/* note: you can remove the "inline"s if your compiler complains about it */
|
||||
//static INLINE void
|
||||
static void
|
||||
float2rgbe(unsigned char rgbe[4], float red, float green, float blue)
|
||||
{
|
||||
float v;
|
||||
int e;
|
||||
|
||||
v = red;
|
||||
if (green > v) v = green;
|
||||
if (blue > v) v = blue;
|
||||
if (v < 1e-32) {
|
||||
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
|
||||
}
|
||||
else {
|
||||
v = (float)(frexp(v,&e) * 256.0/v);
|
||||
rgbe[0] = (unsigned char) (red * v);
|
||||
rgbe[1] = (unsigned char) (green * v);
|
||||
rgbe[2] = (unsigned char) (blue * v);
|
||||
rgbe[3] = (unsigned char) (e + 128);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
ILuint valid; /* indicate which fields are valid */
|
||||
ILbyte programtype[16]; /* listed at beginning of file to identify it
|
||||
* after "#?". defaults to "RGBE" */
|
||||
ILfloat gamma; /* image has already been gamma corrected with
|
||||
* given gamma. defaults to 1.0 (no correction) */
|
||||
ILfloat exposure; /* a value of 1.0 in an image corresponds to
|
||||
* <exposure> watts/steradian/m^2.
|
||||
* defaults to 1.0 */
|
||||
} rgbe_header_info;
|
||||
|
||||
/* flags indicating which fields in an rgbe_header_info are valid */
|
||||
#define RGBE_VALID_PROGRAMTYPE 0x01
|
||||
#define RGBE_VALID_GAMMA 0x02
|
||||
#define RGBE_VALID_EXPOSURE 0x04
|
||||
|
||||
/* offsets to red, green, and blue components in a data (float) pixel */
|
||||
#define RGBE_DATA_RED 0
|
||||
#define RGBE_DATA_GREEN 1
|
||||
#define RGBE_DATA_BLUE 2
|
||||
/* number of floats per pixel */
|
||||
#define RGBE_DATA_SIZE 3
|
||||
|
||||
|
||||
/* default minimal header. modify if you want more information in header */
|
||||
ILboolean RGBE_WriteHeader(ILuint width, ILuint height, rgbe_header_info *info)
|
||||
{
|
||||
char *programtype = "RGBE";
|
||||
|
||||
if (info && (info->valid & RGBE_VALID_PROGRAMTYPE))
|
||||
programtype = info->programtype;
|
||||
if (ilprintf("#?%s\n",programtype) < 0)
|
||||
return IL_FALSE;
|
||||
/* The #? is to identify file type, the programtype is optional. */
|
||||
if (info && (info->valid & RGBE_VALID_GAMMA)) {
|
||||
if (ilprintf("GAMMA=%g\n",info->gamma) < 0)
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (info && (info->valid & RGBE_VALID_EXPOSURE)) {
|
||||
if (ilprintf("EXPOSURE=%g\n",info->exposure) < 0)
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (ilprintf("FORMAT=32-bit_rle_rgbe\n\n") < 0)
|
||||
return IL_FALSE;
|
||||
if (ilprintf("-Y %d +X %d\n", height, width) < 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* simple write routine that does not use run length encoding */
|
||||
/* These routines can be made faster by allocating a larger buffer and
|
||||
fread-ing and iwrite-ing the data in larger chunks */
|
||||
int RGBE_WritePixels(float *data, int numpixels)
|
||||
{
|
||||
unsigned char rgbe[4];
|
||||
|
||||
while (numpixels-- > 0) {
|
||||
float2rgbe(rgbe,data[RGBE_DATA_RED],data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
|
||||
data += RGBE_DATA_SIZE;
|
||||
if (iwrite(rgbe, sizeof(rgbe), 1) < 1)
|
||||
return IL_FALSE;
|
||||
}
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* The code below is only needed for the run-length encoded files. */
|
||||
/* Run length encoding adds considerable complexity but does */
|
||||
/* save some space. For each scanline, each channel (r,g,b,e) is */
|
||||
/* encoded separately for better compression. */
|
||||
|
||||
ILboolean RGBE_WriteBytes_RLE(ILubyte *data, ILuint numbytes)
|
||||
{
|
||||
#define MINRUNLENGTH 4
|
||||
ILuint cur, beg_run, run_count, old_run_count, nonrun_count;
|
||||
ILubyte buf[2];
|
||||
|
||||
cur = 0;
|
||||
while (cur < numbytes) {
|
||||
beg_run = cur;
|
||||
/* find next run of length at least 4 if one exists */
|
||||
run_count = old_run_count = 0;
|
||||
while((run_count < MINRUNLENGTH) && (beg_run < numbytes)) {
|
||||
beg_run += run_count;
|
||||
old_run_count = run_count;
|
||||
run_count = 1;
|
||||
// 01-25-2009: Moved test for beg_run + run_count first so that it is
|
||||
// tested first. This keeps it from going out of bounds by 1.
|
||||
while((beg_run + run_count < numbytes) && (run_count < 127) &&
|
||||
(data[beg_run] == data[beg_run + run_count]))
|
||||
run_count++;
|
||||
}
|
||||
/* if data before next big run is a short run then write it as such */
|
||||
if ((old_run_count > 1)&&(old_run_count == beg_run - cur)) {
|
||||
buf[0] = 128 + old_run_count; /*write short run*/
|
||||
buf[1] = data[cur];
|
||||
if (iwrite(buf,sizeof(buf[0])*2,1) < 1)
|
||||
return IL_FALSE;
|
||||
cur = beg_run;
|
||||
}
|
||||
/* write out bytes until we reach the start of the next run */
|
||||
while(cur < beg_run) {
|
||||
nonrun_count = beg_run - cur;
|
||||
if (nonrun_count > 128)
|
||||
nonrun_count = 128;
|
||||
buf[0] = nonrun_count;
|
||||
if (iwrite(buf,sizeof(buf[0]),1) < 1)
|
||||
return IL_FALSE;
|
||||
if (iwrite(&data[cur],sizeof(data[0])*nonrun_count,1) < 1)
|
||||
return IL_FALSE;
|
||||
cur += nonrun_count;
|
||||
}
|
||||
/* write out next run if one was found */
|
||||
if (run_count >= MINRUNLENGTH) {
|
||||
buf[0] = 128 + run_count;
|
||||
buf[1] = data[beg_run];
|
||||
if (iwrite(buf,sizeof(buf[0])*2,1) < 1)
|
||||
return IL_FALSE;
|
||||
cur += run_count;
|
||||
}
|
||||
}
|
||||
return IL_TRUE;
|
||||
#undef MINRUNLENGTH
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to save the Hdr.
|
||||
ILboolean iSaveHdrInternal()
|
||||
{
|
||||
ILimage *TempImage;
|
||||
rgbe_header_info stHeader;
|
||||
unsigned char rgbe[4];
|
||||
ILubyte *buffer;
|
||||
ILfloat *data;
|
||||
ILuint i;
|
||||
ILboolean bRet;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
stHeader.exposure = 0;
|
||||
stHeader.gamma = 0;
|
||||
stHeader.programtype[0] = 0;
|
||||
stHeader.valid = 0;
|
||||
|
||||
if (iCurImage->Format != IL_UNSIGNED_BYTE) {
|
||||
TempImage = iConvertImage(iCurImage, IL_RGB, IL_FLOAT);
|
||||
if (TempImage == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
else
|
||||
TempImage = iCurImage;
|
||||
|
||||
if (!RGBE_WriteHeader(TempImage->Width, TempImage->Height, &stHeader))
|
||||
return IL_FALSE;
|
||||
|
||||
if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
|
||||
iFlipBuffer(TempImage->Data, TempImage->Depth, TempImage->Bps, TempImage->Height);
|
||||
data = (ILfloat*)TempImage->Data;
|
||||
|
||||
if ((TempImage->Width < 8)||(TempImage->Width > 0x7fff)) {
|
||||
/* run length encoding is not allowed so write flat*/
|
||||
bRet = RGBE_WritePixels(data,TempImage->Width*TempImage->Height);
|
||||
if (iCurImage != TempImage)
|
||||
ilCloseImage(TempImage);
|
||||
return bRet;
|
||||
}
|
||||
buffer = (ILubyte*)ialloc(sizeof(ILubyte)*4*TempImage->Width);
|
||||
if (buffer == NULL) {
|
||||
/* no buffer space so write flat */
|
||||
bRet = RGBE_WritePixels(data,TempImage->Width*TempImage->Height);
|
||||
if (iCurImage != TempImage)
|
||||
ilCloseImage(TempImage);
|
||||
return bRet;
|
||||
}
|
||||
|
||||
while(TempImage->Height-- > 0) {
|
||||
rgbe[0] = 2;
|
||||
rgbe[1] = 2;
|
||||
rgbe[2] = TempImage->Width >> 8;
|
||||
rgbe[3] = TempImage->Width & 0xFF;
|
||||
if (iwrite(rgbe, sizeof(rgbe), 1) < 1) {
|
||||
free(buffer);
|
||||
if (iCurImage != TempImage)
|
||||
ilCloseImage(TempImage);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
for(i=0;i<TempImage->Width;i++) {
|
||||
float2rgbe(rgbe,data[RGBE_DATA_RED],data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
|
||||
buffer[i] = rgbe[0];
|
||||
buffer[i+TempImage->Width] = rgbe[1];
|
||||
buffer[i+2*TempImage->Width] = rgbe[2];
|
||||
buffer[i+3*TempImage->Width] = rgbe[3];
|
||||
data += RGBE_DATA_SIZE;
|
||||
}
|
||||
/* write out each of the four channels separately run length encoded */
|
||||
/* first red, then green, then blue, then exponent */
|
||||
for(i=0;i<4;i++) {
|
||||
if (RGBE_WriteBytes_RLE(&buffer[i*TempImage->Width],TempImage->Width) != IL_TRUE) {
|
||||
ifree(buffer);
|
||||
if (iCurImage != TempImage)
|
||||
ilCloseImage(TempImage);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
ifree(buffer);
|
||||
|
||||
if (iCurImage != TempImage)
|
||||
ilCloseImage(TempImage);
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_HDR
|
||||
@@ -0,0 +1,135 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2008 by Denton Woods
|
||||
// Last modified: 10/10/2006
|
||||
//
|
||||
// Filename: src-IL/src/il_header.c
|
||||
//
|
||||
// Description: Generates a C-style header file for the current image.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef IL_NO_CHEAD
|
||||
|
||||
#include "il_internal.h"
|
||||
|
||||
// Just a guess...let's see what's purty!
|
||||
#define MAX_LINE_WIDTH 14
|
||||
|
||||
//! Generates a C-style header file for the current image.
|
||||
ILboolean ilSaveCHeader(ILconst_string FileName, char *InternalName)
|
||||
{
|
||||
FILE *HeadFile;
|
||||
ILuint i = 0, j;
|
||||
ILimage *TempImage;
|
||||
const char *Name;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Name = iGetString(IL_CHEAD_HEADER_STRING);
|
||||
if (Name == NULL)
|
||||
Name = InternalName;
|
||||
|
||||
if (FileName == NULL || Name == NULL ||
|
||||
ilStrLen(FileName) < 1 || ilCharStrLen(Name) < 1) {
|
||||
ilSetError(IL_INVALID_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("h"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (iCurImage->Bpc > 1) {
|
||||
TempImage = iConvertImage(iCurImage, iCurImage->Format, IL_UNSIGNED_BYTE);
|
||||
if (TempImage == NULL)
|
||||
return IL_FALSE;
|
||||
} else {
|
||||
TempImage = iCurImage;
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
HeadFile = fopen(FileName, "wb");
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
HeadFile = _wfopen(FileName, L"rb");
|
||||
#else
|
||||
HeadFile = fopen((char*)FileName, "rb");
|
||||
#endif
|
||||
|
||||
#endif//_UNICODE
|
||||
|
||||
if (HeadFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
fprintf(HeadFile, "//#include <il/il.h>\n");
|
||||
fprintf(HeadFile, "// C Image Header:\n\n\n");
|
||||
fprintf(HeadFile, "// IMAGE_BPP is in bytes per pixel, *not* bits\n");
|
||||
fprintf(HeadFile, "#define IMAGE_BPP %d\n",iCurImage->Bpp);
|
||||
fprintf(HeadFile, "#define IMAGE_WIDTH %d\n", iCurImage->Width);
|
||||
fprintf(HeadFile, "#define IMAGE_HEIGHT %d\n", iCurImage->Height);
|
||||
fprintf(HeadFile, "#define IMAGE_DEPTH %d\n\n\n", iCurImage->Depth);
|
||||
fprintf(HeadFile, "#define IMAGE_TYPE 0x%X\n", iCurImage->Type);
|
||||
fprintf(HeadFile, "#define IMAGE_FORMAT 0x%X\n\n\n", iCurImage->Format);
|
||||
fprintf(HeadFile, "ILubyte %s[] = {\n", Name);
|
||||
|
||||
|
||||
for (; i < TempImage->SizeOfData; i += MAX_LINE_WIDTH) {
|
||||
fprintf(HeadFile, "\t");
|
||||
for (j = 0; j < MAX_LINE_WIDTH; j++) {
|
||||
if (i + j >= TempImage->SizeOfData - 1) {
|
||||
fprintf(HeadFile, "%4d", TempImage->Data[i+j]);
|
||||
break;
|
||||
}
|
||||
else
|
||||
fprintf(HeadFile, "%4d,", TempImage->Data[i+j]);
|
||||
}
|
||||
fprintf(HeadFile, "\n");
|
||||
}
|
||||
if (TempImage != iCurImage)
|
||||
ilCloseImage(TempImage);
|
||||
|
||||
fprintf(HeadFile, "};\n");
|
||||
|
||||
|
||||
if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize && iCurImage->Pal.PalType != IL_PAL_NONE) {
|
||||
fprintf(HeadFile, "\n\n");
|
||||
fprintf(HeadFile, "#define IMAGE_PALSIZE %u\n\n", iCurImage->Pal.PalSize);
|
||||
fprintf(HeadFile, "#define IMAGE_PALTYPE 0x%X\n\n", iCurImage->Pal.PalType);
|
||||
fprintf(HeadFile, "ILubyte %sPal[] = {\n", Name);
|
||||
for (i = 0; i < iCurImage->Pal.PalSize; i += MAX_LINE_WIDTH) {
|
||||
fprintf(HeadFile, "\t");
|
||||
for (j = 0; j < MAX_LINE_WIDTH; j++) {
|
||||
if (i + j >= iCurImage->Pal.PalSize - 1) {
|
||||
fprintf(HeadFile, " %4d", iCurImage->Pal.Palette[i+j]);
|
||||
break;
|
||||
}
|
||||
else
|
||||
fprintf(HeadFile, " %4d,", iCurImage->Pal.Palette[i+j]);
|
||||
}
|
||||
fprintf(HeadFile, "\n");
|
||||
}
|
||||
|
||||
fprintf(HeadFile, "};\n");
|
||||
}
|
||||
fclose(HeadFile);
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif//IL_NO_CHEAD
|
||||
@@ -0,0 +1,362 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2001-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_icns.c
|
||||
//
|
||||
// Description: Reads from a Mac OS X icon (.icns) file.
|
||||
// Credit for the format of .icns files goes to
|
||||
// http://www.macdisk.com/maciconen.php3 and
|
||||
// http://ezix.org/project/wiki/MacOSXIcons
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//@TODO: Put ilSetError calls in when errors occur.
|
||||
//@TODO: Should we clear the alpha channel just in case there isn't one in the file?
|
||||
//@TODO: Checks on iread
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_ICNS
|
||||
#include "il_icns.h"
|
||||
|
||||
#ifndef IL_NO_JP2
|
||||
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#ifndef _DEBUG
|
||||
#pragma comment(lib, "libjasper.lib")
|
||||
#else
|
||||
#pragma comment(lib, "libjasper-d.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif//IL_NO_JP2
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid .icns file.
|
||||
ILboolean ilIsValidIcns(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE IcnsFile;
|
||||
ILboolean bIcns = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("icns"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bIcns;
|
||||
}
|
||||
|
||||
IcnsFile = iopenr(FileName);
|
||||
if (IcnsFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bIcns;
|
||||
}
|
||||
|
||||
bIcns = ilIsValidIcnsF(IcnsFile);
|
||||
icloser(IcnsFile);
|
||||
|
||||
return bIcns;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid .icns file at the current position.
|
||||
ILboolean ilIsValidIcnsF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidIcns();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid .icns lump.
|
||||
ILboolean ilIsValidIcnsL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidIcns();
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidIcns()
|
||||
{
|
||||
ICNSHEAD Header;
|
||||
|
||||
iread(Header.Head, 1, 4);
|
||||
iseek(-4, IL_SEEK_CUR); // Go ahead and restore to previous state
|
||||
|
||||
if (strncmp(Header.Head, "icns", 4)) // First 4 bytes have to be 'icns'.
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an icon file.
|
||||
ILboolean ilLoadIcns(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE IcnsFile;
|
||||
ILboolean bIcns = IL_FALSE;
|
||||
|
||||
IcnsFile = iopenr(FileName);
|
||||
if (IcnsFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bIcns;
|
||||
}
|
||||
|
||||
bIcns = ilLoadIcnsF(IcnsFile);
|
||||
icloser(IcnsFile);
|
||||
|
||||
return bIcns;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened icon file.
|
||||
ILboolean ilLoadIcnsF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadIcnsInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains an icon.
|
||||
ILboolean ilLoadIcnsL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadIcnsInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the icon.
|
||||
ILboolean iLoadIcnsInternal()
|
||||
{
|
||||
ICNSHEAD Header;
|
||||
ICNSDATA Entry;
|
||||
ILimage *Image = NULL;
|
||||
ILboolean BaseCreated = IL_FALSE;
|
||||
|
||||
|
||||
if (iCurImage == NULL)
|
||||
{
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iread(Header.Head, 4, 1);
|
||||
Header.Size = GetBigInt();
|
||||
|
||||
if (strncmp(Header.Head, "icns", 4)) // First 4 bytes have to be 'icns'.
|
||||
return IL_FALSE;
|
||||
|
||||
while ((ILint)itell() < Header.Size && !ieof())
|
||||
{
|
||||
iread(Entry.ID, 4, 1);
|
||||
Entry.Size = GetBigInt();
|
||||
|
||||
if (!strncmp(Entry.ID, "it32", 4)) // 128x128 24-bit
|
||||
{
|
||||
if (iIcnsReadData(&BaseCreated, IL_FALSE, 128, &Entry, &Image) == IL_FALSE)
|
||||
goto icns_error;
|
||||
}
|
||||
else if (!strncmp(Entry.ID, "t8mk", 4)) // 128x128 alpha mask
|
||||
{
|
||||
if (iIcnsReadData(&BaseCreated, IL_TRUE, 128, &Entry, &Image) == IL_FALSE)
|
||||
goto icns_error;
|
||||
}
|
||||
else if (!strncmp(Entry.ID, "ih32", 4)) // 48x48 24-bit
|
||||
{
|
||||
if (iIcnsReadData(&BaseCreated, IL_FALSE, 48, &Entry, &Image) == IL_FALSE)
|
||||
goto icns_error;
|
||||
}
|
||||
else if (!strncmp(Entry.ID, "h8mk", 4)) // 48x48 alpha mask
|
||||
{
|
||||
if (iIcnsReadData(&BaseCreated, IL_TRUE, 48, &Entry, &Image) == IL_FALSE)
|
||||
goto icns_error;
|
||||
}
|
||||
else if (!strncmp(Entry.ID, "il32", 4)) // 32x32 24-bit
|
||||
{
|
||||
if (iIcnsReadData(&BaseCreated, IL_FALSE, 32, &Entry, &Image) == IL_FALSE)
|
||||
goto icns_error;
|
||||
}
|
||||
else if (!strncmp(Entry.ID, "l8mk", 4)) // 32x32 alpha mask
|
||||
{
|
||||
if (iIcnsReadData(&BaseCreated, IL_TRUE, 32, &Entry, &Image) == IL_FALSE)
|
||||
goto icns_error;
|
||||
}
|
||||
else if (!strncmp(Entry.ID, "is32", 4)) // 16x16 24-bit
|
||||
{
|
||||
if (iIcnsReadData(&BaseCreated, IL_FALSE, 16, &Entry, &Image) == IL_FALSE)
|
||||
goto icns_error;
|
||||
}
|
||||
else if (!strncmp(Entry.ID, "s8mk", 4)) // 16x16 alpha mask
|
||||
{
|
||||
if (iIcnsReadData(&BaseCreated, IL_TRUE, 16, &Entry, &Image) == IL_FALSE)
|
||||
goto icns_error;
|
||||
}
|
||||
#ifndef IL_NO_JP2
|
||||
else if (!strncmp(Entry.ID, "ic09", 4)) // 512x512 JPEG2000 encoded - Uses JasPer
|
||||
{
|
||||
if (iIcnsReadData(&BaseCreated, IL_FALSE, 512, &Entry, &Image) == IL_FALSE)
|
||||
goto icns_error;
|
||||
}
|
||||
else if (!strncmp(Entry.ID, "ic08", 4)) // 256x256 JPEG2000 encoded - Uses JasPer
|
||||
{
|
||||
if (iIcnsReadData(&BaseCreated, IL_FALSE, 256, &Entry, &Image) == IL_FALSE)
|
||||
goto icns_error;
|
||||
}
|
||||
#endif//IL_NO_JP2
|
||||
else // Not a valid format or one that we can use
|
||||
{
|
||||
iseek(Entry.Size - 8, IL_SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
|
||||
icns_error:
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
ILboolean iIcnsReadData(ILboolean *BaseCreated, ILboolean IsAlpha, ILint Width, ICNSDATA *Entry, ILimage **Image)
|
||||
{
|
||||
ILint Position = 0, RLEPos = 0, Channel, i;
|
||||
ILubyte RLERead, *Data = NULL;
|
||||
ILimage *TempImage = NULL;
|
||||
ILboolean ImageAlreadyExists = IL_FALSE;
|
||||
|
||||
// The .icns format stores the alpha and RGB as two separate images, so this
|
||||
// checks to see if one exists for that particular size. Unfortunately,
|
||||
// there is no guarantee that they are in any particular order.
|
||||
if (*BaseCreated && iCurImage != NULL)
|
||||
{
|
||||
TempImage = iCurImage;
|
||||
while (TempImage != NULL)
|
||||
{
|
||||
if ((ILuint)Width == TempImage->Width)
|
||||
{
|
||||
ImageAlreadyExists = IL_TRUE;
|
||||
break;
|
||||
}
|
||||
TempImage = TempImage->Next;
|
||||
}
|
||||
}
|
||||
|
||||
Data = ialloc(Entry->Size - 8);
|
||||
if (Data == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
if (!ImageAlreadyExists)
|
||||
{
|
||||
if (!*BaseCreated) // Create base image
|
||||
{
|
||||
ilTexImage(Width, Width, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
*Image = iCurImage;
|
||||
*BaseCreated = IL_TRUE;
|
||||
}
|
||||
else // Create next image in list
|
||||
{
|
||||
(*Image)->Next = ilNewImage(Width, Width, 1, 4, 1);
|
||||
*Image = (*Image)->Next;
|
||||
(*Image)->Format = IL_RGBA;
|
||||
(*Image)->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
}
|
||||
|
||||
TempImage = *Image;
|
||||
}
|
||||
|
||||
if (IsAlpha) // Alpha is never compressed.
|
||||
{
|
||||
iread(Data, Entry->Size - 8, 1); // Size includes the header
|
||||
if (Entry->Size - 8 != Width * Width)
|
||||
{
|
||||
ifree(Data);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < Width * Width; i++)
|
||||
{
|
||||
TempImage->Data[(i * 4) + 3] = Data[i];
|
||||
}
|
||||
}
|
||||
else if (Width == 256 || Width == 512) // JPEG2000 encoded - uses JasPer
|
||||
{
|
||||
#ifndef IL_NO_JP2
|
||||
iread(Data, Entry->Size - 8, 1); // Size includes the header
|
||||
if (ilLoadJp2LInternal(Data, Entry->Size - 8, TempImage) == IL_FALSE)
|
||||
{
|
||||
ifree(Data);
|
||||
ilSetError(IL_LIB_JP2_ERROR);
|
||||
return IL_TRUE;
|
||||
}
|
||||
#else // Cannot handle this size.
|
||||
ilSetError(IL_LIB_JP2_ERROR); //@TODO: Handle this better...just skip the data.
|
||||
return IL_FALSE;
|
||||
#endif//IL_NO_JP2
|
||||
}
|
||||
else // RGB data
|
||||
{
|
||||
iread(Data, Entry->Size - 8, 1); // Size includes the header
|
||||
if (Width == 128)
|
||||
RLEPos += 4; // There are an extra 4 bytes here of zeros.
|
||||
//@TODO: Should we check to make sure they are all 0?
|
||||
|
||||
if (Entry->Size - 8 == Width * Width * 4) // Uncompressed
|
||||
{
|
||||
//memcpy(TempImage->Data, Data, Entry->Size);
|
||||
for (i = 0; i < Width * Width; i++, Position += 4)
|
||||
{
|
||||
TempImage->Data[i * 4 + 0] = Data[Position+1];
|
||||
TempImage->Data[i * 4 + 1] = Data[Position+2];
|
||||
TempImage->Data[i * 4 + 2] = Data[Position+3];
|
||||
}
|
||||
}
|
||||
else // RLE decoding
|
||||
{
|
||||
for (Channel = 0; Channel < 3; Channel++)
|
||||
{
|
||||
Position = 0;
|
||||
while (Position < Width * Width)
|
||||
{
|
||||
RLERead = Data[RLEPos];
|
||||
RLEPos++;
|
||||
|
||||
if (RLERead >= 128)
|
||||
{
|
||||
for (i = 0; i < RLERead - 125 && (Position + i) < Width * Width; i++)
|
||||
{
|
||||
TempImage->Data[Channel + (Position + i) * 4] = Data[RLEPos];
|
||||
}
|
||||
RLEPos++;
|
||||
Position += RLERead - 125;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < RLERead + 1 && (Position + i) < Width * Width; i++)
|
||||
{
|
||||
TempImage->Data[Channel + (Position + i) * 4] = Data[RLEPos + i];
|
||||
}
|
||||
RLEPos += RLERead + 1;
|
||||
Position += RLERead + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ifree(Data);
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
#endif//IL_NO_ICNS
|
||||
@@ -0,0 +1,674 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2001-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_icon.c
|
||||
//
|
||||
// Description: Reads from a Windows icon (.ico) file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_ICO
|
||||
#include "il_icon.h"
|
||||
#ifndef IL_NO_PNG
|
||||
#include <png.h>
|
||||
#endif
|
||||
|
||||
//! Reads an icon file.
|
||||
ILboolean ilLoadIcon(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE IconFile;
|
||||
ILboolean bIcon = IL_FALSE;
|
||||
|
||||
IconFile = iopenr(FileName);
|
||||
if (IconFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bIcon;
|
||||
}
|
||||
|
||||
bIcon = ilLoadIconF(IconFile);
|
||||
icloser(IconFile);
|
||||
|
||||
return bIcon;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened icon file.
|
||||
ILboolean ilLoadIconF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadIconInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains an icon.
|
||||
ILboolean ilLoadIconL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadIconInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the icon.
|
||||
ILboolean iLoadIconInternal()
|
||||
{
|
||||
ICODIR IconDir;
|
||||
ICODIRENTRY *DirEntries = NULL;
|
||||
ICOIMAGE *IconImages = NULL;
|
||||
ILimage *Image = NULL;
|
||||
ILint i;
|
||||
ILuint Size, PadSize, ANDPadSize, j, k, l, m, x, w, CurAndByte, AndBytes;
|
||||
ILboolean BaseCreated = IL_FALSE;
|
||||
ILubyte PNGTest[3];
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
IconDir.Reserved = GetLittleShort();
|
||||
IconDir.Type = GetLittleShort();
|
||||
IconDir.Count = GetLittleShort();
|
||||
|
||||
if (ieof())
|
||||
goto file_read_error;
|
||||
|
||||
DirEntries = (ICODIRENTRY*)ialloc(sizeof(ICODIRENTRY) * IconDir.Count);
|
||||
IconImages = (ICOIMAGE*)ialloc(sizeof(ICOIMAGE) * IconDir.Count);
|
||||
if (DirEntries == NULL || IconImages == NULL) {
|
||||
ifree(DirEntries);
|
||||
ifree(IconImages);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Make it easier for file_read_error.
|
||||
for (i = 0; i < IconDir.Count; i++)
|
||||
imemclear(&IconImages[i], sizeof(ICOIMAGE));
|
||||
|
||||
for (i = 0; i < IconDir.Count; ++i) {
|
||||
DirEntries[i].Width = (ILubyte)igetc();
|
||||
DirEntries[i].Height = (ILubyte)igetc();
|
||||
DirEntries[i].NumColours = (ILubyte)igetc();
|
||||
DirEntries[i].Reserved = (ILubyte)igetc();
|
||||
DirEntries[i].Planes = GetLittleShort();
|
||||
DirEntries[i].Bpp = GetLittleShort();
|
||||
DirEntries[i].SizeOfData = GetLittleUInt();
|
||||
DirEntries[i].Offset = GetLittleUInt();
|
||||
|
||||
if (ieof())
|
||||
goto file_read_error;
|
||||
}
|
||||
|
||||
for (i = 0; i < IconDir.Count; i++) {
|
||||
iseek(DirEntries[i].Offset, IL_SEEK_SET);
|
||||
|
||||
// 08-22-2008: Adding test for compressed PNG data
|
||||
igetc(); // Skip the first character...seems to vary.
|
||||
iread(PNGTest, 3, 1);
|
||||
if (!strnicmp((char*)PNGTest, "PNG", 3)) // Characters 'P', 'N', 'G' for PNG header
|
||||
{
|
||||
#ifdef IL_NO_PNG
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED); // Cannot handle these without libpng.
|
||||
goto file_read_error;
|
||||
#else
|
||||
iseek(DirEntries[i].Offset, IL_SEEK_SET);
|
||||
if (!iLoadIconPNG(&IconImages[i]))
|
||||
goto file_read_error;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to go back the 4 bytes that were just read.
|
||||
iseek(DirEntries[i].Offset, IL_SEEK_SET);
|
||||
|
||||
IconImages[i].Head.Size = GetLittleInt();
|
||||
IconImages[i].Head.Width = GetLittleInt();
|
||||
IconImages[i].Head.Height = GetLittleInt();
|
||||
IconImages[i].Head.Planes = GetLittleShort();
|
||||
IconImages[i].Head.BitCount = GetLittleShort();
|
||||
IconImages[i].Head.Compression = GetLittleInt();
|
||||
IconImages[i].Head.SizeImage = GetLittleInt();
|
||||
IconImages[i].Head.XPixPerMeter = GetLittleInt();
|
||||
IconImages[i].Head.YPixPerMeter = GetLittleInt();
|
||||
IconImages[i].Head.ColourUsed = GetLittleInt();
|
||||
IconImages[i].Head.ColourImportant = GetLittleInt();
|
||||
|
||||
if (ieof())
|
||||
goto file_read_error;
|
||||
|
||||
if (IconImages[i].Head.BitCount < 8) {
|
||||
if (IconImages[i].Head.ColourUsed == 0) {
|
||||
switch (IconImages[i].Head.BitCount)
|
||||
{
|
||||
case 1:
|
||||
IconImages[i].Head.ColourUsed = 2;
|
||||
break;
|
||||
case 4:
|
||||
IconImages[i].Head.ColourUsed = 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
IconImages[i].Pal = (ILubyte*)ialloc(IconImages[i].Head.ColourUsed * 4);
|
||||
if (IconImages[i].Pal == NULL)
|
||||
goto file_read_error; // @TODO: Rename the label.
|
||||
if (iread(IconImages[i].Pal, IconImages[i].Head.ColourUsed * 4, 1) != 1)
|
||||
goto file_read_error;
|
||||
}
|
||||
else if (IconImages[i].Head.BitCount == 8) {
|
||||
IconImages[i].Pal = (ILubyte*)ialloc(256 * 4);
|
||||
if (IconImages[i].Pal == NULL)
|
||||
goto file_read_error;
|
||||
if (iread(IconImages[i].Pal, 1, 256 * 4) != 256*4)
|
||||
goto file_read_error;
|
||||
}
|
||||
else {
|
||||
IconImages[i].Pal = NULL;
|
||||
}
|
||||
|
||||
PadSize = (4 - ((IconImages[i].Head.Width*IconImages[i].Head.BitCount + 7) / 8) % 4) % 4; // Has to be DWORD-aligned.
|
||||
ANDPadSize = (4 - ((IconImages[i].Head.Width + 7) / 8) % 4) % 4; // AND is 1 bit/pixel
|
||||
Size = ((IconImages[i].Head.Width*IconImages[i].Head.BitCount + 7) / 8 + PadSize)
|
||||
* (IconImages[i].Head.Height / 2);
|
||||
|
||||
|
||||
IconImages[i].Data = (ILubyte*)ialloc(Size);
|
||||
if (IconImages[i].Data == NULL)
|
||||
goto file_read_error;
|
||||
if (iread(IconImages[i].Data, 1, Size) != Size)
|
||||
goto file_read_error;
|
||||
|
||||
Size = (((IconImages[i].Head.Width + 7) /8) + ANDPadSize) * (IconImages[i].Head.Height / 2);
|
||||
IconImages[i].AND = (ILubyte*)ialloc(Size);
|
||||
if (IconImages[i].AND == NULL)
|
||||
goto file_read_error;
|
||||
if (iread(IconImages[i].AND, 1, Size) != Size)
|
||||
goto file_read_error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < IconDir.Count; i++) {
|
||||
if (IconImages[i].Head.BitCount != 1 && IconImages[i].Head.BitCount != 4 &&
|
||||
IconImages[i].Head.BitCount != 8 && IconImages[i].Head.BitCount != 24 &&
|
||||
|
||||
IconImages[i].Head.BitCount != 32)
|
||||
continue;
|
||||
|
||||
if (!BaseCreated) {
|
||||
if (IconImages[i].Head.Size == 0) // PNG compressed icon
|
||||
ilTexImage(IconImages[i].Head.Width, IconImages[i].Head.Height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
|
||||
else
|
||||
ilTexImage(IconImages[i].Head.Width, IconImages[i].Head.Height / 2, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
Image = iCurImage;
|
||||
BaseCreated = IL_TRUE;
|
||||
}
|
||||
else {
|
||||
if (IconImages[i].Head.Size == 0) // PNG compressed icon
|
||||
Image->Next = ilNewImage(IconImages[i].Head.Width, IconImages[i].Head.Height, 1, 4, 1);
|
||||
else
|
||||
Image->Next = ilNewImage(IconImages[i].Head.Width, IconImages[i].Head.Height / 2, 1, 4, 1);
|
||||
Image = Image->Next;
|
||||
Image->Format = IL_BGRA;
|
||||
}
|
||||
Image->Type = IL_UNSIGNED_BYTE;
|
||||
|
||||
j = 0; k = 0; l = 128; CurAndByte = 0; x = 0;
|
||||
|
||||
w = IconImages[i].Head.Width;
|
||||
PadSize = (4 - ((w*IconImages[i].Head.BitCount + 7) / 8) % 4) % 4; // Has to be DWORD-aligned.
|
||||
|
||||
ANDPadSize = (4 - ((w + 7) / 8) % 4) % 4; // AND is 1 bit/pixel
|
||||
AndBytes = (w + 7) / 8;
|
||||
|
||||
if (IconImages[i].Head.BitCount == 1) {
|
||||
for (; j < Image->SizeOfData; k++) {
|
||||
for (m = 128; m && x < w; m >>= 1) {
|
||||
Image->Data[j] = IconImages[i].Pal[!!(IconImages[i].Data[k] & m) * 4];
|
||||
Image->Data[j+1] = IconImages[i].Pal[!!(IconImages[i].Data[k] & m) * 4 + 1];
|
||||
Image->Data[j+2] = IconImages[i].Pal[!!(IconImages[i].Data[k] & m) * 4 + 2];
|
||||
Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
|
||||
j += 4;
|
||||
l >>= 1;
|
||||
|
||||
++x;
|
||||
}
|
||||
if (l == 0 || x == w) {
|
||||
l = 128;
|
||||
CurAndByte++;
|
||||
if (x == w) {
|
||||
CurAndByte += ANDPadSize;
|
||||
k += PadSize;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IconImages[i].Head.BitCount == 4) {
|
||||
for (; j < Image->SizeOfData; j += 8, k++) {
|
||||
Image->Data[j] = IconImages[i].Pal[((IconImages[i].Data[k] & 0xF0) >> 4) * 4];
|
||||
Image->Data[j+1] = IconImages[i].Pal[((IconImages[i].Data[k] & 0xF0) >> 4) * 4 + 1];
|
||||
Image->Data[j+2] = IconImages[i].Pal[((IconImages[i].Data[k] & 0xF0) >> 4) * 4 + 2];
|
||||
Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
|
||||
l >>= 1;
|
||||
|
||||
++x;
|
||||
|
||||
if(x < w) {
|
||||
Image->Data[j+4] = IconImages[i].Pal[(IconImages[i].Data[k] & 0x0F) * 4];
|
||||
Image->Data[j+5] = IconImages[i].Pal[(IconImages[i].Data[k] & 0x0F) * 4 + 1];
|
||||
Image->Data[j+6] = IconImages[i].Pal[(IconImages[i].Data[k] & 0x0F) * 4 + 2];
|
||||
Image->Data[j+7] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
|
||||
l >>= 1;
|
||||
|
||||
++x;
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
j -= 4;
|
||||
|
||||
|
||||
if (l == 0 || x == w) {
|
||||
l = 128;
|
||||
CurAndByte++;
|
||||
if (x == w) {
|
||||
CurAndByte += ANDPadSize;
|
||||
|
||||
k += PadSize;
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IconImages[i].Head.BitCount == 8) {
|
||||
for (; j < Image->SizeOfData; j += 4, k++) {
|
||||
Image->Data[j] = IconImages[i].Pal[IconImages[i].Data[k] * 4];
|
||||
Image->Data[j+1] = IconImages[i].Pal[IconImages[i].Data[k] * 4 + 1];
|
||||
Image->Data[j+2] = IconImages[i].Pal[IconImages[i].Data[k] * 4 + 2];
|
||||
if (IconImages[i].AND == NULL) // PNG Palette
|
||||
{
|
||||
Image->Data[j+3] = IconImages[i].Pal[IconImages[i].Data[k] * 4 + 3];
|
||||
}
|
||||
else
|
||||
{
|
||||
Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
|
||||
}
|
||||
l >>= 1;
|
||||
|
||||
++x;
|
||||
if (l == 0 || x == w) {
|
||||
l = 128;
|
||||
CurAndByte++;
|
||||
if (x == w) {
|
||||
CurAndByte += ANDPadSize;
|
||||
|
||||
k += PadSize;
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IconImages[i].Head.BitCount == 24) {
|
||||
for (; j < Image->SizeOfData; j += 4, k += 3) {
|
||||
Image->Data[j] = IconImages[i].Data[k];
|
||||
Image->Data[j+1] = IconImages[i].Data[k+1];
|
||||
Image->Data[j+2] = IconImages[i].Data[k+2];
|
||||
Image->Data[j+3] = (IconImages[i].AND[CurAndByte] & l) != 0 ? 0 : 255;
|
||||
l >>= 1;
|
||||
|
||||
++x;
|
||||
if (l == 0 || x == w) {
|
||||
l = 128;
|
||||
CurAndByte++;
|
||||
if (x == w) {
|
||||
CurAndByte += ANDPadSize;
|
||||
|
||||
k += PadSize;
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (IconImages[i].Head.BitCount == 32) {
|
||||
for (; j < Image->SizeOfData; j += 4, k += 4) {
|
||||
Image->Data[j] = IconImages[i].Data[k];
|
||||
Image->Data[j+1] = IconImages[i].Data[k+1];
|
||||
Image->Data[j+2] = IconImages[i].Data[k+2];
|
||||
|
||||
//If the icon has 4 channels, use 4th channel for alpha...
|
||||
//(for Windows XP style icons with true alpha channel
|
||||
Image->Data[j+3] = IconImages[i].Data[k+3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < IconDir.Count; i++) {
|
||||
ifree(IconImages[i].Pal);
|
||||
ifree(IconImages[i].Data);
|
||||
ifree(IconImages[i].AND);
|
||||
}
|
||||
ifree(IconImages);
|
||||
ifree(DirEntries);
|
||||
|
||||
return ilFixImage();
|
||||
|
||||
file_read_error:
|
||||
if (IconImages) {
|
||||
for (i = 0; i < IconDir.Count; i++) {
|
||||
if (IconImages[i].Pal)
|
||||
ifree(IconImages[i].Pal);
|
||||
if (IconImages[i].Data)
|
||||
ifree(IconImages[i].Data);
|
||||
if (IconImages[i].AND)
|
||||
ifree(IconImages[i].AND);
|
||||
}
|
||||
ifree(IconImages);
|
||||
}
|
||||
if (DirEntries)
|
||||
ifree(DirEntries);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
#ifndef IL_NO_PNG
|
||||
// 08-22-2008: Copying a lot of this over from il_png.c for the moment.
|
||||
// @TODO: Make .ico and .png use the same functions.
|
||||
png_structp ico_png_ptr = NULL;
|
||||
png_infop ico_info_ptr = NULL;
|
||||
ILint ico_color_type;
|
||||
|
||||
#define GAMMA_CORRECTION 1.0 // Doesn't seem to be doing anything...
|
||||
|
||||
ILint ico_readpng_init();
|
||||
ILboolean ico_readpng_get_image(ICOIMAGE *Icon, ILdouble display_exponent);
|
||||
void ico_readpng_cleanup();
|
||||
#endif
|
||||
|
||||
ILboolean iLoadIconPNG(ICOIMAGE *Icon)
|
||||
{
|
||||
#ifndef IL_NO_PNG
|
||||
ILint init;
|
||||
init = ico_readpng_init();
|
||||
if (init)
|
||||
return IL_FALSE;
|
||||
if (!ico_readpng_get_image(Icon, GAMMA_CORRECTION))
|
||||
return IL_FALSE;
|
||||
|
||||
ico_readpng_cleanup();
|
||||
Icon->Head.Size = 0; // Easiest way to tell that this is a PNG.
|
||||
// In the normal routine, it will not be 0.
|
||||
|
||||
return IL_TRUE;
|
||||
#else
|
||||
Icon;
|
||||
return IL_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef IL_NO_PNG
|
||||
static void ico_png_read(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
(void)png_ptr;
|
||||
iread(data, 1, (ILuint)length);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void ico_png_error_func(png_structp png_ptr, png_const_charp message)
|
||||
{
|
||||
message;
|
||||
ilSetError(IL_LIB_PNG_ERROR);
|
||||
|
||||
/*
|
||||
changed 20040224
|
||||
From the libpng docs:
|
||||
"Errors handled through png_error() are fatal, meaning that png_error()
|
||||
should never return to its caller. Currently, this is handled via
|
||||
setjmp() and longjmp()"
|
||||
*/
|
||||
//return;
|
||||
longjmp(png_jmpbuf(png_ptr), 1);
|
||||
}
|
||||
|
||||
static void ico_png_warn_func(png_structp png_ptr, png_const_charp message)
|
||||
{
|
||||
png_ptr; message;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILint ico_readpng_init()
|
||||
{
|
||||
ico_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, ico_png_error_func, ico_png_warn_func);
|
||||
if (!ico_png_ptr)
|
||||
return 4; /* out of memory */
|
||||
|
||||
ico_info_ptr = png_create_info_struct(ico_png_ptr);
|
||||
if (!ico_info_ptr) {
|
||||
png_destroy_read_struct(&ico_png_ptr, NULL, NULL);
|
||||
return 4; /* out of memory */
|
||||
}
|
||||
|
||||
|
||||
/* we could create a second info struct here (end_info), but it's only
|
||||
* useful if we want to keep pre- and post-IDAT chunk info separated
|
||||
* (mainly for PNG-aware image editors and converters) */
|
||||
|
||||
|
||||
/* setjmp() must be called in every function that calls a PNG-reading
|
||||
* libpng function */
|
||||
|
||||
if (setjmp(png_jmpbuf(ico_png_ptr))) {
|
||||
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
png_set_read_fn(ico_png_ptr, NULL, ico_png_read);
|
||||
png_set_error_fn(ico_png_ptr, NULL, ico_png_error_func, ico_png_warn_func);
|
||||
|
||||
// png_set_sig_bytes(ico_png_ptr, 8); /* we already read the 8 signature bytes */
|
||||
|
||||
png_read_info(ico_png_ptr, ico_info_ptr); /* read all PNG info up to image data */
|
||||
|
||||
/* alternatively, could make separate calls to png_get_image_width(),
|
||||
* etc., but want bit_depth and ico_color_type for later [don't care about
|
||||
* compression_type and filter_type => NULLs] */
|
||||
|
||||
/* OK, that's all we need for now; return happy */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ico_readpng_get_image(ICOIMAGE *Icon, ILdouble display_exponent)
|
||||
{
|
||||
png_bytepp row_pointers = NULL;
|
||||
png_uint_32 width, height; // Changed the type to fix AMD64 bit problems, thanks to Eric Werness
|
||||
ILdouble screen_gamma = 1.0;
|
||||
ILuint i, channels;
|
||||
ILenum format;
|
||||
png_colorp palette;
|
||||
ILint num_palette, j, bit_depth;
|
||||
#if _WIN32 || DJGPP
|
||||
ILdouble image_gamma;
|
||||
#endif
|
||||
|
||||
display_exponent;
|
||||
|
||||
/* setjmp() must be called in every function that calls a PNG-reading
|
||||
* libpng function */
|
||||
|
||||
if (setjmp(png_jmpbuf(ico_png_ptr))) {
|
||||
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
png_get_IHDR(ico_png_ptr, ico_info_ptr, (png_uint_32*)&width, (png_uint_32*)&height,
|
||||
&bit_depth, &ico_color_type, NULL, NULL, NULL);
|
||||
|
||||
// Expand low-bit-depth grayscale images to 8 bits
|
||||
if (ico_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
|
||||
png_set_gray_1_2_4_to_8(ico_png_ptr);
|
||||
}
|
||||
|
||||
// Expand RGB images with transparency to full alpha channels
|
||||
// so the data will be available as RGBA quartets.
|
||||
// But don't expand paletted images, since we want alpha palettes!
|
||||
if (png_get_valid(ico_png_ptr, ico_info_ptr, PNG_INFO_tRNS) && !(png_get_valid(ico_png_ptr, ico_info_ptr, PNG_INFO_PLTE)))
|
||||
png_set_tRNS_to_alpha(ico_png_ptr);
|
||||
|
||||
//refresh information (added 20040224)
|
||||
png_get_IHDR(ico_png_ptr, ico_info_ptr, (png_uint_32*)&width, (png_uint_32*)&height,
|
||||
&bit_depth, &ico_color_type, NULL, NULL, NULL);
|
||||
|
||||
if (bit_depth < 8) { // Expanded earlier for grayscale, now take care of palette and rgb
|
||||
bit_depth = 8;
|
||||
png_set_packing(ico_png_ptr);
|
||||
}
|
||||
|
||||
// Perform gamma correction.
|
||||
// @TODO: Determine if we should call png_set_gamma if image_gamma is 1.0.
|
||||
#if _WIN32 || DJGPP
|
||||
screen_gamma = 2.2;
|
||||
if (png_get_gAMA(ico_png_ptr, ico_info_ptr, &image_gamma))
|
||||
png_set_gamma(ico_png_ptr, screen_gamma, image_gamma);
|
||||
#else
|
||||
screen_gamma = screen_gamma;
|
||||
#endif
|
||||
|
||||
//fix endianess
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
if (bit_depth == 16)
|
||||
png_set_swap(ico_png_ptr);
|
||||
#endif
|
||||
|
||||
|
||||
png_read_update_info(ico_png_ptr, ico_info_ptr);
|
||||
channels = (ILint)png_get_channels(ico_png_ptr, ico_info_ptr);
|
||||
// added 20040224: update ico_color_type so that it has the correct value
|
||||
// in iLoadPngInternal (globals rule...)
|
||||
ico_color_type = png_get_color_type(ico_png_ptr, ico_info_ptr);
|
||||
|
||||
// Determine internal format
|
||||
switch (ico_color_type)
|
||||
{
|
||||
case PNG_COLOR_TYPE_PALETTE:
|
||||
Icon->Head.BitCount = 8;
|
||||
format = IL_COLOUR_INDEX;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
Icon->Head.BitCount = 24;
|
||||
format = IL_RGB;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
Icon->Head.BitCount = 32;
|
||||
format = IL_RGBA;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (ico_color_type & PNG_COLOR_MASK_COLOR)
|
||||
png_set_bgr(ico_png_ptr);
|
||||
|
||||
Icon->Head.Width = width;
|
||||
Icon->Head.Height = height;
|
||||
Icon->Data = ialloc(width * height * Icon->Head.BitCount / 8);
|
||||
if (Icon->Data == NULL)
|
||||
{
|
||||
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Copy Palette
|
||||
if (format == IL_COLOUR_INDEX)
|
||||
{
|
||||
int chans;
|
||||
png_bytep trans = NULL;
|
||||
int num_trans = -1;
|
||||
if (!png_get_PLTE(ico_png_ptr, ico_info_ptr, &palette, &num_palette)) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
chans = 4;
|
||||
|
||||
if (png_get_valid(ico_png_ptr, ico_info_ptr, PNG_INFO_tRNS)) {
|
||||
png_get_tRNS(ico_png_ptr, ico_info_ptr, &trans, &num_trans, NULL);
|
||||
}
|
||||
|
||||
// @TODO: We may need to keep track of the size of the palette.
|
||||
Icon->Pal = (ILubyte*)ialloc(num_palette * chans);
|
||||
|
||||
for (j = 0; j < num_palette; ++j) {
|
||||
Icon->Pal[chans*j + 0] = palette[j].blue;
|
||||
Icon->Pal[chans*j + 1] = palette[j].green;
|
||||
Icon->Pal[chans*j + 2] = palette[j].red;
|
||||
if (trans != NULL) {
|
||||
if (j < num_trans)
|
||||
Icon->Pal[chans*j + 3] = trans[j];
|
||||
else
|
||||
Icon->Pal[chans*j + 3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
Icon->AND = NULL; // Transparency information is obtained from libpng.
|
||||
}
|
||||
|
||||
//allocate row pointers
|
||||
if ((row_pointers = (png_bytepp)ialloc(height * sizeof(png_bytep))) == NULL) {
|
||||
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// Set the individual row_pointers to point at the correct offsets
|
||||
// Needs to be flipped
|
||||
for (i = 0; i < height; i++)
|
||||
row_pointers[height - i - 1] = Icon->Data + i * width * Icon->Head.BitCount / 8;
|
||||
//row_pointers[i] = Icon->Data + i * width * Icon->Head.BitCount / 8;
|
||||
|
||||
|
||||
// Now we can go ahead and just read the whole image
|
||||
png_read_image(ico_png_ptr, row_pointers);
|
||||
|
||||
/* and we're done! (png_read_end() can be omitted if no processing of
|
||||
* post-IDAT text/time/etc. is desired) */
|
||||
//png_read_end(ico_png_ptr, NULL);
|
||||
ifree(row_pointers);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
void ico_readpng_cleanup()
|
||||
{
|
||||
if (ico_png_ptr && ico_info_ptr) {
|
||||
png_destroy_read_struct(&ico_png_ptr, &ico_info_ptr, NULL);
|
||||
ico_png_ptr = NULL;
|
||||
ico_info_ptr = NULL;
|
||||
}
|
||||
}
|
||||
#endif//IL_NO_PNG
|
||||
|
||||
#endif//IL_NO_ICO
|
||||
@@ -0,0 +1,479 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Last modified: 03/0/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_iff.c
|
||||
//
|
||||
// Description: Reads from an .iff file. Contribution from GAIA:
|
||||
// http://gaia.fdi.ucm.es/grupo/projects/javy/devzone.html#DevILNotes.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
|
||||
#ifndef IL_NO_IFF
|
||||
|
||||
// Chunk type, data and functions:
|
||||
typedef struct _iff_chunk {
|
||||
ILuint tag;
|
||||
ILuint start;
|
||||
ILuint size;
|
||||
ILuint chunkType;
|
||||
} iff_chunk;
|
||||
|
||||
#define CHUNK_STACK_SIZE (32)
|
||||
static iff_chunk chunkStack[CHUNK_STACK_SIZE];
|
||||
static int chunkDepth = -1;
|
||||
|
||||
iff_chunk iff_begin_read_chunk();
|
||||
void iff_end_read_chunk();
|
||||
char *iff_read_data(int size);
|
||||
ILboolean iLoadIffInternal(void);
|
||||
|
||||
|
||||
/* Define the IFF tags we are looking for in the file. */
|
||||
const ILuint IFF_TAG_CIMG = ('C' << 24) | ('I' << 16) | ('M' << 8) | ('G');
|
||||
const ILuint IFF_TAG_FOR4 = ('F' << 24) | ('O' << 16) | ('R' << 8) | ('4');
|
||||
const ILuint IFF_TAG_TBHD = ('T' << 24) | ('B' << 16) | ('H' << 8) | ('D');
|
||||
const ILuint IFF_TAG_TBMP = ('T' << 24) | ('B' << 16) | ('M' << 8) | ('P');
|
||||
const ILuint IFF_TAG_RGBA = ('R' << 24) | ('G' << 16) | ('B' << 8) | ('A');
|
||||
const ILuint IFF_TAG_CLPZ = ('C' << 24) | ('L' << 16) | ('P' << 8) | ('Z');
|
||||
const ILuint IFF_TAG_ESXY = ('E' << 24) | ('S' << 16) | ('X' << 8) | ('Y');
|
||||
const ILuint IFF_TAG_ZBUF = ('Z' << 24) | ('B' << 16) | ('U' << 8) | ('F');
|
||||
const ILuint IFF_TAG_BLUR = ('B' << 24) | ('L' << 16) | ('U' << 8) | ('R');
|
||||
const ILuint IFF_TAG_BLRT = ('B' << 24) | ('L' << 16) | ('R' << 8) | ('T');
|
||||
const ILuint IFF_TAG_HIST = ('H' << 24) | ('I' << 16) | ('S' << 8) | ('T');
|
||||
|
||||
// Flags
|
||||
#define RGB_FLAG (1)
|
||||
#define ALPHA_FLAG (2)
|
||||
#define ZBUFFER_FLAG (4)
|
||||
|
||||
// Function for decompress the file.
|
||||
char *iff_decompress_rle(ILuint numBytes, char *compressedData,
|
||||
ILuint compressedDataSize,
|
||||
ILuint *compressedStartIndex);
|
||||
|
||||
char *iffReadUncompressedTile(ILushort width, ILushort height, ILbyte depth);
|
||||
char *iff_decompress_tile_rle(ILushort width, ILushort height, ILushort depth,
|
||||
char *compressedData, ILuint compressedDataSize);
|
||||
|
||||
|
||||
//! Reads an IFF file
|
||||
ILboolean ilLoadIff(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE iffFile;
|
||||
ILboolean ret = IL_FALSE;
|
||||
|
||||
iffFile = iopenr(FileName);
|
||||
if (iffFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return ret;
|
||||
}
|
||||
ret = ilLoadIffF(iffFile);
|
||||
icloser(iffFile);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened IFF file
|
||||
ILboolean ilLoadIffF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadIffInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
// Lbm files can have the .iff extension as well, so if Iff-loading failed,
|
||||
// try to load it as a Lbm.
|
||||
if (bRet == IL_FALSE)
|
||||
return ilLoadIlbmF(File);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains an IFF
|
||||
ILboolean ilLoadIffL(const void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputLump(Lump, Size);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadIffInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
// Lbm files can have the .iff extension as well, so if Iff-loading failed,
|
||||
// try to load it as a Lbm.
|
||||
if (bRet == IL_FALSE)
|
||||
return ilLoadIlbmL(Lump, Size);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
ILboolean iLoadIffInternal(void)
|
||||
{
|
||||
iff_chunk chunkInfo;
|
||||
|
||||
// -- Header info.
|
||||
ILuint width, height;
|
||||
ILuint flags, compress;
|
||||
ILushort tiles;
|
||||
|
||||
ILenum format;
|
||||
ILubyte bpp;
|
||||
|
||||
ILboolean tileImageDataFound;
|
||||
|
||||
// -- Initialize the top of the chunk stack.
|
||||
chunkDepth = -1;
|
||||
|
||||
// -- File should begin with a FOR4 chunk of type CIMG
|
||||
chunkInfo = iff_begin_read_chunk();
|
||||
if (chunkInfo.chunkType != IFF_TAG_CIMG) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the image header
|
||||
* OK, we have a FOR4 of type CIMG, look for the following tags
|
||||
* FVER
|
||||
* TBHD bitmap header, definition of size, etc.
|
||||
* AUTH
|
||||
* DATE
|
||||
*/
|
||||
while (1) {
|
||||
|
||||
chunkInfo = iff_begin_read_chunk();
|
||||
|
||||
// -- Right now, the only info we need about the image is in TBHD
|
||||
// -- so search this level until we find it.
|
||||
if( chunkInfo.tag == IFF_TAG_TBHD ) {
|
||||
// -- Header chunk found
|
||||
width = GetBigUInt();
|
||||
height = GetBigUInt();
|
||||
GetBigShort(); // -- Don't support
|
||||
GetBigShort(); // -- Don't support
|
||||
flags = GetBigUInt();
|
||||
GetBigShort(); // -- Don't support
|
||||
tiles = GetBigUShort();
|
||||
compress = GetBigUInt();
|
||||
|
||||
iff_end_read_chunk();
|
||||
|
||||
if( compress > 1 ) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
} else
|
||||
iff_end_read_chunk();
|
||||
} /* END find TBHD while loop */
|
||||
|
||||
if (!(flags & RGB_FLAG)) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (flags & ALPHA_FLAG) {
|
||||
format = IL_RGBA; bpp = 4;
|
||||
} else {
|
||||
format = IL_RGB; bpp = 3;
|
||||
}
|
||||
|
||||
if (!ilTexImage(width, height, 1, bpp, format, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
tileImageDataFound = IL_FALSE;
|
||||
|
||||
while (!tileImageDataFound) {
|
||||
ILuint tileImage;
|
||||
ILuint tileZ;
|
||||
|
||||
chunkInfo = iff_begin_read_chunk();
|
||||
|
||||
/*
|
||||
* OK, we have a FOR4 of type TBMP, (embedded FOR4)
|
||||
* look for the following tags
|
||||
* RGBA color data, RLE compressed tiles of 32 bbp data
|
||||
* ZBUF z-buffer data, 32 bit float values
|
||||
* CLPZ depth map specific, clipping planes, 2 float values
|
||||
* ESXY depth map specific, eye x-y ratios, 2 float values
|
||||
* HIST
|
||||
* VERS
|
||||
* FOR4 <size> BLUR (twice embedded FOR4)
|
||||
*/
|
||||
if (chunkInfo.chunkType != IFF_TAG_TBMP) {
|
||||
iff_end_read_chunk();
|
||||
continue;
|
||||
}
|
||||
tileImageDataFound = IL_TRUE;
|
||||
tileImage = 0; // Si no RGBA, tileImage = tiles...
|
||||
if (flags & ZBUFFER_FLAG)
|
||||
tileZ = 0;
|
||||
else
|
||||
tileZ = tiles;
|
||||
|
||||
// Read tiles
|
||||
while ( (tileImage < tiles) || (tileZ < tiles)) {
|
||||
char *tileData;
|
||||
ILushort x1, x2, y1, y2, tile_width, tile_height;
|
||||
ILuint remainingDataSize;
|
||||
ILushort tile_area;
|
||||
ILuint tileCompressed;
|
||||
|
||||
chunkInfo = iff_begin_read_chunk();
|
||||
if ((chunkInfo.tag != IFF_TAG_RGBA) && (chunkInfo.tag != IFF_TAG_ZBUF)) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
x1 = GetBigUShort(); y1 = GetBigUShort();
|
||||
x2 = GetBigUShort(); y2 = GetBigUShort();
|
||||
|
||||
remainingDataSize = chunkInfo.size - 4*sizeof(ILushort);
|
||||
tile_width = x2 - x1 + 1;
|
||||
tile_height = y2 - y1 + 1;
|
||||
tile_area = tile_width * tile_height;
|
||||
|
||||
if ((ILint)remainingDataSize >= (tile_width * tile_height * bpp))
|
||||
tileCompressed = 0;
|
||||
else
|
||||
tileCompressed = 1;
|
||||
|
||||
if (chunkInfo.tag == IFF_TAG_RGBA) {
|
||||
if (tileCompressed) {
|
||||
char *data = iff_read_data(remainingDataSize);
|
||||
if (data) {
|
||||
tileData = iff_decompress_tile_rle(tile_width, tile_height,
|
||||
bpp, data, remainingDataSize);
|
||||
ifree(data);
|
||||
}
|
||||
} else {
|
||||
tileData = iffReadUncompressedTile(tile_width, tile_height, bpp);
|
||||
}
|
||||
|
||||
if (tileData) {
|
||||
// Dump RGBA data to our data structure
|
||||
ILushort i;
|
||||
ILuint base;
|
||||
base = bpp*(width * y1 + x1);
|
||||
for (i = 0; i < tile_height; i++) {
|
||||
memcpy(&iCurImage->Data[base + bpp*i*width],
|
||||
&tileData[bpp*i*tile_width],
|
||||
tile_width*bpp*sizeof(char));
|
||||
}
|
||||
ifree(tileData);
|
||||
tileData = NULL;
|
||||
|
||||
iff_end_read_chunk();
|
||||
tileImage++;
|
||||
} else
|
||||
return IL_FALSE;
|
||||
} else if (chunkInfo.tag == IFF_TAG_ZBUF) {
|
||||
tileZ++;
|
||||
iff_end_read_chunk();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE); // Why was this here?
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
/*
|
||||
* IFF Chunking Routines.
|
||||
*
|
||||
*/
|
||||
|
||||
iff_chunk iff_begin_read_chunk()
|
||||
{
|
||||
chunkDepth++;
|
||||
if (chunkDepth >= CHUNK_STACK_SIZE){
|
||||
ilSetError(IL_STACK_OVERFLOW);
|
||||
return chunkStack[0];
|
||||
}
|
||||
if (chunkDepth < 0) {
|
||||
ilSetError(IL_STACK_UNDERFLOW);
|
||||
return chunkStack[0];
|
||||
}
|
||||
|
||||
chunkStack[chunkDepth].start = itell();
|
||||
chunkStack[chunkDepth].tag = GetBigInt();
|
||||
chunkStack[chunkDepth].size = GetBigInt();
|
||||
|
||||
if (chunkStack[chunkDepth].tag == IFF_TAG_FOR4) {
|
||||
// -- We have a form, so read the form type tag as well.
|
||||
chunkStack[chunkDepth].chunkType = GetBigInt();
|
||||
} else {
|
||||
chunkStack[chunkDepth].chunkType = 0;
|
||||
}
|
||||
|
||||
return chunkStack[chunkDepth];
|
||||
}
|
||||
|
||||
void iff_end_read_chunk()
|
||||
{
|
||||
ILuint end;
|
||||
int part;
|
||||
|
||||
end = chunkStack[chunkDepth].start + chunkStack[chunkDepth].size + 8;
|
||||
|
||||
if (chunkStack[chunkDepth].chunkType != 0) {
|
||||
end += 4;
|
||||
}
|
||||
// Add padding
|
||||
part = end % 4;
|
||||
if (part != 0) {
|
||||
end += 4 - part;
|
||||
}
|
||||
|
||||
iseek(end, IL_SEEK_SET);
|
||||
|
||||
chunkDepth--;
|
||||
}
|
||||
|
||||
char * iff_read_data(int size)
|
||||
{
|
||||
char *buffer = ialloc(size * sizeof(char));
|
||||
if (buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
if (iread(buffer, size*sizeof(char), 1) != 1) {
|
||||
ifree(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
IFF decompress functions
|
||||
*/
|
||||
|
||||
char *iffReadUncompressedTile(ILushort width, ILushort height, ILbyte depth)
|
||||
{
|
||||
|
||||
char *data = NULL;
|
||||
char *iniPixel;
|
||||
char *finPixel;
|
||||
int i, j;
|
||||
int tam = width* height * depth * sizeof(char);
|
||||
|
||||
data = ialloc(tam);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
if (iread(data, tam, 1) != 1) {
|
||||
ifree(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iniPixel = data;
|
||||
for (i = 0; i < tam / depth; i++) {
|
||||
finPixel = iniPixel + depth;
|
||||
for (j = 0; j < (depth /2); j++) {
|
||||
char aux;
|
||||
aux = *iniPixel;
|
||||
*(finPixel--) = *iniPixel;
|
||||
*(iniPixel++) = aux;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
char *iff_decompress_tile_rle(ILushort width, ILushort height, ILushort depth,
|
||||
char *compressedData, ILuint compressedDataSize)
|
||||
{
|
||||
|
||||
char *channels[4];
|
||||
char *data;
|
||||
int i, k, row, column;
|
||||
ILuint compressedStart = 0;
|
||||
|
||||
// Decompress only in RGBA.
|
||||
if (depth != 4) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = depth-1; i >= 0; --i) {
|
||||
channels[i] = iff_decompress_rle(width * height, compressedData,
|
||||
compressedDataSize, &compressedStart);
|
||||
if (channels[i] == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Build all the channels from the decompression into an RGBA array.
|
||||
data = ialloc(width * height * depth * sizeof(char));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
for (row = 0; row < height; row++)
|
||||
for (column = 0; column < width; column++)
|
||||
for (k = 0; k < depth; k++)
|
||||
data[depth*(row*width + column) + k] =
|
||||
channels[k][row*width + column];
|
||||
|
||||
ifree(channels[0]); ifree(channels[1]);
|
||||
ifree(channels[2]); ifree(channels[3]);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
char *iff_decompress_rle(ILuint numBytes, char *compressedData,
|
||||
ILuint compressedDataSize,
|
||||
ILuint *compressedStartIndex)
|
||||
{
|
||||
|
||||
char *data = ialloc(numBytes * sizeof(char));
|
||||
unsigned char nextChar, count;
|
||||
int i;
|
||||
ILuint byteCount = 0;
|
||||
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(data, 0, numBytes*sizeof(char));
|
||||
|
||||
while (byteCount < numBytes) {
|
||||
if (*compressedStartIndex >= compressedDataSize)
|
||||
break;
|
||||
nextChar = compressedData[*compressedStartIndex];
|
||||
(*compressedStartIndex)++;
|
||||
count = (nextChar & 0x7f) + 1;
|
||||
if ((byteCount + count) > numBytes) break;
|
||||
if (nextChar & 0x80) {
|
||||
// Duplication run
|
||||
nextChar = compressedData[*compressedStartIndex];
|
||||
(*compressedStartIndex)++;
|
||||
// assert ((byteCount + count) <= numBytes);
|
||||
for (i = 0; i < count; i++) {
|
||||
data[byteCount]= nextChar;
|
||||
byteCount++;
|
||||
}
|
||||
} else {
|
||||
// Verbatim run
|
||||
for (i = 0; i < count; i++) {
|
||||
data[byteCount] = compressedData[*compressedStartIndex];
|
||||
(*compressedStartIndex)++;
|
||||
byteCount++;
|
||||
}
|
||||
}
|
||||
//assert(byteCount <= numBytes);
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
#endif //IL_NO_IFF
|
||||
@@ -0,0 +1,658 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/08/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_ilbm.c
|
||||
//
|
||||
// Description: IFF ILBM file (.iff, .ilbm, .lbm) functions
|
||||
// IFF ILBM loader, ported from SDL_Image library (IMG_lbm.c)
|
||||
// http://www.libsdl.org/cgi/viewvc.cgi/trunk/SDL_image/IMG_lbm.c?view=markup
|
||||
//
|
||||
// Handles Amiga ILBM and PBM images (including .lbm files saved by the PC
|
||||
// version of dpaint)
|
||||
// Handles ExtraHalfBright and HAM images.
|
||||
//
|
||||
// Adapted from SDL_image by Ben Campbell (http://scumways.com) 2009-02-23
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// TODO: sort out the .iff extension confusion: .iff is currently handled by
|
||||
// Maya IFF/CIMG handler (il_iff.c), but it should defer to this one if
|
||||
// fileturns out to be an ILBM. I think the best solution would be to
|
||||
// rename the IFF handler to CIMG, and create a new iff handler to act as
|
||||
// a front end, passing off to either il_ilbm or il_cimg...
|
||||
// For now, this handler only handles .lbm and .ilbm extenstions (but
|
||||
// traditionally, .iff is more common).
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_ILBM
|
||||
#include <stdlib.h>
|
||||
|
||||
ILboolean iIsValidIlbm(void);
|
||||
ILboolean iLoadIlbmInternal(void);
|
||||
static ILboolean load_ilbm(void);
|
||||
static int isLBM(void );
|
||||
|
||||
|
||||
ILboolean ilIsValidIlbm(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE f;
|
||||
ILboolean bIlbm = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("iff")) &&
|
||||
!iCheckExtension(FileName, IL_TEXT("ilbm")) &&
|
||||
!iCheckExtension(FileName, IL_TEXT("lbm")) &&
|
||||
!iCheckExtension(FileName, IL_TEXT("ham")) ) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bIlbm;
|
||||
}
|
||||
|
||||
f = iopenr(FileName);
|
||||
if (f == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bIlbm;
|
||||
}
|
||||
|
||||
bIlbm = ilIsValidIlbmF(f);
|
||||
icloser(f);
|
||||
|
||||
return bIlbm;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ilIsValidIlbmF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidIlbm();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ilIsValidIlbmL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidIlbm();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iIsValidIlbm()
|
||||
{
|
||||
return isLBM() ? IL_TRUE:IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// Reads a file
|
||||
ILboolean ilLoadIlbm(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE IlbmFile;
|
||||
ILboolean bIlbm = IL_FALSE;
|
||||
|
||||
IlbmFile = iopenr(FileName);
|
||||
if (IlbmFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bIlbm;
|
||||
}
|
||||
|
||||
bIlbm = ilLoadIlbmF(IlbmFile);
|
||||
icloser(IlbmFile);
|
||||
|
||||
return bIlbm;
|
||||
}
|
||||
|
||||
|
||||
// Reads an already-opened file
|
||||
ILboolean ilLoadIlbmF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadIlbmInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
// Reads from a memory "lump"
|
||||
ILboolean ilLoadIlbmL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadIlbmInternal();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadIlbmInternal()
|
||||
{
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (!iIsValidIlbm()) {
|
||||
ilSetError(IL_INVALID_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!load_ilbm() )
|
||||
{
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
/* some defines to allow us to use the SDL_image source in as unmodified form
|
||||
* as possible, so it'll be easy to diff. Yes, it does look evil, but it's
|
||||
* really just some local syntactic sugar - most things correspond directly
|
||||
* to DevIL calls. It's not that bad, honest ;-)
|
||||
* This will make it _much_ easier to track changes to SDL_Image.
|
||||
* - BenC
|
||||
*/
|
||||
|
||||
#define Sint8 ILbyte
|
||||
#define Sint16 ILshort
|
||||
#define Sint32 ILint
|
||||
#define Uint8 ILubyte
|
||||
#define Uint16 ILushort
|
||||
#define Uint32 ILuint
|
||||
|
||||
#define SDL_RWops void
|
||||
#define SDL_RWtell(s) itell()
|
||||
#define SDL_RWread(s,ptr,size,nmemb) iread(ptr,size,nmemb)
|
||||
#define SDL_RWseek(s,offset,whence) iseek(offset, IL_ ## whence)
|
||||
|
||||
|
||||
/* use different function names to avoid any possible symbol contamination
|
||||
* (user might also be linking with libSDL) */
|
||||
#define SDL_SwapBE32(i) iSDL_SwapBE32(i)
|
||||
#define SDL_SwapBE16(s) iSDL_SwapBE16(s)
|
||||
static Uint16 iSDL_SwapBE16( Uint16 s )
|
||||
{ Uint16 foo = s; iSwapUShort(&foo); return foo; }
|
||||
static Uint32 iSDL_SwapBE32( Uint32 i )
|
||||
{ Uint32 foo = i; iSwapUInt(&foo); return foo; }
|
||||
|
||||
/* rest of this file is as unchanged as possible from IMG_lbm.c - BenC */
|
||||
/***************************************************************************/
|
||||
|
||||
/* This is a ILBM image file loading framework
|
||||
Load IFF pictures, PBM & ILBM packing methods, with or without stencil
|
||||
Written by Daniel Morais ( Daniel AT Morais DOT com ) in September 2001.
|
||||
24 bits ILBM files support added by Marc Le Douarain (http://www.multimania.com/mavati)
|
||||
in December 2002.
|
||||
EHB and HAM (specific Amiga graphic chip modes) support added by Marc Le Douarain
|
||||
(http://www.multimania.com/mavati) in December 2003.
|
||||
Stencil and colorkey fixes by David Raulo (david.raulo AT free DOT fr) in February 2004.
|
||||
Buffer overflow fix in RLE decompression by David Raulo in January 2008.
|
||||
*/
|
||||
|
||||
|
||||
#define MAXCOLORS 256
|
||||
|
||||
/* Structure for an IFF picture ( BMHD = Bitmap Header ) */
|
||||
|
||||
/* TODO: SDL_Image seems to get away without any struct
|
||||
* packing... should it be added? */
|
||||
typedef struct
|
||||
{
|
||||
Uint16 w, h; /* width & height of the bitmap in pixels */
|
||||
Sint16 x, y; /* screen coordinates of the bitmap */
|
||||
Uint8 planes; /* number of planes of the bitmap */
|
||||
Uint8 mask; /* mask type ( 0 => no mask ) */
|
||||
Uint8 tcomp; /* compression type */
|
||||
Uint8 pad1; /* dummy value, for padding */
|
||||
Uint16 tcolor; /* transparent color */
|
||||
Uint8 xAspect, /* pixel aspect ratio */
|
||||
yAspect;
|
||||
Sint16 Lpage; /* width of the screen in pixels */
|
||||
Sint16 Hpage; /* height of the screen in pixels */
|
||||
} BMHD;
|
||||
|
||||
static int isLBM()
|
||||
{
|
||||
SDL_RWops* src = 0;
|
||||
int start;
|
||||
int is_LBM;
|
||||
Uint8 magic[4+4+4];
|
||||
|
||||
start = SDL_RWtell(src);
|
||||
is_LBM = 0;
|
||||
if ( SDL_RWread( src, magic, sizeof(magic), 1 ) )
|
||||
{
|
||||
if ( !memcmp( magic, "FORM", 4 ) &&
|
||||
( !memcmp( magic + 8, "PBM ", 4 ) ||
|
||||
!memcmp( magic + 8, "ILBM", 4 ) ) )
|
||||
{
|
||||
is_LBM = 1;
|
||||
}
|
||||
}
|
||||
SDL_RWseek(src, start, SEEK_SET);
|
||||
return( is_LBM );
|
||||
}
|
||||
|
||||
static ILboolean load_ilbm(void)
|
||||
{
|
||||
SDL_RWops* src = 0;
|
||||
struct { Uint8 r; Uint8 g; Uint8 b; } scratch_pal[MAXCOLORS];
|
||||
ILenum format; /* IL_RGB (ham or 24bit) or IL_COLOUR_INDEX */
|
||||
|
||||
int start;
|
||||
Uint8 id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
|
||||
Uint32 size, bytesloaded, nbcolors;
|
||||
Uint32 i, j, bytesperline, nbplanes, plane, h;
|
||||
Uint32 remainingbytes;
|
||||
Uint32 width;
|
||||
BMHD bmhd;
|
||||
char *error;
|
||||
Uint8 flagHAM,flagEHB;
|
||||
|
||||
error = NULL;
|
||||
MiniBuf = NULL;
|
||||
|
||||
start = SDL_RWtell(src);
|
||||
if ( !SDL_RWread( src, id, 4, 1 ) )
|
||||
{
|
||||
error="error reading IFF chunk";
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Should be the size of the file minus 4+4 ( 'FORM'+size ) */
|
||||
if ( !SDL_RWread( src, &size, 4, 1 ) )
|
||||
{
|
||||
error="error reading IFF chunk size";
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* As size is not used here, no need to swap it */
|
||||
|
||||
if ( memcmp( id, "FORM", 4 ) != 0 )
|
||||
{
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
error="not a IFF file";
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( !SDL_RWread( src, id, 4, 1 ) )
|
||||
{
|
||||
error="error reading IFF chunk";
|
||||
goto done;
|
||||
}
|
||||
|
||||
pbm = 0;
|
||||
|
||||
/* File format : PBM=Packed Bitmap, ILBM=Interleaved Bitmap */
|
||||
if ( !memcmp( id, "PBM ", 4 ) ) pbm = 1;
|
||||
else if ( memcmp( id, "ILBM", 4 ) )
|
||||
{
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
error="not a IFF picture";
|
||||
goto done;
|
||||
}
|
||||
|
||||
nbcolors = 0;
|
||||
|
||||
memset( &bmhd, 0, sizeof( BMHD ) );
|
||||
flagHAM = 0;
|
||||
flagEHB = 0;
|
||||
|
||||
while ( memcmp( id, "BODY", 4 ) != 0 )
|
||||
{
|
||||
if ( !SDL_RWread( src, id, 4, 1 ) )
|
||||
{
|
||||
error="error reading IFF chunk";
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( !SDL_RWread( src, &size, 4, 1 ) )
|
||||
{
|
||||
error="error reading IFF chunk size";
|
||||
goto done;
|
||||
}
|
||||
|
||||
bytesloaded = 0;
|
||||
|
||||
size = SDL_SwapBE32( size );
|
||||
|
||||
if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
|
||||
{
|
||||
if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
|
||||
{
|
||||
error="error reading BMHD chunk";
|
||||
goto done;
|
||||
}
|
||||
|
||||
bytesloaded = sizeof( BMHD );
|
||||
|
||||
bmhd.w = SDL_SwapBE16( bmhd.w );
|
||||
bmhd.h = SDL_SwapBE16( bmhd.h );
|
||||
bmhd.x = SDL_SwapBE16( bmhd.x );
|
||||
bmhd.y = SDL_SwapBE16( bmhd.y );
|
||||
bmhd.tcolor = SDL_SwapBE16( bmhd.tcolor );
|
||||
bmhd.Lpage = SDL_SwapBE16( bmhd.Lpage );
|
||||
bmhd.Hpage = SDL_SwapBE16( bmhd.Hpage );
|
||||
}
|
||||
|
||||
if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
|
||||
{
|
||||
if ( !SDL_RWread( src, &colormap, size, 1 ) )
|
||||
{
|
||||
error="error reading CMAP chunk";
|
||||
goto done;
|
||||
}
|
||||
|
||||
bytesloaded = size;
|
||||
nbcolors = size / 3;
|
||||
}
|
||||
|
||||
if ( !memcmp( id, "CAMG", 4 ) ) /* Amiga ViewMode */
|
||||
{
|
||||
Uint32 viewmodes;
|
||||
if ( !SDL_RWread( src, &viewmodes, sizeof(viewmodes), 1 ) )
|
||||
{
|
||||
error="error reading CAMG chunk";
|
||||
goto done;
|
||||
}
|
||||
|
||||
bytesloaded = size;
|
||||
viewmodes = SDL_SwapBE32( viewmodes );
|
||||
if ( viewmodes & 0x0800 )
|
||||
flagHAM = 1;
|
||||
if ( viewmodes & 0x0080 )
|
||||
flagEHB = 1;
|
||||
}
|
||||
|
||||
if ( memcmp( id, "BODY", 4 ) )
|
||||
{
|
||||
if ( size & 1 ) ++size; /* padding ! */
|
||||
size -= bytesloaded;
|
||||
/* skip the remaining bytes of this chunk */
|
||||
if ( size ) SDL_RWseek( src, size, SEEK_CUR );
|
||||
}
|
||||
}
|
||||
|
||||
/* compute some usefull values, based on the bitmap header */
|
||||
|
||||
width = ( bmhd.w + 15 ) & 0xFFFFFFF0; /* Width in pixels modulo 16 */
|
||||
|
||||
bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
|
||||
|
||||
nbplanes = bmhd.planes;
|
||||
|
||||
if ( pbm ) /* File format : 'Packed Bitmap' */
|
||||
{
|
||||
bytesperline *= 8;
|
||||
nbplanes = 1;
|
||||
}
|
||||
|
||||
if ( bmhd.mask & 1 ) ++nbplanes; /* There is a mask ( 'stencil' ) */
|
||||
|
||||
/* Allocate memory for a temporary buffer ( used for
|
||||
decompression/deinterleaving ) */
|
||||
|
||||
if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
|
||||
{
|
||||
ilSetError( IL_OUT_OF_MEMORY );
|
||||
error="no enough memory for temporary buffer";
|
||||
goto done;
|
||||
}
|
||||
|
||||
if( bmhd.planes==24 || flagHAM==1 ) {
|
||||
format = IL_BGR;
|
||||
} else {
|
||||
format = IL_COLOUR_INDEX;
|
||||
}
|
||||
if( !ilTexImage( width, bmhd.h, 1, (format==IL_COLOUR_INDEX)?1:3, format, IL_UNSIGNED_BYTE, NULL ) )
|
||||
goto done;
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
#if 0 /* No transparent colour support in DevIL? (TODO: confirm) */
|
||||
if ( bmhd.mask & 2 ) /* There is a transparent color */
|
||||
SDL_SetColorKey( Image, SDL_SRCCOLORKEY, bmhd.tcolor );
|
||||
#endif
|
||||
|
||||
/* Update palette informations */
|
||||
|
||||
/* There is no palette in 24 bits ILBM file */
|
||||
if ( nbcolors>0 && flagHAM==0 )
|
||||
{
|
||||
int nbrcolorsfinal = 1 << nbplanes;
|
||||
ptr = &colormap[0];
|
||||
|
||||
for ( i=0; i<nbcolors; i++ )
|
||||
{
|
||||
scratch_pal[i].r = *ptr++;
|
||||
scratch_pal[i].g = *ptr++;
|
||||
scratch_pal[i].b = *ptr++;
|
||||
}
|
||||
|
||||
/* Amiga EHB mode (Extra-Half-Bright) */
|
||||
/* 6 bitplanes mode with a 32 colors palette */
|
||||
/* The 32 last colors are the same but divided by 2 */
|
||||
/* Some Amiga pictures save 64 colors with 32 last wrong colors, */
|
||||
/* they shouldn't !, and here we overwrite these 32 bad colors. */
|
||||
if ( (nbcolors==32 || flagEHB ) && (1<<bmhd.planes)==64 )
|
||||
{
|
||||
nbcolors = 64;
|
||||
ptr = &colormap[0];
|
||||
for ( i=32; i<64; i++ )
|
||||
{
|
||||
scratch_pal[i].r = (*ptr++)/2;
|
||||
scratch_pal[i].g = (*ptr++)/2;
|
||||
scratch_pal[i].b = (*ptr++)/2;
|
||||
}
|
||||
}
|
||||
|
||||
/* If nbcolors < 2^nbplanes, repeat the colormap */
|
||||
/* This happens when pictures have a stencil mask */
|
||||
if ( nbrcolorsfinal > (1<<bmhd.planes) ) {
|
||||
nbrcolorsfinal = (1<<bmhd.planes);
|
||||
}
|
||||
for ( i=nbcolors; i < (Uint32)nbrcolorsfinal; i++ )
|
||||
{
|
||||
scratch_pal[i].r = scratch_pal[i%nbcolors].r;
|
||||
scratch_pal[i].g = scratch_pal[i%nbcolors].g;
|
||||
scratch_pal[i].b = scratch_pal[i%nbcolors].b;
|
||||
}
|
||||
|
||||
if ( !pbm )
|
||||
ilRegisterPal( scratch_pal, 3*nbrcolorsfinal, IL_PAL_RGB24 );
|
||||
|
||||
}
|
||||
|
||||
/* Get the bitmap */
|
||||
|
||||
for ( h=0; h < bmhd.h; h++ )
|
||||
{
|
||||
/* uncompress the datas of each planes */
|
||||
|
||||
for ( plane=0; plane < nbplanes; plane++ )
|
||||
{
|
||||
ptr = MiniBuf + ( plane * bytesperline );
|
||||
|
||||
remainingbytes = bytesperline;
|
||||
|
||||
if ( bmhd.tcomp == 1 ) /* Datas are compressed */
|
||||
{
|
||||
do
|
||||
{
|
||||
if ( !SDL_RWread( src, &count, 1, 1 ) )
|
||||
{
|
||||
error="error reading BODY chunk";
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( count & 0x80 )
|
||||
{
|
||||
count ^= 0xFF;
|
||||
count += 2; /* now it */
|
||||
|
||||
if ( ( count > remainingbytes ) || !SDL_RWread( src, &color, 1, 1 ) )
|
||||
{
|
||||
if( count>remainingbytes)
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE );
|
||||
error="error reading BODY chunk";
|
||||
goto done;
|
||||
}
|
||||
memset( ptr, color, count );
|
||||
}
|
||||
else
|
||||
{
|
||||
++count;
|
||||
|
||||
if ( ( count > remainingbytes ) || !SDL_RWread( src, ptr, count, 1 ) )
|
||||
{
|
||||
if( count>remainingbytes)
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE );
|
||||
error="error reading BODY chunk";
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ptr += count;
|
||||
remainingbytes -= count;
|
||||
|
||||
} while ( remainingbytes > 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
|
||||
{
|
||||
error="error reading BODY chunk";
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* One line has been read, store it ! */
|
||||
|
||||
ptr = ilGetData();
|
||||
if ( nbplanes==24 || flagHAM==1 )
|
||||
ptr += h * width * 3;
|
||||
else
|
||||
ptr += h * width;
|
||||
|
||||
if ( pbm ) /* File format : 'Packed Bitmap' */
|
||||
{
|
||||
memcpy( ptr, MiniBuf, width );
|
||||
}
|
||||
else /* We have to un-interlace the bits ! */
|
||||
{
|
||||
if ( nbplanes!=24 && flagHAM==0 )
|
||||
{
|
||||
size = ( width + 7 ) / 8;
|
||||
|
||||
for ( i=0; i < size; i++ )
|
||||
{
|
||||
memset( ptr, 0, 8 );
|
||||
|
||||
for ( plane=0; plane < nbplanes; plane++ )
|
||||
{
|
||||
color = *( MiniBuf + i + ( plane * bytesperline ) );
|
||||
msk = 0x80;
|
||||
|
||||
for ( j=0; j<8; j++ )
|
||||
{
|
||||
if ( ( plane + j ) <= 7 ) ptr[j] |= (Uint8)( color & msk ) >> ( 7 - plane - j );
|
||||
else ptr[j] |= (Uint8)( color & msk ) << ( plane + j - 7 );
|
||||
|
||||
msk >>= 1;
|
||||
}
|
||||
}
|
||||
ptr += 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Uint32 finalcolor = 0;
|
||||
size = ( width + 7 ) / 8;
|
||||
/* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
|
||||
/* or HAM (6 bitplanes) or HAM8 (8 bitplanes) modes */
|
||||
for ( i=0; i<width; i=i+8 )
|
||||
{
|
||||
Uint8 maskBit = 0x80;
|
||||
for ( j=0; j<8; j++ )
|
||||
{
|
||||
Uint32 pixelcolor = 0;
|
||||
Uint32 maskColor = 1;
|
||||
Uint8 dataBody;
|
||||
for ( plane=0; plane < nbplanes; plane++ )
|
||||
{
|
||||
dataBody = MiniBuf[ plane*size+i/8 ];
|
||||
if ( dataBody&maskBit )
|
||||
pixelcolor = pixelcolor | maskColor;
|
||||
maskColor = maskColor<<1;
|
||||
}
|
||||
/* HAM : 12 bits RGB image (4 bits per color component) */
|
||||
/* HAM8 : 18 bits RGB image (6 bits per color component) */
|
||||
if ( flagHAM )
|
||||
{
|
||||
switch( pixelcolor>>(nbplanes-2) )
|
||||
{
|
||||
case 0: /* take direct color from palette */
|
||||
finalcolor = colormap[ pixelcolor*3 ] + (colormap[ pixelcolor*3+1 ]<<8) + (colormap[ pixelcolor*3+2 ]<<16);
|
||||
break;
|
||||
case 1: /* modify only blue component */
|
||||
finalcolor = finalcolor&0x00FFFF;
|
||||
finalcolor = finalcolor | (pixelcolor<<(16+(10-nbplanes)));
|
||||
break;
|
||||
case 2: /* modify only red component */
|
||||
finalcolor = finalcolor&0xFFFF00;
|
||||
finalcolor = finalcolor | pixelcolor<<(10-nbplanes);
|
||||
break;
|
||||
case 3: /* modify only green component */
|
||||
finalcolor = finalcolor&0xFF00FF;
|
||||
finalcolor = finalcolor | (pixelcolor<<(8+(10-nbplanes)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
finalcolor = pixelcolor;
|
||||
}
|
||||
#if defined( __LITTLE_ENDIAN__ )
|
||||
{
|
||||
*ptr++ = (Uint8)(finalcolor>>16);
|
||||
*ptr++ = (Uint8)(finalcolor>>8);
|
||||
*ptr++ = (Uint8)(finalcolor);
|
||||
}
|
||||
#else
|
||||
{
|
||||
*ptr++ = (Uint8)(finalcolor);
|
||||
*ptr++ = (Uint8)(finalcolor>>8);
|
||||
*ptr++ = (Uint8)(finalcolor>>16);
|
||||
}
|
||||
#endif
|
||||
maskBit = maskBit>>1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if ( MiniBuf ) free( MiniBuf );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
/* fprintf(stderr,"il_ilbm.c: '%s'\n",error); */
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif//IL_NO_ILBM
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2008 by Denton Woods
|
||||
// Last modified: 11/08/2008
|
||||
//
|
||||
// Filename: src-IL/src/il_internal.c
|
||||
//
|
||||
// Description: Internal stuff for DevIL
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
ILimage *iCurImage = NULL;
|
||||
|
||||
|
||||
/* Siigron: added this for Linux... a #define should work, but for some reason
|
||||
it doesn't (anyone who knows why?) */
|
||||
#if !_WIN32 || (_WIN32 && __GNUC__) // Cygwin
|
||||
int stricmp(const char *src1, const char *src2)
|
||||
{
|
||||
return strcasecmp(src1, src2);
|
||||
}
|
||||
int strnicmp(const char *src1, const char *src2, size_t max)
|
||||
{
|
||||
return strncasecmp(src1, src2, max);
|
||||
}
|
||||
#elif _WIN32_WCE
|
||||
int stricmp(const char *src1, const char *src2)
|
||||
{
|
||||
return _stricmp(src1, src2);
|
||||
}
|
||||
int strnicmp(const char *src1, const char *src2, size_t max)
|
||||
{
|
||||
return _strnicmp(src1, src2, max);
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
char *strdup(const char *src)
|
||||
{
|
||||
return _strdup(src);
|
||||
}
|
||||
#endif//_WIN32_WCE
|
||||
|
||||
|
||||
#ifdef _UNICODE
|
||||
int iStrCmp(ILconst_string src1, ILconst_string src2)
|
||||
{
|
||||
return wcsicmp(src1, src2);
|
||||
}
|
||||
#else
|
||||
int iStrCmp(ILconst_string src1, ILconst_string src2)
|
||||
{
|
||||
return stricmp(src1, src2);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//! Glut's portability.txt says to use this...
|
||||
ILstring ilStrDup(ILconst_string Str)
|
||||
{
|
||||
ILstring copy;
|
||||
|
||||
copy = (ILstring)ialloc((ilStrLen(Str) + 1) * sizeof(ILchar));
|
||||
if (copy == NULL)
|
||||
return NULL;
|
||||
iStrCpy(copy, Str);
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
// Because MSVC++'s version is too stupid to check for NULL...
|
||||
ILuint ilStrLen(ILconst_string Str)
|
||||
{
|
||||
ILconst_string eos = Str;
|
||||
|
||||
if (Str == NULL)
|
||||
return 0;
|
||||
|
||||
while (*eos++);
|
||||
|
||||
return((int)(eos - Str - 1));
|
||||
}
|
||||
|
||||
|
||||
// Because MSVC++'s version is too stupid to check for NULL...
|
||||
// Passing NULL to strlen will definitely cause a crash.
|
||||
ILuint ilCharStrLen(const char *Str)
|
||||
{
|
||||
const char *eos = Str;
|
||||
|
||||
if (Str == NULL)
|
||||
return 0;
|
||||
|
||||
while (*eos++);
|
||||
|
||||
return((int)(eos - Str - 1));
|
||||
}
|
||||
|
||||
|
||||
// Simple function to test if a filename has a given extension, disregarding case
|
||||
ILboolean iCheckExtension(ILconst_string Arg, ILconst_string Ext)
|
||||
{
|
||||
ILboolean PeriodFound = IL_FALSE;
|
||||
ILint i, Len;
|
||||
ILstring Argu = (ILstring)Arg;
|
||||
|
||||
if (Arg == NULL || Ext == NULL || !ilStrLen(Arg) || !ilStrLen(Ext)) // if not a good filename/extension, exit early
|
||||
return IL_FALSE;
|
||||
|
||||
Len = ilStrLen(Arg);
|
||||
Argu += Len; // start at the end
|
||||
|
||||
for (i = Len; i >= 0; i--) {
|
||||
if (*Argu == '.') { // try to find a period
|
||||
PeriodFound = IL_TRUE;
|
||||
break;
|
||||
}
|
||||
Argu--;
|
||||
}
|
||||
|
||||
if (!PeriodFound) // if no period, no extension
|
||||
return IL_FALSE;
|
||||
|
||||
if (!iStrCmp(Argu+1, Ext)) // extension and ext match?
|
||||
return IL_TRUE;
|
||||
|
||||
return IL_FALSE; // if all else fails, return IL_FALSE
|
||||
}
|
||||
|
||||
|
||||
ILstring iGetExtension(ILconst_string FileName)
|
||||
{
|
||||
ILboolean PeriodFound = IL_FALSE;
|
||||
ILstring Ext = (ILstring)FileName;
|
||||
ILint i, Len = ilStrLen(FileName);
|
||||
|
||||
if (FileName == NULL || !Len) // if not a good filename/extension, exit early
|
||||
return NULL;
|
||||
|
||||
Ext += Len; // start at the end
|
||||
|
||||
for (i = Len; i >= 0; i--) {
|
||||
if (*Ext == '.') { // try to find a period
|
||||
PeriodFound = IL_TRUE;
|
||||
break;
|
||||
}
|
||||
Ext--;
|
||||
}
|
||||
|
||||
if (!PeriodFound) // if no period, no extension
|
||||
return NULL;
|
||||
|
||||
return Ext+1;
|
||||
}
|
||||
|
||||
|
||||
// Checks if the file exists
|
||||
ILboolean iFileExists(ILconst_string FileName)
|
||||
{
|
||||
#if (!defined(_UNICODE) || !defined(_WIN32))
|
||||
FILE *CheckFile = fopen(FileName, "rb");
|
||||
#else // Windows uses _wfopen instead.
|
||||
FILE *CheckFile = _wfopen(FileName, L"rb");
|
||||
#endif//_UNICODE
|
||||
|
||||
if (CheckFile) {
|
||||
fclose(CheckFile);
|
||||
return IL_TRUE;
|
||||
}
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// Last time I tried, MSVC++'s fgets() was really really screwy
|
||||
ILbyte *iFgets(char *buffer, ILuint maxlen)
|
||||
{
|
||||
ILuint counter = 0;
|
||||
ILint temp = '\0';
|
||||
|
||||
while ((temp = igetc()) && temp != '\n' && temp != IL_EOF && counter < maxlen) {
|
||||
buffer[counter] = temp;
|
||||
counter++;
|
||||
}
|
||||
buffer[counter] = '\0';
|
||||
|
||||
if (temp == IL_EOF && counter == 0) // Only return NULL if no data was "got".
|
||||
return NULL;
|
||||
|
||||
return (ILbyte*)buffer;
|
||||
}
|
||||
|
||||
|
||||
// A fast integer squareroot, completely accurate for x < 289.
|
||||
// Taken from http://atoms.org.uk/sqrt/
|
||||
// There is also a version that is accurate for all integers
|
||||
// < 2^31, if we should need it
|
||||
|
||||
static int table[] = {
|
||||
0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57,
|
||||
59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83,
|
||||
84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101, 102,
|
||||
103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118,
|
||||
119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131, 132,
|
||||
133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145,
|
||||
146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 157,
|
||||
158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168,
|
||||
169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178,
|
||||
179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188,
|
||||
189, 189, 190, 191, 192, 192, 193, 193, 194, 195, 195, 196, 197, 197,
|
||||
198, 199, 199, 200, 201, 201, 202, 203, 203, 204, 204, 205, 206, 206,
|
||||
207, 208, 208, 209, 209, 210, 211, 211, 212, 212, 213, 214, 214, 215,
|
||||
215, 216, 217, 217, 218, 218, 219, 219, 220, 221, 221, 222, 222, 223,
|
||||
224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, 230, 231,
|
||||
231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
|
||||
239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246,
|
||||
246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253,
|
||||
253, 254, 254, 255
|
||||
};
|
||||
|
||||
int iSqrt(int x) {
|
||||
if (x >= 0x10000) {
|
||||
if (x >= 0x1000000) {
|
||||
if (x >= 0x10000000) {
|
||||
if (x >= 0x40000000) {
|
||||
return (table[x >> 24] << 8);
|
||||
} else {
|
||||
return (table[x >> 22] << 7);
|
||||
}
|
||||
} else if (x >= 0x4000000) {
|
||||
return (table[x >> 20] << 6);
|
||||
} else {
|
||||
return (table[x >> 18] << 5);
|
||||
}
|
||||
} else if (x >= 0x100000) {
|
||||
if (x >= 0x400000) {
|
||||
return (table[x >> 16] << 4);
|
||||
} else {
|
||||
return (table[x >> 14] << 3);
|
||||
}
|
||||
} else if (x >= 0x40000) {
|
||||
return (table[x >> 12] << 2);
|
||||
} else {
|
||||
return (table[x >> 10] << 1);
|
||||
}
|
||||
} else if (x >= 0x100) {
|
||||
if (x >= 0x1000) {
|
||||
if (x >= 0x4000) {
|
||||
return (table[x >> 8]);
|
||||
} else {
|
||||
return (table[x >> 6] >> 1);
|
||||
}
|
||||
} else if (x >= 0x400) {
|
||||
return (table[x >> 4] >> 2);
|
||||
} else {
|
||||
return (table[x >> 2] >> 3);
|
||||
}
|
||||
} else if (x >= 0) {
|
||||
return table[x] >> 4;
|
||||
}
|
||||
|
||||
//hm, x was negative....
|
||||
return -1;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,401 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/04/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_iwi.c
|
||||
//
|
||||
// Description: Reads from an Infinity Ward Image (.iwi) file from Call of Duty.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_IWI
|
||||
#include "il_dds.h"
|
||||
|
||||
typedef struct IWIHEAD
|
||||
{
|
||||
ILuint Signature;
|
||||
ILubyte Format;
|
||||
ILubyte Flags;
|
||||
ILushort Width;
|
||||
ILushort Height;
|
||||
} IWIHEAD;
|
||||
|
||||
#define IWI_ARGB8 0x01
|
||||
#define IWI_RGB8 0x02
|
||||
#define IWI_ARGB4 0x03
|
||||
#define IWI_A8 0x04
|
||||
#define IWI_JPG 0x07
|
||||
#define IWI_DXT1 0x0B
|
||||
#define IWI_DXT3 0x0C
|
||||
#define IWI_DXT5 0x0D
|
||||
|
||||
ILboolean iIsValidIwi(void);
|
||||
ILboolean iCheckIwi(IWIHEAD *Header);
|
||||
ILboolean iLoadIwiInternal(void);
|
||||
ILboolean IwiInitMipmaps(ILimage *BaseImage, ILuint *NumMips);
|
||||
ILboolean IwiReadImage(ILimage *BaseImage, IWIHEAD *Header, ILuint NumMips);
|
||||
ILenum IwiGetFormat(ILubyte Format, ILubyte *Bpp);
|
||||
|
||||
//! Checks if the file specified in FileName is a valid IWI file.
|
||||
ILboolean ilIsValidIwi(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE IwiFile;
|
||||
ILboolean bIwi = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("iwi"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bIwi;
|
||||
}
|
||||
|
||||
IwiFile = iopenr(FileName);
|
||||
if (IwiFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bIwi;
|
||||
}
|
||||
|
||||
bIwi = ilIsValidIwiF(IwiFile);
|
||||
icloser(IwiFile);
|
||||
|
||||
return bIwi;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid IWI file at the current position.
|
||||
ILboolean ilIsValidIwiF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidIwi();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid IWI lump.
|
||||
ILboolean ilIsValidIwiL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidIwi();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the IWI header from the current file.
|
||||
ILboolean iGetIwiHead(IWIHEAD *Header)
|
||||
{
|
||||
Header->Signature = GetLittleUInt();
|
||||
Header->Format = igetc();
|
||||
Header->Flags = igetc(); //@TODO: Find out what the flags mean.
|
||||
Header->Width = GetLittleUShort();
|
||||
Header->Height = GetLittleUShort();
|
||||
|
||||
// @TODO: Find out what is in the rest of the header.
|
||||
iseek(18, IL_SEEK_CUR);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidIwi(void)
|
||||
{
|
||||
IWIHEAD Header;
|
||||
ILuint Pos = itell();
|
||||
|
||||
if (!iGetIwiHead(&Header))
|
||||
return IL_FALSE;
|
||||
// The length of the header varies, so we just go back to the original position.
|
||||
iseek(Pos, IL_SEEK_CUR);
|
||||
|
||||
return iCheckIwi(&Header);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid IWI header.
|
||||
ILboolean iCheckIwi(IWIHEAD *Header)
|
||||
{
|
||||
if (Header->Signature != 0x06695749 && Header->Signature != 0x05695749) // 'IWi-' (version 6, and version 5 is the second).
|
||||
return IL_FALSE;
|
||||
if (Header->Width == 0 || Header->Height == 0)
|
||||
return IL_FALSE;
|
||||
// DXT images must have power-of-2 dimensions.
|
||||
if (Header->Format == IWI_DXT1 || Header->Format == IWI_DXT3 || Header->Format == IWI_DXT5)
|
||||
if (Header->Width != ilNextPower2(Header->Width) || Header->Height != ilNextPower2(Header->Height))
|
||||
return IL_FALSE;
|
||||
// 0x0B, 0x0C and 0x0D are DXT formats.
|
||||
if (Header->Format != IWI_ARGB4 && Header->Format != IWI_RGB8 && Header->Format != IWI_ARGB8 && Header->Format != IWI_A8
|
||||
&& Header->Format != IWI_DXT1 && Header->Format != IWI_DXT3 && Header->Format != IWI_DXT5)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a IWI file
|
||||
ILboolean ilLoadIwi(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE IwiFile;
|
||||
ILboolean bIwi = IL_FALSE;
|
||||
|
||||
IwiFile = iopenr(FileName);
|
||||
if (IwiFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bIwi;
|
||||
}
|
||||
|
||||
bIwi = ilLoadIwiF(IwiFile);
|
||||
icloser(IwiFile);
|
||||
|
||||
return bIwi;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened IWI file
|
||||
ILboolean ilLoadIwiF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadIwiInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a IWI
|
||||
ILboolean ilLoadIwiL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadIwiInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the IWI.
|
||||
ILboolean iLoadIwiInternal(void)
|
||||
{
|
||||
IWIHEAD Header;
|
||||
ILuint NumMips = 0;
|
||||
ILboolean HasMipmaps = IL_TRUE;
|
||||
ILenum Format;
|
||||
ILubyte Bpp;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Read the header and check it.
|
||||
if (!iGetIwiHead(&Header))
|
||||
return IL_FALSE;
|
||||
if (!iCheckIwi(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// From a post by Pointy on http://iwnation.com/forums/index.php?showtopic=27903,
|
||||
// flags ending with 0x3 have no mipmaps.
|
||||
HasMipmaps = ((Header.Flags & 0x03) == 0x03) ? IL_FALSE : IL_TRUE;
|
||||
|
||||
// Create the image, then create the mipmaps, then finally read the image.
|
||||
Format = IwiGetFormat(Header.Format, &Bpp);
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, Bpp, Format, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
if (HasMipmaps)
|
||||
if (!IwiInitMipmaps(iCurImage, &NumMips))
|
||||
return IL_FALSE;
|
||||
if (!IwiReadImage(iCurImage, &Header, NumMips))
|
||||
return IL_FALSE;
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
// Helper function to convert IWI formats to DevIL formats and Bpp.
|
||||
ILenum IwiGetFormat(ILubyte Format, ILubyte *Bpp)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case IWI_ARGB8:
|
||||
*Bpp = 4;
|
||||
return IL_BGRA;
|
||||
case IWI_RGB8:
|
||||
*Bpp = 3;
|
||||
return IL_BGR;
|
||||
case IWI_ARGB4:
|
||||
*Bpp = 4;
|
||||
return IL_BGRA;
|
||||
case IWI_A8:
|
||||
*Bpp = 1;
|
||||
return IL_ALPHA;
|
||||
case IWI_DXT1:
|
||||
*Bpp = 4;
|
||||
return IL_RGBA;
|
||||
case IWI_DXT3:
|
||||
*Bpp = 4;
|
||||
return IL_RGBA;
|
||||
case IWI_DXT5:
|
||||
*Bpp = 4;
|
||||
return IL_RGBA;
|
||||
}
|
||||
|
||||
return 0; // Will never reach this.
|
||||
}
|
||||
|
||||
|
||||
// Function to intialize the mipmaps and determine the number of mipmaps.
|
||||
ILboolean IwiInitMipmaps(ILimage *BaseImage, ILuint *NumMips)
|
||||
{
|
||||
ILimage *Image;
|
||||
ILuint Width, Height, Mipmap;
|
||||
|
||||
Image = BaseImage;
|
||||
Width = BaseImage->Width; Height = BaseImage->Height;
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
for (Mipmap = 0; Width != 1 && Height != 1; Mipmap++) {
|
||||
// 1 is the smallest dimension possible.
|
||||
Width = (Width >> 1) == 0 ? 1 : (Width >> 1);
|
||||
Height = (Height >> 1) == 0 ? 1 : (Height >> 1);
|
||||
|
||||
Image->Mipmaps = ilNewImageFull(Width, Height, 1, BaseImage->Bpp, BaseImage->Format, BaseImage->Type, NULL);
|
||||
if (Image->Mipmaps == NULL)
|
||||
return IL_FALSE;
|
||||
Image = Image->Mipmaps;
|
||||
|
||||
// ilNewImage does not set these.
|
||||
Image->Format = BaseImage->Format;
|
||||
Image->Type = BaseImage->Type;
|
||||
// The origin is in the upper left.
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
}
|
||||
|
||||
*NumMips = Mipmap;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean IwiReadImage(ILimage *BaseImage, IWIHEAD *Header, ILuint NumMips)
|
||||
{
|
||||
ILimage *Image;
|
||||
ILuint SizeOfData;
|
||||
ILubyte *CompData = NULL;
|
||||
ILint i, j, k, m;
|
||||
|
||||
for (i = NumMips; i >= 0; i--) {
|
||||
Image = BaseImage;
|
||||
// Go to the ith mipmap level.
|
||||
// The mipmaps go from smallest to the largest.
|
||||
for (j = 0; j < i; j++)
|
||||
Image = Image->Mipmaps;
|
||||
|
||||
switch (Header->Format)
|
||||
{
|
||||
case IWI_ARGB8: // These are all
|
||||
case IWI_RGB8: // uncompressed data,
|
||||
case IWI_A8: // so just read it.
|
||||
if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData)
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case IWI_ARGB4: //@TODO: Find some test images for this.
|
||||
// Data is in ARGB4 format - 4 bits per component.
|
||||
SizeOfData = Image->Width * Image->Height * 2;
|
||||
CompData = ialloc(SizeOfData); // Not really compressed - just in ARGB4 format.
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
for (k = 0, m = 0; k < (ILint)Image->SizeOfData; k += 4, m += 2) {
|
||||
// @TODO: Double the image data into the low and high nibbles for a better range of values.
|
||||
Image->Data[k+0] = CompData[m] & 0xF0;
|
||||
Image->Data[k+1] = (CompData[m] & 0x0F) << 4;
|
||||
Image->Data[k+2] = CompData[m+1] & 0xF0;
|
||||
Image->Data[k+3] = (CompData[m+1] & 0x0F) << 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case IWI_DXT1:
|
||||
// DXT1 data has at least 8 bytes, even for one pixel.
|
||||
SizeOfData = IL_MAX(Image->Width * Image->Height / 2, 8);
|
||||
CompData = ialloc(SizeOfData); // Gives a 6:1 compression ratio (or 8:1 for DXT1 with alpha)
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Decompress the DXT1 data into Image (ith mipmap).
|
||||
if (!DecompressDXT1(Image, CompData)) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Keep a copy of the DXTC data if the user wants it.
|
||||
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
|
||||
Image->DxtcSize = SizeOfData;
|
||||
Image->DxtcData = CompData;
|
||||
Image->DxtcFormat = IL_DXT1;
|
||||
CompData = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IWI_DXT3:
|
||||
// DXT3 data has at least 16 bytes, even for one pixel.
|
||||
SizeOfData = IL_MAX(Image->Width * Image->Height, 16);
|
||||
CompData = ialloc(SizeOfData); // Gives a 4:1 compression ratio
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Decompress the DXT3 data into Image (ith mipmap).
|
||||
if (!DecompressDXT3(Image, CompData)) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case IWI_DXT5:
|
||||
// DXT5 data has at least 16 bytes, even for one pixel.
|
||||
SizeOfData = IL_MAX(Image->Width * Image->Height, 16);
|
||||
CompData = ialloc(SizeOfData); // Gives a 4:1 compression ratio
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Decompress the DXT5 data into Image (ith mipmap).
|
||||
if (!DecompressDXT5(Image, CompData)) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ifree(CompData);
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_IWI
|
||||
@@ -0,0 +1,823 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_jp2.c
|
||||
//
|
||||
// Description: Jpeg-2000 (.jp2) functions
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_JP2
|
||||
#include <jasper/jasper.h>
|
||||
#include "il_jp2.h"
|
||||
|
||||
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#ifndef _DEBUG
|
||||
#pragma comment(lib, "libjasper.lib")
|
||||
#else
|
||||
#pragma comment(lib, "libjasper-d.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ILboolean iIsValidJp2(void);
|
||||
|
||||
ILboolean JasperInit = IL_FALSE;
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid .jp2 file.
|
||||
ILboolean ilIsValidJp2(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE Jp2File;
|
||||
ILboolean bJp2 = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("jp2")) && !iCheckExtension(FileName, IL_TEXT("jpx")) &&
|
||||
!iCheckExtension(FileName, IL_TEXT("j2k")) && !iCheckExtension(FileName, IL_TEXT("j2c"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bJp2;
|
||||
}
|
||||
|
||||
Jp2File = iopenr(FileName);
|
||||
if (Jp2File == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bJp2;
|
||||
}
|
||||
|
||||
bJp2 = ilIsValidJp2F(Jp2File);
|
||||
icloser(Jp2File);
|
||||
|
||||
return bJp2;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid .jp2 file at the current position.
|
||||
ILboolean ilIsValidJp2F(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidJp2();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid .jp2 lump.
|
||||
ILboolean ilIsValidJp2L(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidJp2();
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidJp2(void)
|
||||
{
|
||||
ILubyte Signature[4];
|
||||
|
||||
iseek(4, IL_SEEK_CUR); // Skip the 4 bytes that tell the size of the signature box.
|
||||
if (iread(Signature, 1, 4) != 4) {
|
||||
iseek(-4, IL_SEEK_CUR);
|
||||
return IL_FALSE; // File read error
|
||||
}
|
||||
|
||||
iseek(-8, IL_SEEK_CUR); // Restore to previous state
|
||||
|
||||
// Signature is 'jP\040\040' by the specs (or 0x6A502020).
|
||||
// http://www.jpeg.org/public/fcd15444-6.pdf
|
||||
if (Signature[0] != 0x6A || Signature[1] != 0x50 ||
|
||||
Signature[2] != 0x20 || Signature[3] != 0x20)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a Jpeg2000 file.
|
||||
ILboolean ilLoadJp2(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE Jp2File;
|
||||
ILboolean bRet;
|
||||
|
||||
Jp2File = iopenr(FileName);
|
||||
if (Jp2File == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
bRet = ilLoadJp2F(Jp2File);
|
||||
icloser(Jp2File);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened Jpeg2000 file.
|
||||
ILboolean ilLoadJp2F(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
jas_stream_t *Stream;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
|
||||
if (!JasperInit) {
|
||||
if (jas_init()) {
|
||||
ilSetError(IL_LIB_JP2_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
JasperInit = IL_TRUE;
|
||||
}
|
||||
Stream = iJp2ReadStream();
|
||||
if (!Stream)
|
||||
{
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
bRet = iLoadJp2Internal(Stream, NULL);
|
||||
// Close the input stream.
|
||||
jas_stream_close(Stream);
|
||||
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a Jpeg2000 stream.
|
||||
ILboolean ilLoadJp2L(const void *Lump, ILuint Size)
|
||||
{
|
||||
return ilLoadJp2LInternal(Lump, Size, NULL);
|
||||
}
|
||||
|
||||
|
||||
//! This is separated so that it can be called for other file types, such as .icns.
|
||||
ILboolean ilLoadJp2LInternal(const void *Lump, ILuint Size, ILimage *Image)
|
||||
{
|
||||
ILboolean bRet;
|
||||
jas_stream_t *Stream;
|
||||
|
||||
if (!JasperInit) {
|
||||
if (jas_init()) {
|
||||
ilSetError(IL_LIB_JP2_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
JasperInit = IL_TRUE;
|
||||
}
|
||||
Stream = jas_stream_memopen((char*)Lump, Size);
|
||||
if (!Stream)
|
||||
{
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
bRet = iLoadJp2Internal(Stream, Image);
|
||||
// Close the input stream.
|
||||
jas_stream_close(Stream);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the Jpeg2000 stream.
|
||||
ILboolean iLoadJp2Internal(jas_stream_t *Stream, ILimage *Image)
|
||||
{
|
||||
jas_image_t *Jp2Image = NULL;
|
||||
jas_matrix_t *origdata;
|
||||
ILuint x, y, c, Error;
|
||||
ILimage *TempImage;
|
||||
|
||||
// Decode image
|
||||
Jp2Image = jas_image_decode(Stream, -1, 0);
|
||||
if (!Jp2Image)
|
||||
{
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
jas_stream_close(Stream);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// JasPer likes to buffer a lot, so it may try buffering past the end
|
||||
// of the file. iread naturally sets IL_FILE_READ_ERROR if it tries
|
||||
// reading past the end of the file, but this actually is not an error.
|
||||
Error = ilGetError();
|
||||
// Put the error back if it is not IL_FILE_READ_ERROR.
|
||||
if (Error != IL_FILE_READ_ERROR)
|
||||
ilSetError(Error);
|
||||
|
||||
|
||||
// We're not supporting anything other than 8 bits/component yet.
|
||||
if (jas_image_cmptprec(Jp2Image, 0) != 8)
|
||||
{
|
||||
jas_image_destroy(Jp2Image);
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
switch (jas_image_numcmpts(Jp2Image))
|
||||
{
|
||||
//@TODO: Can we do alpha data? jas_image_cmpttype always returns 0 for this case.
|
||||
case 1: // Assuming this is luminance data.
|
||||
if (Image == NULL) {
|
||||
ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL);
|
||||
TempImage = iCurImage;
|
||||
}
|
||||
else {
|
||||
ifree(Image->Data); // @TODO: Not really the most efficient way to do this...
|
||||
ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL);
|
||||
TempImage = Image;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // Assuming this is luminance-alpha data.
|
||||
if (Image == NULL) {
|
||||
ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 2, IL_LUMINANCE_ALPHA, IL_UNSIGNED_BYTE, NULL);
|
||||
TempImage = iCurImage;
|
||||
}
|
||||
else {
|
||||
ifree(Image->Data); // @TODO: Not really the most efficient way to do this...
|
||||
ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 2, IL_LUMINANCE_ALPHA, IL_UNSIGNED_BYTE, NULL);
|
||||
TempImage = Image;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (Image == NULL) {
|
||||
ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
|
||||
TempImage = iCurImage;
|
||||
}
|
||||
else {
|
||||
ifree(Image->Data); // @TODO: Not really the most efficient way to do this...
|
||||
ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
|
||||
TempImage = Image;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (Image == NULL) {
|
||||
ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
|
||||
TempImage = iCurImage;
|
||||
}
|
||||
else {
|
||||
ifree(Image->Data); // @TODO: Not really the most efficient way to do this...
|
||||
ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
|
||||
TempImage = Image;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
jas_image_destroy(Jp2Image);
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
TempImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
// JasPer stores the data channels separately.
|
||||
// I am assuming RGBA format. Is it possible for other formats to be included?
|
||||
for (c = 0; c < TempImage->Bpp; c++)
|
||||
{
|
||||
origdata = jas_matrix_create(TempImage->Height, TempImage->Width);
|
||||
if (!origdata)
|
||||
{
|
||||
ilSetError(IL_LIB_JP2_ERROR);
|
||||
return IL_FALSE; // @TODO: Error
|
||||
}
|
||||
// Have to convert data into an intermediate matrix format.
|
||||
if (jas_image_readcmpt(Jp2Image, c, 0, 0, TempImage->Width, TempImage->Height, origdata))
|
||||
{
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
for (y = 0; y < TempImage->Height; y++)
|
||||
{
|
||||
for (x = 0; x < TempImage->Width; x++)
|
||||
{
|
||||
TempImage->Data[y * TempImage->Width * TempImage->Bpp + x * TempImage->Bpp + c] = origdata->data_[y * origdata->numcols_ + x];
|
||||
}
|
||||
}
|
||||
|
||||
jas_matrix_destroy(origdata);
|
||||
}
|
||||
|
||||
jas_image_destroy(Jp2Image);
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int iJp2_file_read(jas_stream_obj_t *obj, char *buf, int cnt)
|
||||
{
|
||||
obj;
|
||||
return iread(buf, 1, cnt);
|
||||
}
|
||||
|
||||
static int iJp2_file_write(jas_stream_obj_t *obj, char *buf, int cnt)
|
||||
{
|
||||
obj;
|
||||
return iwrite(buf, 1, cnt);
|
||||
}
|
||||
|
||||
static long iJp2_file_seek(jas_stream_obj_t *obj, long offset, int origin)
|
||||
{
|
||||
obj;
|
||||
|
||||
// We could just pass origin to iseek, but this is probably more portable.
|
||||
switch (origin)
|
||||
{
|
||||
case SEEK_SET:
|
||||
return iseek(offset, IL_SEEK_SET);
|
||||
case SEEK_CUR:
|
||||
return iseek(offset, IL_SEEK_CUR);
|
||||
case SEEK_END:
|
||||
return iseek(offset, IL_SEEK_END);
|
||||
}
|
||||
return 0; // Failed
|
||||
}
|
||||
|
||||
static int iJp2_file_close(jas_stream_obj_t *obj)
|
||||
{
|
||||
obj;
|
||||
return 0; // We choose when we want to close the file.
|
||||
}
|
||||
|
||||
static jas_stream_ops_t jas_stream_devilops = {
|
||||
iJp2_file_read,
|
||||
iJp2_file_write,
|
||||
iJp2_file_seek,
|
||||
iJp2_file_close
|
||||
};
|
||||
|
||||
static jas_stream_t *jas_stream_create(void);
|
||||
static void jas_stream_destroy(jas_stream_t *stream);
|
||||
static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf, int bufsize);
|
||||
|
||||
|
||||
// Modified version of jas_stream_fopen and jas_stream_memopen from jas_stream.c of JasPer
|
||||
// so that we can use our own file routines.
|
||||
jas_stream_t *iJp2ReadStream()
|
||||
{
|
||||
jas_stream_t *stream;
|
||||
jas_stream_memobj_t *obj;
|
||||
|
||||
if (!(stream = jas_stream_create())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A stream associated with a memory buffer is always opened
|
||||
for both reading and writing in binary mode. */
|
||||
stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_BINARY;
|
||||
|
||||
/* We use buffering whether it is from memory or a file. */
|
||||
jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
|
||||
|
||||
/* Select the operations for a memory stream. */
|
||||
stream->ops_ = &jas_stream_devilops;
|
||||
|
||||
/* Allocate memory for the underlying memory stream object. */
|
||||
if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
|
||||
jas_stream_destroy(stream);
|
||||
return 0;
|
||||
}
|
||||
stream->obj_ = (void *) obj;
|
||||
|
||||
/* Initialize a few important members of the memory stream object. */
|
||||
obj->myalloc_ = 0;
|
||||
obj->buf_ = 0;
|
||||
|
||||
// Shouldn't need any of this.
|
||||
|
||||
///* If the buffer size specified is nonpositive, then the buffer
|
||||
//is allocated internally and automatically grown as needed. */
|
||||
//if (bufsize <= 0) {
|
||||
// obj->bufsize_ = 1024;
|
||||
// obj->growable_ = 1;
|
||||
//} else {
|
||||
// obj->bufsize_ = bufsize;
|
||||
// obj->growable_ = 0;
|
||||
//}
|
||||
//if (buf) {
|
||||
// obj->buf_ = (unsigned char *) buf;
|
||||
//} else {
|
||||
// obj->buf_ = jas_malloc(obj->bufsize_ * sizeof(char));
|
||||
// obj->myalloc_ = 1;
|
||||
//}
|
||||
//if (!obj->buf_) {
|
||||
// jas_stream_close(stream);
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
//if (bufsize > 0 && buf) {
|
||||
// /* If a buffer was supplied by the caller and its length is positive,
|
||||
// make the associated buffer data appear in the stream initially. */
|
||||
// obj->len_ = bufsize;
|
||||
//} else {
|
||||
// /* The stream is initially empty. */
|
||||
// obj->len_ = 0;
|
||||
//}
|
||||
//obj->pos_ = 0;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
// The following functions are taken directly from jas_stream.c of JasPer,
|
||||
// since they are designed to be used within JasPer only.
|
||||
|
||||
static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
|
||||
int bufsize)
|
||||
{
|
||||
/* If this function is being called, the buffer should not have been
|
||||
initialized yet. */
|
||||
assert(!stream->bufbase_);
|
||||
|
||||
if (bufmode != JAS_STREAM_UNBUF) {
|
||||
/* The full- or line-buffered mode is being employed. */
|
||||
if (!buf) {
|
||||
/* The caller has not specified a buffer to employ, so allocate
|
||||
one. */
|
||||
if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE +
|
||||
JAS_STREAM_MAXPUTBACK))) {
|
||||
stream->bufmode_ |= JAS_STREAM_FREEBUF;
|
||||
stream->bufsize_ = JAS_STREAM_BUFSIZE;
|
||||
} else {
|
||||
/* The buffer allocation has failed. Resort to unbuffered
|
||||
operation. */
|
||||
stream->bufbase_ = stream->tinybuf_;
|
||||
stream->bufsize_ = 1;
|
||||
}
|
||||
} else {
|
||||
/* The caller has specified a buffer to employ. */
|
||||
/* The buffer must be large enough to accommodate maximum
|
||||
putback. */
|
||||
assert(bufsize > JAS_STREAM_MAXPUTBACK);
|
||||
stream->bufbase_ = JAS_CAST(uchar *, buf);
|
||||
stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
|
||||
}
|
||||
} else {
|
||||
/* The unbuffered mode is being employed. */
|
||||
/* A buffer should not have been supplied by the caller. */
|
||||
assert(!buf);
|
||||
/* Use a trivial one-character buffer. */
|
||||
stream->bufbase_ = stream->tinybuf_;
|
||||
stream->bufsize_ = 1;
|
||||
}
|
||||
stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
|
||||
stream->ptr_ = stream->bufstart_;
|
||||
stream->cnt_ = 0;
|
||||
stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
|
||||
}
|
||||
|
||||
static jas_stream_t *jas_stream_create()
|
||||
{
|
||||
jas_stream_t *stream;
|
||||
|
||||
if (!(stream = jas_malloc(sizeof(jas_stream_t)))) {
|
||||
return 0;
|
||||
}
|
||||
stream->openmode_ = 0;
|
||||
stream->bufmode_ = 0;
|
||||
stream->flags_ = 0;
|
||||
stream->bufbase_ = 0;
|
||||
stream->bufstart_ = 0;
|
||||
stream->bufsize_ = 0;
|
||||
stream->ptr_ = 0;
|
||||
stream->cnt_ = 0;
|
||||
stream->ops_ = 0;
|
||||
stream->obj_ = 0;
|
||||
stream->rwcnt_ = 0;
|
||||
stream->rwlimit_ = -1;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
static void jas_stream_destroy(jas_stream_t *stream)
|
||||
{
|
||||
/* If the memory for the buffer was allocated with malloc, free
|
||||
this memory. */
|
||||
if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
|
||||
jas_free(stream->bufbase_);
|
||||
stream->bufbase_ = 0;
|
||||
}
|
||||
jas_free(stream);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
jas_stream_t *iJp2WriteStream()
|
||||
{
|
||||
jas_stream_t *stream;
|
||||
jas_stream_memobj_t *obj;
|
||||
|
||||
if (!(stream = jas_stream_create())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A stream associated with a memory buffer is always opened
|
||||
for both reading and writing in binary mode. */
|
||||
stream->openmode_ = JAS_STREAM_WRITE | JAS_STREAM_BINARY;
|
||||
|
||||
/* We use buffering whether it is from memory or a file. */
|
||||
jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
|
||||
|
||||
/* Select the operations for a memory stream. */
|
||||
stream->ops_ = &jas_stream_devilops;
|
||||
|
||||
/* Allocate memory for the underlying memory stream object. */
|
||||
if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
|
||||
jas_stream_destroy(stream);
|
||||
return 0;
|
||||
}
|
||||
stream->obj_ = (void *) obj;
|
||||
|
||||
/* Initialize a few important members of the memory stream object. */
|
||||
obj->myalloc_ = 0;
|
||||
obj->buf_ = 0;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Writes a Jp2 file
|
||||
ILboolean ilSaveJp2(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE Jp2File;
|
||||
ILuint Jp2Size;
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
Jp2File = iopenw(FileName);
|
||||
if (Jp2File == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Jp2Size = ilSaveJp2F(Jp2File);
|
||||
iclosew(Jp2File);
|
||||
|
||||
if (Jp2Size == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Jp2 to an already-opened file
|
||||
ILuint ilSaveJp2F(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputFile(File);
|
||||
Pos = itellw();
|
||||
if (iSaveJp2Internal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Jp2 to a memory "lump"
|
||||
ILuint ilSaveJp2L(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputLump(Lump, Size);
|
||||
Pos = itellw();
|
||||
if (iSaveJp2Internal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Function from OpenSceneGraph (originally called getdata in their sources):
|
||||
// http://openscenegraph.sourcearchive.com/documentation/2.2.0/ReaderWriterJP2_8cpp-source.html
|
||||
ILint Jp2ConvertData(jas_stream_t *in, jas_image_t *image)
|
||||
{
|
||||
int ret;
|
||||
int numcmpts;
|
||||
int cmptno;
|
||||
jas_matrix_t *data[4];
|
||||
int x;
|
||||
int y;
|
||||
int width, height;
|
||||
|
||||
width = jas_image_cmptwidth(image, 0);
|
||||
height = jas_image_cmptheight(image, 0);
|
||||
numcmpts = jas_image_numcmpts(image);
|
||||
|
||||
ret = -1;
|
||||
|
||||
data[0] = 0;
|
||||
data[1] = 0;
|
||||
data[2] = 0;
|
||||
data[3] = 0;
|
||||
for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
|
||||
if (!(data[cmptno] = jas_matrix_create(1, width))) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
for (y = height - 1; y >= 0; --y)
|
||||
// for (y = 0; y < height; ++y)
|
||||
{
|
||||
for (x = 0; x < width; ++x)
|
||||
{
|
||||
for (cmptno = 0; cmptno < numcmpts; ++cmptno)
|
||||
{
|
||||
// The sample data is unsigned.
|
||||
int c;
|
||||
if ((c = jas_stream_getc(in)) == EOF) {
|
||||
return -1;
|
||||
}
|
||||
jas_matrix_set(data[cmptno], 0, x, c);
|
||||
}
|
||||
}
|
||||
for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
|
||||
if (jas_image_writecmpt(image, cmptno, 0, y, width, 1,
|
||||
data[cmptno])) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jas_stream_flush(in);
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
|
||||
if (data[cmptno]) {
|
||||
jas_matrix_destroy(data[cmptno]);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to save the Jp2.
|
||||
// Since the JasPer documentation is extremely incomplete, I had to look at how OpenSceneGraph uses it:
|
||||
// http://openscenegraph.sourcearchive.com/documentation/2.2.0/ReaderWriterJP2_8cpp-source.html
|
||||
|
||||
//@TODO: Do we need to worry about images with depths > 1?
|
||||
ILboolean iSaveJp2Internal()
|
||||
{
|
||||
jas_image_t *Jp2Image;
|
||||
jas_image_cmptparm_t cmptparm[4];
|
||||
jas_stream_t *Mem, *Stream;
|
||||
ILuint NumChans, i;
|
||||
ILenum NewFormat, NewType = IL_UNSIGNED_BYTE;
|
||||
ILimage *TempImage = iCurImage;
|
||||
|
||||
if (!JasperInit) {
|
||||
if (jas_init()) {
|
||||
ilSetError(IL_LIB_JP2_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
JasperInit = IL_TRUE;
|
||||
}
|
||||
|
||||
if (iCurImage->Type != IL_UNSIGNED_BYTE) { //@TODO: Support greater than 1 bpc.
|
||||
NewType = IL_UNSIGNED_BYTE;
|
||||
}
|
||||
//@TODO: Do luminance/luminance-alpha/alpha separately.
|
||||
switch (iCurImage->Format)
|
||||
{
|
||||
case IL_LUMINANCE:
|
||||
NewFormat = IL_LUMINANCE;
|
||||
NumChans = 1;
|
||||
break;
|
||||
case IL_ALPHA:
|
||||
NewFormat = IL_ALPHA;
|
||||
NumChans = 1;
|
||||
break;
|
||||
case IL_LUMINANCE_ALPHA:
|
||||
NewFormat = IL_LUMINANCE_ALPHA;
|
||||
NumChans = 2;
|
||||
break;
|
||||
case IL_COLOUR_INDEX: // Assuming the color palette does not have an alpha value.
|
||||
//@TODO: Check for this in the future.
|
||||
case IL_RGB:
|
||||
case IL_BGR:
|
||||
NewFormat = IL_RGB;
|
||||
NumChans = 3;
|
||||
break;
|
||||
case IL_RGBA:
|
||||
case IL_BGRA:
|
||||
NewFormat = IL_RGBA;
|
||||
NumChans = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (NewType != iCurImage->Type || NewFormat != iCurImage->Format) {
|
||||
TempImage = iConvertImage(iCurImage, NewFormat, NewType);
|
||||
if (TempImage == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// The origin is always in the lower left corner. Flip the buffer if it is not.
|
||||
if (TempImage->Origin == IL_ORIGIN_UPPER_LEFT)
|
||||
iFlipBuffer(TempImage->Data, TempImage->Depth, TempImage->Bps, TempImage->Height);
|
||||
|
||||
// Have to tell JasPer about each channel. In our case, they all have the same information.
|
||||
for (i = 0; i < NumChans; i++) {
|
||||
cmptparm[i].width = iCurImage->Width;
|
||||
cmptparm[i].height = iCurImage->Height;
|
||||
cmptparm[i].hstep = 1;
|
||||
cmptparm[i].vstep = 1;
|
||||
cmptparm[i].tlx = 0;
|
||||
cmptparm[i].tly = 0;
|
||||
cmptparm[i].prec = 8;
|
||||
cmptparm[i].sgnd = 0; // Unsigned data
|
||||
}
|
||||
|
||||
// Using the unknown color space, since we have not determined the space yet.
|
||||
// This is done in the following switch statement.
|
||||
Jp2Image = jas_image_create(NumChans, cmptparm, JAS_CLRSPC_UNKNOWN);
|
||||
if (Jp2Image == NULL) {
|
||||
ilSetError(IL_LIB_JP2_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
switch (NumChans)
|
||||
{
|
||||
case 1:
|
||||
jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SGRAY);
|
||||
if (NewFormat == IL_LUMINANCE)
|
||||
jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
|
||||
else // IL_ALPHA
|
||||
jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
|
||||
break;
|
||||
case 2:
|
||||
jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SGRAY);
|
||||
jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
|
||||
jas_image_setcmpttype(Jp2Image, 1, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
|
||||
break;
|
||||
case 3:
|
||||
jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SRGB);
|
||||
jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
|
||||
jas_image_setcmpttype(Jp2Image, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
|
||||
jas_image_setcmpttype(Jp2Image, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
|
||||
break;
|
||||
case 4:
|
||||
jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SRGB);
|
||||
jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
|
||||
jas_image_setcmpttype(Jp2Image, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
|
||||
jas_image_setcmpttype(Jp2Image, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
|
||||
jas_image_setcmpttype(Jp2Image, 3, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
|
||||
break;
|
||||
}
|
||||
|
||||
Mem = jas_stream_memopen((char*)TempImage->Data, TempImage->SizeOfData);
|
||||
if (Mem == NULL) {
|
||||
jas_image_destroy(Jp2Image);
|
||||
ilSetError(IL_LIB_JP2_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
Stream = iJp2WriteStream();
|
||||
if (Stream == NULL) {
|
||||
jas_stream_close(Mem);
|
||||
jas_image_destroy(Jp2Image);
|
||||
ilSetError(IL_LIB_JP2_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Puts data in the format that JasPer wants it in.
|
||||
Jp2ConvertData(Mem, Jp2Image);
|
||||
|
||||
// Does all of the encoding.
|
||||
if (jas_image_encode(Jp2Image, Stream, jas_image_strtofmt("jp2"), NULL)) { //@TODO: Do we want to use any options?
|
||||
jas_stream_close(Mem);
|
||||
jas_stream_close(Stream);
|
||||
jas_image_destroy(Jp2Image);
|
||||
ilSetError(IL_LIB_JP2_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
jas_stream_flush(Stream); // Do any final writing.
|
||||
|
||||
// Close the memory and output streams.
|
||||
jas_stream_close(Mem);
|
||||
jas_stream_close(Stream);
|
||||
// Destroy the JasPer image.
|
||||
jas_image_destroy(Jp2Image);
|
||||
|
||||
// Destroy our temporary image if we used one.
|
||||
if (TempImage != iCurImage)
|
||||
ilCloseImage(TempImage);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_JP2
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,198 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_lif.c
|
||||
//
|
||||
// Description: Reads a Homeworld image.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_LIF
|
||||
#include "il_lif.h"
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid Lif file.
|
||||
ILboolean ilIsValidLif(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE LifFile;
|
||||
ILboolean bLif = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("lif"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bLif;
|
||||
}
|
||||
|
||||
LifFile = iopenr(FileName);
|
||||
if (LifFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bLif;
|
||||
}
|
||||
|
||||
bLif = ilIsValidLifF(LifFile);
|
||||
icloser(LifFile);
|
||||
|
||||
return bLif;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid Lif file at the current position.
|
||||
ILboolean ilIsValidLifF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidLif();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid Lif lump.
|
||||
ILboolean ilIsValidLifL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidLif();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the Lif header from the current file.
|
||||
ILboolean iGetLifHead(LIF_HEAD *Header)
|
||||
{
|
||||
|
||||
iread(Header->Id, 1, 8);
|
||||
|
||||
Header->Version = GetLittleUInt();
|
||||
|
||||
Header->Flags = GetLittleUInt();
|
||||
|
||||
Header->Width = GetLittleUInt();
|
||||
|
||||
Header->Height = GetLittleUInt();
|
||||
|
||||
Header->PaletteCRC = GetLittleUInt();
|
||||
|
||||
Header->ImageCRC = GetLittleUInt();
|
||||
|
||||
Header->PalOffset = GetLittleUInt();
|
||||
|
||||
Header->TeamEffect0 = GetLittleUInt();
|
||||
|
||||
Header->TeamEffect1 = GetLittleUInt();
|
||||
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidLif()
|
||||
{
|
||||
LIF_HEAD Head;
|
||||
|
||||
if (!iGetLifHead(&Head))
|
||||
return IL_FALSE;
|
||||
iseek(-(ILint)sizeof(LIF_HEAD), IL_SEEK_CUR);
|
||||
|
||||
return iCheckLif(&Head);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid Lif header.
|
||||
ILboolean iCheckLif(LIF_HEAD *Header)
|
||||
{
|
||||
if (Header->Version != 260 || Header->Flags != 50)
|
||||
return IL_FALSE;
|
||||
if (stricmp(Header->Id, "Willy 7"))
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a .Lif file
|
||||
ILboolean ilLoadLif(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE LifFile;
|
||||
ILboolean bLif = IL_FALSE;
|
||||
|
||||
LifFile = iopenr(FileName);
|
||||
if (LifFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bLif;
|
||||
}
|
||||
|
||||
bLif = ilLoadLifF(LifFile);
|
||||
icloser(LifFile);
|
||||
|
||||
return bLif;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .Lif file
|
||||
ILboolean ilLoadLifF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadLifInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a .Lif
|
||||
ILboolean ilLoadLifL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadLifInternal();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadLifInternal()
|
||||
{
|
||||
LIF_HEAD LifHead;
|
||||
ILuint i;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!iGetLifHead(&LifHead))
|
||||
return IL_FALSE;
|
||||
|
||||
if (!ilTexImage(LifHead.Width, LifHead.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
iCurImage->Pal.Palette = (ILubyte*)ialloc(1024);
|
||||
if (iCurImage->Pal.Palette == NULL)
|
||||
return IL_FALSE;
|
||||
iCurImage->Pal.PalSize = 1024;
|
||||
iCurImage->Pal.PalType = IL_PAL_RGBA32;
|
||||
|
||||
if (iread(iCurImage->Data, LifHead.Width * LifHead.Height, 1) != 1)
|
||||
return IL_FALSE;
|
||||
if (iread(iCurImage->Pal.Palette, 1, 1024) != 1024)
|
||||
return IL_FALSE;
|
||||
|
||||
// Each data offset is offset by -1, so we add one.
|
||||
for (i = 0; i < iCurImage->SizeOfData; i++) {
|
||||
iCurImage->Data[i]++;
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
#endif//IL_NO_LIF
|
||||
@@ -0,0 +1,30 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2002 by Denton Woods
|
||||
// Last modified: 02/16/2002 <--Y2K Compliant! =]
|
||||
//
|
||||
// Filename: src-IL/src/il_main.c
|
||||
//
|
||||
// Description: Startup function
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
|
||||
/* Only needed for MSVC++ unless extended to actually do something =) */
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
hModule; ul_reason_for_call; lpReserved;
|
||||
|
||||
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
|
||||
//ilInit();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,948 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 01/24/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_manip.c
|
||||
//
|
||||
// Description: Image manipulation
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
#include "il_manip.h"
|
||||
|
||||
|
||||
ILAPI void ILAPIENTRY iFlipBuffer(ILubyte *buff, ILuint depth, ILuint line_size, ILuint line_num)
|
||||
{
|
||||
ILubyte *StartPtr, *EndPtr;
|
||||
ILuint y, d;
|
||||
const ILuint size = line_num * line_size;
|
||||
|
||||
for (d = 0; d < depth; d++) {
|
||||
StartPtr = buff + d * size;
|
||||
EndPtr = buff + d * size + size;
|
||||
|
||||
for (y = 0; y < (line_num/2); y++) {
|
||||
EndPtr -= line_size;
|
||||
iMemSwap(StartPtr, EndPtr, line_size);
|
||||
StartPtr += line_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Just created for internal use.
|
||||
ILubyte* iFlipNewBuffer(ILubyte *buff, ILuint depth, ILuint line_size, ILuint line_num)
|
||||
{
|
||||
ILubyte *data;
|
||||
ILubyte *s1, *s2;
|
||||
ILuint y, d;
|
||||
const ILuint size = line_num * line_size;
|
||||
|
||||
if ((data = (ILubyte*)ialloc(depth*size)) == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
for (d = 0; d < depth; d++) {
|
||||
s1 = buff + d * size;
|
||||
s2 = data + d * size+size;
|
||||
|
||||
for (y = 0; y < line_num; y++) {
|
||||
s2 -= line_size;
|
||||
memcpy(s2,s1,line_size);
|
||||
s1 += line_size;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
// Flips an image over its x axis
|
||||
ILboolean ilFlipImage()
|
||||
{
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iCurImage->Origin = (iCurImage->Origin == IL_ORIGIN_LOWER_LEFT) ?
|
||||
IL_ORIGIN_UPPER_LEFT : IL_ORIGIN_LOWER_LEFT;
|
||||
|
||||
iFlipBuffer(iCurImage->Data,iCurImage->Depth,iCurImage->Bps,iCurImage->Height);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
// Just created for internal use.
|
||||
ILubyte* ILAPIENTRY iGetFlipped(ILimage *img)
|
||||
{
|
||||
if (img == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return NULL;
|
||||
}
|
||||
return iFlipNewBuffer(img->Data,img->Depth,img->Bps,img->Height);
|
||||
}
|
||||
|
||||
|
||||
//@JASON New routine created 28/03/2001
|
||||
//! Mirrors an image over its y axis
|
||||
ILboolean ILAPIENTRY iMirror() {
|
||||
ILubyte *Data, *DataPtr, *Temp;
|
||||
ILuint y, d, PixLine;
|
||||
ILint x, c;
|
||||
ILushort *ShortPtr, *TempShort;
|
||||
ILuint *IntPtr, *TempInt;
|
||||
ILdouble *DblPtr, *TempDbl;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Data = (ILubyte*)ialloc(iCurImage->SizeOfData);
|
||||
if (Data == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
PixLine = iCurImage->Bps / iCurImage->Bpc;
|
||||
switch (iCurImage->Bpc)
|
||||
{
|
||||
case 1:
|
||||
Temp = iCurImage->Data;
|
||||
for (d = 0; d < iCurImage->Depth; d++) {
|
||||
DataPtr = Data + d * iCurImage->SizeOfPlane;
|
||||
for (y = 0; y < iCurImage->Height; y++) {
|
||||
for (x = iCurImage->Width - 1; x >= 0; x--) {
|
||||
for (c = 0; c < iCurImage->Bpp; c++, Temp++) {
|
||||
DataPtr[y * PixLine + x * iCurImage->Bpp + c] = *Temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
TempShort = (ILushort*)iCurImage->Data;
|
||||
for (d = 0; d < iCurImage->Depth; d++) {
|
||||
ShortPtr = (ILushort*)(Data + d * iCurImage->SizeOfPlane);
|
||||
for (y = 0; y < iCurImage->Height; y++) {
|
||||
for (x = iCurImage->Width - 1; x >= 0; x--) {
|
||||
for (c = 0; c < iCurImage->Bpp; c++, TempShort++) {
|
||||
ShortPtr[y * PixLine + x * iCurImage->Bpp + c] = *TempShort;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
TempInt = (ILuint*)iCurImage->Data;
|
||||
for (d = 0; d < iCurImage->Depth; d++) {
|
||||
IntPtr = (ILuint*)(Data + d * iCurImage->SizeOfPlane);
|
||||
for (y = 0; y < iCurImage->Height; y++) {
|
||||
for (x = iCurImage->Width - 1; x >= 0; x--) {
|
||||
for (c = 0; c < iCurImage->Bpp; c++, TempInt++) {
|
||||
IntPtr[y * PixLine + x * iCurImage->Bpp + c] = *TempInt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
TempDbl = (ILdouble*)iCurImage->Data;
|
||||
for (d = 0; d < iCurImage->Depth; d++) {
|
||||
DblPtr = (ILdouble*)(Data + d * iCurImage->SizeOfPlane);
|
||||
for (y = 0; y < iCurImage->Height; y++) {
|
||||
for (x = iCurImage->Width - 1; x >= 0; x--) {
|
||||
for (c = 0; c < iCurImage->Bpp; c++, TempDbl++) {
|
||||
DblPtr[y * PixLine + x * iCurImage->Bpp + c] = *TempDbl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ifree(iCurImage->Data);
|
||||
iCurImage->Data = Data;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Should we add type to the parameter list?
|
||||
// Copies a 1d block of pixels to the buffer pointed to by Data.
|
||||
ILboolean ilCopyPixels1D(ILuint XOff, ILuint Width, void *Data)
|
||||
{
|
||||
ILuint x, c, NewBps, NewOff, PixBpp;
|
||||
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
|
||||
|
||||
if (ilIsEnabled(IL_ORIGIN_SET)) {
|
||||
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
|
||||
TempData = iGetFlipped(iCurImage);
|
||||
if (TempData == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
|
||||
|
||||
if (iCurImage->Width < XOff + Width) {
|
||||
NewBps = (iCurImage->Width - XOff) * PixBpp;
|
||||
}
|
||||
else {
|
||||
NewBps = Width * PixBpp;
|
||||
}
|
||||
NewOff = XOff * PixBpp;
|
||||
|
||||
for (x = 0; x < NewBps; x += PixBpp) {
|
||||
for (c = 0; c < PixBpp; c++) {
|
||||
Temp[x + c] = TempData[(x + NewOff) + c];
|
||||
}
|
||||
}
|
||||
|
||||
if (TempData != iCurImage->Data)
|
||||
ifree(TempData);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Copies a 2d block of pixels to the buffer pointed to by Data.
|
||||
ILboolean ilCopyPixels2D(ILuint XOff, ILuint YOff, ILuint Width, ILuint Height, void *Data)
|
||||
{
|
||||
ILuint x, y, c, NewBps, DataBps, NewXOff, NewHeight, PixBpp;
|
||||
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
|
||||
|
||||
if (ilIsEnabled(IL_ORIGIN_SET)) {
|
||||
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
|
||||
TempData = iGetFlipped(iCurImage);
|
||||
if (TempData == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
|
||||
|
||||
if (iCurImage->Width < XOff + Width)
|
||||
NewBps = (iCurImage->Width - XOff) * PixBpp;
|
||||
else
|
||||
NewBps = Width * PixBpp;
|
||||
|
||||
if (iCurImage->Height < YOff + Height)
|
||||
NewHeight = iCurImage->Height - YOff;
|
||||
else
|
||||
NewHeight = Height;
|
||||
|
||||
DataBps = Width * PixBpp;
|
||||
NewXOff = XOff * PixBpp;
|
||||
|
||||
for (y = 0; y < NewHeight; y++) {
|
||||
for (x = 0; x < NewBps; x += PixBpp) {
|
||||
for (c = 0; c < PixBpp; c++) {
|
||||
Temp[y * DataBps + x + c] =
|
||||
TempData[(y + YOff) * iCurImage->Bps + x + NewXOff + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TempData != iCurImage->Data)
|
||||
ifree(TempData);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Copies a 3d block of pixels to the buffer pointed to by Data.
|
||||
ILboolean ilCopyPixels3D(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth, void *Data)
|
||||
{
|
||||
ILuint x, y, z, c, NewBps, DataBps, NewSizePlane, NewH, NewD, NewXOff, PixBpp;
|
||||
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
|
||||
|
||||
if (ilIsEnabled(IL_ORIGIN_SET)) {
|
||||
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
|
||||
TempData = iGetFlipped(iCurImage);
|
||||
if (TempData == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
|
||||
|
||||
if (iCurImage->Width < XOff + Width)
|
||||
NewBps = (iCurImage->Width - XOff) * PixBpp;
|
||||
else
|
||||
NewBps = Width * PixBpp;
|
||||
|
||||
if (iCurImage->Height < YOff + Height)
|
||||
NewH = iCurImage->Height - YOff;
|
||||
else
|
||||
NewH = Height;
|
||||
|
||||
if (iCurImage->Depth < ZOff + Depth)
|
||||
NewD = iCurImage->Depth - ZOff;
|
||||
else
|
||||
NewD = Depth;
|
||||
|
||||
DataBps = Width * PixBpp;
|
||||
NewSizePlane = NewBps * NewH;
|
||||
|
||||
NewXOff = XOff * PixBpp;
|
||||
|
||||
for (z = 0; z < NewD; z++) {
|
||||
for (y = 0; y < NewH; y++) {
|
||||
for (x = 0; x < NewBps; x += PixBpp) {
|
||||
for (c = 0; c < PixBpp; c++) {
|
||||
Temp[z * NewSizePlane + y * DataBps + x + c] =
|
||||
TempData[(z + ZOff) * iCurImage->SizeOfPlane + (y + YOff) * iCurImage->Bps + x + NewXOff + c];
|
||||
//TempData[(z + ZOff) * iCurImage->SizeOfPlane + (y + YOff) * iCurImage->Bps + (x + XOff) * iCurImage->Bpp + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TempData != iCurImage->Data)
|
||||
ifree(TempData);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILuint ILAPIENTRY ilCopyPixels(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data)
|
||||
{
|
||||
void *Converted = NULL;
|
||||
ILubyte *TempBuff = NULL;
|
||||
ILuint SrcSize, DestSize;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return 0;
|
||||
}
|
||||
DestSize = Width * Height * Depth * ilGetBppFormat(Format) * ilGetBpcType(Type);
|
||||
if (DestSize == 0) {
|
||||
return DestSize;
|
||||
}
|
||||
if (Data == NULL || Format == IL_COLOUR_INDEX) {
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
return 0;
|
||||
}
|
||||
SrcSize = Width * Height * Depth * iCurImage->Bpp * iCurImage->Bpc;
|
||||
|
||||
if (Format == iCurImage->Format && Type == iCurImage->Type) {
|
||||
TempBuff = (ILubyte*)Data;
|
||||
}
|
||||
else {
|
||||
TempBuff = (ILubyte*)ialloc(SrcSize);
|
||||
if (TempBuff == NULL) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (YOff + Height <= 1) {
|
||||
if (!ilCopyPixels1D(XOff, Width, TempBuff)) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
else if (ZOff + Depth <= 1) {
|
||||
if (!ilCopyPixels2D(XOff, YOff, Width, Height, TempBuff)) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!ilCopyPixels3D(XOff, YOff, ZOff, Width, Height, Depth, TempBuff)) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (Format == iCurImage->Format && Type == iCurImage->Type) {
|
||||
return DestSize;
|
||||
}
|
||||
|
||||
Converted = ilConvertBuffer(SrcSize, iCurImage->Format, Format, iCurImage->Type, Type, &iCurImage->Pal, TempBuff);
|
||||
if (Converted == NULL)
|
||||
goto failed;
|
||||
|
||||
memcpy(Data, Converted, DestSize);
|
||||
|
||||
ifree(Converted);
|
||||
if (TempBuff != Data)
|
||||
ifree(TempBuff);
|
||||
|
||||
return DestSize;
|
||||
|
||||
failed:
|
||||
if (TempBuff != Data)
|
||||
ifree(TempBuff);
|
||||
ifree(Converted);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ilSetPixels1D(ILint XOff, ILuint Width, void *Data)
|
||||
{
|
||||
ILuint c, SkipX = 0, PixBpp;
|
||||
ILint x, NewWidth;
|
||||
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
|
||||
|
||||
if (ilIsEnabled(IL_ORIGIN_SET)) {
|
||||
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
|
||||
TempData = iGetFlipped(iCurImage);
|
||||
if (TempData == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
|
||||
|
||||
if (XOff < 0) {
|
||||
SkipX = abs(XOff);
|
||||
XOff = 0;
|
||||
}
|
||||
|
||||
if (iCurImage->Width < XOff + Width) {
|
||||
NewWidth = iCurImage->Width - XOff;
|
||||
}
|
||||
else {
|
||||
NewWidth = Width;
|
||||
}
|
||||
|
||||
NewWidth -= SkipX;
|
||||
|
||||
for (x = 0; x < NewWidth; x++) {
|
||||
for (c = 0; c < PixBpp; c++) {
|
||||
TempData[(x + XOff) * PixBpp + c] = Temp[(x + SkipX) * PixBpp + c];
|
||||
}
|
||||
}
|
||||
|
||||
if (TempData != iCurImage->Data) {
|
||||
ifree(iCurImage->Data);
|
||||
iCurImage->Data = TempData;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ilSetPixels2D(ILint XOff, ILint YOff, ILuint Width, ILuint Height, void *Data)
|
||||
{
|
||||
ILuint c, SkipX = 0, SkipY = 0, NewBps, PixBpp;
|
||||
ILint x, y, NewWidth, NewHeight;
|
||||
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
|
||||
|
||||
if (ilIsEnabled(IL_ORIGIN_SET)) {
|
||||
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
|
||||
TempData = iGetFlipped(iCurImage);
|
||||
if (TempData == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
|
||||
|
||||
if (XOff < 0) {
|
||||
SkipX = abs(XOff);
|
||||
XOff = 0;
|
||||
}
|
||||
if (YOff < 0) {
|
||||
SkipY = abs(YOff);
|
||||
YOff = 0;
|
||||
}
|
||||
|
||||
if (iCurImage->Width < XOff + Width)
|
||||
NewWidth = iCurImage->Width - XOff;
|
||||
else
|
||||
NewWidth = Width;
|
||||
NewBps = Width * PixBpp;
|
||||
|
||||
if (iCurImage->Height < YOff + Height)
|
||||
NewHeight = iCurImage->Height - YOff;
|
||||
else
|
||||
NewHeight = Height;
|
||||
|
||||
NewWidth -= SkipX;
|
||||
NewHeight -= SkipY;
|
||||
|
||||
for (y = 0; y < NewHeight; y++) {
|
||||
for (x = 0; x < NewWidth; x++) {
|
||||
for (c = 0; c < PixBpp; c++) {
|
||||
TempData[(y + YOff) * iCurImage->Bps + (x + XOff) * PixBpp + c] =
|
||||
Temp[(y + SkipY) * NewBps + (x + SkipX) * PixBpp + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TempData != iCurImage->Data) {
|
||||
ifree(iCurImage->Data);
|
||||
iCurImage->Data = TempData;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ilSetPixels3D(ILint XOff, ILint YOff, ILint ZOff, ILuint Width, ILuint Height, ILuint Depth, void *Data)
|
||||
{
|
||||
ILuint SkipX = 0, SkipY = 0, SkipZ = 0, c, NewBps, NewSizePlane, PixBpp;
|
||||
ILint x, y, z, NewW, NewH, NewD;
|
||||
ILubyte *Temp = (ILubyte*)Data, *TempData = iCurImage->Data;
|
||||
|
||||
if (ilIsEnabled(IL_ORIGIN_SET)) {
|
||||
if ((ILenum)ilGetInteger(IL_ORIGIN_MODE) != iCurImage->Origin) {
|
||||
TempData = iGetFlipped(iCurImage);
|
||||
if (TempData == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PixBpp = iCurImage->Bpp * iCurImage->Bpc;
|
||||
|
||||
if (XOff < 0) {
|
||||
SkipX = abs(XOff);
|
||||
XOff = 0;
|
||||
}
|
||||
if (YOff < 0) {
|
||||
SkipY = abs(YOff);
|
||||
YOff = 0;
|
||||
}
|
||||
if (ZOff < 0) {
|
||||
SkipZ = abs(ZOff);
|
||||
ZOff = 0;
|
||||
}
|
||||
|
||||
if (iCurImage->Width < XOff + Width)
|
||||
NewW = iCurImage->Width - XOff;
|
||||
else
|
||||
NewW = Width;
|
||||
NewBps = Width * PixBpp;
|
||||
|
||||
if (iCurImage->Height < YOff + Height)
|
||||
NewH = iCurImage->Height - YOff;
|
||||
else
|
||||
NewH = Height;
|
||||
|
||||
if (iCurImage->Depth < ZOff + Depth)
|
||||
NewD = iCurImage->Depth - ZOff;
|
||||
else
|
||||
NewD = Depth;
|
||||
NewSizePlane = NewBps * Height;
|
||||
|
||||
NewW -= SkipX;
|
||||
NewH -= SkipY;
|
||||
NewD -= SkipZ;
|
||||
|
||||
for (z = 0; z < NewD; z++) {
|
||||
for (y = 0; y < NewH; y++) {
|
||||
for (x = 0; x < NewW; x++) {
|
||||
for (c = 0; c < PixBpp; c++) {
|
||||
TempData[(z + ZOff) * iCurImage->SizeOfPlane + (y + YOff) * iCurImage->Bps + (x + XOff) * PixBpp + c] =
|
||||
Temp[(z + SkipZ) * NewSizePlane + (y + SkipY) * NewBps + (x + SkipX) * PixBpp + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TempData != iCurImage->Data) {
|
||||
ifree(iCurImage->Data);
|
||||
iCurImage->Data = TempData;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
void ILAPIENTRY ilSetPixels(ILint XOff, ILint YOff, ILint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data)
|
||||
{
|
||||
void *Converted;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return;
|
||||
}
|
||||
if (Data == NULL) {
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Format == iCurImage->Format && Type == iCurImage->Type) {
|
||||
Converted = (void*)Data;
|
||||
}
|
||||
else {
|
||||
Converted = ilConvertBuffer(Width * Height * Depth * ilGetBppFormat(Format) * ilGetBpcType(Type), Format, iCurImage->Format, Type, iCurImage->Type, NULL, Data);
|
||||
if (!Converted)
|
||||
return;
|
||||
}
|
||||
|
||||
if (YOff + Height <= 1) {
|
||||
ilSetPixels1D(XOff, Width, Converted);
|
||||
}
|
||||
else if (ZOff + Depth <= 1) {
|
||||
ilSetPixels2D(XOff, YOff, Width, Height, Converted);
|
||||
}
|
||||
else {
|
||||
ilSetPixels3D(XOff, YOff, ZOff, Width, Height, Depth, Converted);
|
||||
}
|
||||
|
||||
if (Format == iCurImage->Format && Type == iCurImage->Type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Converted != Data)
|
||||
ifree(Converted);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Ripped from Platinum (Denton's sources)
|
||||
// This could very well easily be changed to a 128x128 image instead...needed?
|
||||
|
||||
//! Creates an ugly 64x64 black and yellow checkerboard image.
|
||||
ILboolean ILAPIENTRY ilDefaultImage()
|
||||
{
|
||||
ILubyte *TempData;
|
||||
ILubyte Yellow[3] = { 18, 246, 243 };
|
||||
ILubyte Black[3] = { 0, 0, 0 };
|
||||
ILubyte *ColorPtr = Yellow; // The start color
|
||||
ILboolean Color = IL_TRUE;
|
||||
|
||||
// Loop Variables
|
||||
ILint v, w, x, y;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!ilTexImage(64, 64, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
TempData = iCurImage->Data;
|
||||
|
||||
for (v = 0; v < 8; v++) {
|
||||
// We do this because after a "block" line ends, the next row of blocks
|
||||
// above starts with the ending colour, but the very inner loop switches them.
|
||||
if (Color) {
|
||||
Color = IL_FALSE;
|
||||
ColorPtr = Black;
|
||||
}
|
||||
else {
|
||||
Color = IL_TRUE;
|
||||
ColorPtr = Yellow;
|
||||
}
|
||||
|
||||
for (w = 0; w < 8; w++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
for (y = 0; y < 8; y++, TempData += iCurImage->Bpp) {
|
||||
TempData[0] = ColorPtr[0];
|
||||
TempData[1] = ColorPtr[1];
|
||||
TempData[2] = ColorPtr[2];
|
||||
}
|
||||
|
||||
// Switch to alternate between black and yellow
|
||||
if (Color) {
|
||||
Color = IL_FALSE;
|
||||
ColorPtr = Black;
|
||||
}
|
||||
else {
|
||||
Color = IL_TRUE;
|
||||
ColorPtr = Yellow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILubyte* ILAPIENTRY ilGetAlpha(ILenum Type)
|
||||
{
|
||||
ILimage *TempImage;
|
||||
ILubyte *Alpha;
|
||||
ILushort *AlphaShort;
|
||||
ILuint *AlphaInt;
|
||||
ILdouble *AlphaDbl;
|
||||
ILuint i, j, Bpc, Size, AlphaOff;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Bpc = ilGetBpcType(Type);
|
||||
if (Bpc == 0) {
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (iCurImage->Type == Type) {
|
||||
TempImage = iCurImage;
|
||||
} else {
|
||||
TempImage = iConvertImage(iCurImage, iCurImage->Format, Type);
|
||||
if (TempImage == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Size = iCurImage->Width * iCurImage->Height * iCurImage->Depth * TempImage->Bpp;
|
||||
Alpha = (ILubyte*)ialloc(Size / TempImage->Bpp * Bpc);
|
||||
if (Alpha == NULL) {
|
||||
if (TempImage != iCurImage)
|
||||
ilCloseImage(TempImage);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (TempImage->Format)
|
||||
{
|
||||
case IL_RGB:
|
||||
case IL_BGR:
|
||||
case IL_LUMINANCE:
|
||||
case IL_COLOUR_INDEX: // @TODO: Make IL_COLOUR_INDEX separate.
|
||||
memset(Alpha, 0xFF, Size / TempImage->Bpp * Bpc);
|
||||
if (TempImage != iCurImage)
|
||||
ilCloseImage(TempImage);
|
||||
return Alpha;
|
||||
}
|
||||
|
||||
// If our format is alpha, just return a copy.
|
||||
if (TempImage->Format == IL_ALPHA) {
|
||||
memcpy(Alpha, TempImage->Data, TempImage->SizeOfData);
|
||||
return Alpha;
|
||||
}
|
||||
|
||||
if (TempImage->Format == IL_LUMINANCE_ALPHA)
|
||||
AlphaOff = 2;
|
||||
else
|
||||
AlphaOff = 4;
|
||||
|
||||
switch (TempImage->Type)
|
||||
{
|
||||
case IL_BYTE:
|
||||
case IL_UNSIGNED_BYTE:
|
||||
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
|
||||
Alpha[j] = TempImage->Data[i];
|
||||
break;
|
||||
|
||||
case IL_SHORT:
|
||||
case IL_UNSIGNED_SHORT:
|
||||
AlphaShort = (ILushort*)Alpha;
|
||||
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
|
||||
AlphaShort[j] = ((ILushort*)TempImage->Data)[i];
|
||||
break;
|
||||
|
||||
case IL_INT:
|
||||
case IL_UNSIGNED_INT:
|
||||
case IL_FLOAT: // Can throw float in here, because it's the same size.
|
||||
AlphaInt = (ILuint*)Alpha;
|
||||
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
|
||||
AlphaInt[j] = ((ILuint*)TempImage->Data)[i];
|
||||
break;
|
||||
|
||||
case IL_DOUBLE:
|
||||
AlphaDbl = (ILdouble*)Alpha;
|
||||
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
|
||||
AlphaDbl[j] = ((ILdouble*)TempImage->Data)[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (TempImage != iCurImage)
|
||||
ilCloseImage(TempImage);
|
||||
|
||||
return Alpha;
|
||||
}
|
||||
|
||||
// sets the Alpha value to a specific value for each pixel in the image
|
||||
ILboolean ILAPIENTRY ilSetAlpha(ILdouble AlphaValue)
|
||||
{
|
||||
ILboolean ret = IL_TRUE;
|
||||
ILuint i,Size;
|
||||
ILimage *Image = iCurImage;
|
||||
ILuint AlphaOff;
|
||||
|
||||
if (Image == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
AlphaValue = IL_CLAMP(AlphaValue);
|
||||
|
||||
switch (Image->Format)
|
||||
{
|
||||
case IL_RGB:
|
||||
ret = ilConvertImage(IL_RGBA, Image->Type);
|
||||
case IL_RGBA:
|
||||
AlphaOff = 4;
|
||||
break;
|
||||
case IL_BGR:
|
||||
ret = ilConvertImage(IL_BGRA, Image->Type);
|
||||
case IL_BGRA:
|
||||
AlphaOff = 4;
|
||||
break;
|
||||
case IL_LUMINANCE:
|
||||
ret = ilConvertImage(IL_LUMINANCE_ALPHA, Image->Type);
|
||||
case IL_LUMINANCE_ALPHA:
|
||||
AlphaOff = 2;
|
||||
break;
|
||||
case IL_ALPHA:
|
||||
AlphaOff = 1;
|
||||
case IL_COLOUR_INDEX: //@TODO use palette with alpha
|
||||
ret = ilConvertImage(IL_RGBA, Image->Type);
|
||||
AlphaOff = 4;
|
||||
break;
|
||||
}
|
||||
if (ret == IL_FALSE) {
|
||||
// Error has been set by ilConvertImage.
|
||||
return IL_FALSE;
|
||||
}
|
||||
Size = Image->Width * Image->Height * Image->Depth * Image->Bpp;
|
||||
|
||||
switch (iCurImage->Type)
|
||||
{
|
||||
case IL_BYTE:
|
||||
case IL_UNSIGNED_BYTE: {
|
||||
const ILbyte alpha = (ILubyte)(AlphaValue * IL_MAX_UNSIGNED_BYTE + .5);
|
||||
for (i = AlphaOff-1; i < Size; i += AlphaOff)
|
||||
Image->Data[i] = alpha;
|
||||
break;
|
||||
}
|
||||
case IL_SHORT:
|
||||
case IL_UNSIGNED_SHORT: {
|
||||
const ILushort alpha = (ILushort)(AlphaValue * IL_MAX_UNSIGNED_SHORT + .5);
|
||||
for (i = AlphaOff-1; i < Size; i += AlphaOff)
|
||||
((ILushort*)Image->Data)[i] = alpha;
|
||||
break;
|
||||
}
|
||||
case IL_INT:
|
||||
case IL_UNSIGNED_INT: {
|
||||
const ILushort alpha = (ILushort)(AlphaValue * IL_MAX_UNSIGNED_INT + .5);
|
||||
for (i = AlphaOff-1; i < Size; i += AlphaOff)
|
||||
((ILuint*)Image->Data)[i] = alpha;
|
||||
break;
|
||||
}
|
||||
case IL_FLOAT: {
|
||||
const ILfloat alpha = (ILfloat)AlphaValue;
|
||||
for (i = AlphaOff-1; i < Size; i += AlphaOff)
|
||||
((ILfloat*)Image->Data)[i] = alpha;
|
||||
break;
|
||||
}
|
||||
case IL_DOUBLE: {
|
||||
const ILdouble alpha = AlphaValue;
|
||||
for (i = AlphaOff-1; i < Size; i += AlphaOff)
|
||||
((ILdouble*)Image->Data)[i] = alpha;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
void ILAPIENTRY ilModAlpha(ILdouble AlphaValue)
|
||||
{
|
||||
ILuint AlphaOff = 0;
|
||||
ILboolean ret = IL_FALSE;
|
||||
ILuint i,j,Size;
|
||||
|
||||
union {
|
||||
ILubyte alpha_byte;
|
||||
ILushort alpha_short;
|
||||
ILuint alpha_int;
|
||||
ILfloat alpha_float;
|
||||
ILdouble alpha_double;
|
||||
} Alpha;
|
||||
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (iCurImage->Format)
|
||||
{
|
||||
case IL_RGB:
|
||||
ret = ilConvertImage(IL_RGBA,iCurImage->Type);
|
||||
AlphaOff = 4;
|
||||
break;
|
||||
case IL_BGR:
|
||||
ret = ilConvertImage(IL_BGRA,iCurImage->Type);
|
||||
AlphaOff = 4;
|
||||
break;
|
||||
case IL_LUMINANCE:
|
||||
ret = ilConvertImage(IL_LUMINANCE_ALPHA,iCurImage->Type);
|
||||
AlphaOff = 2;
|
||||
break;
|
||||
case IL_COLOUR_INDEX:
|
||||
ret = ilConvertImage(IL_RGBA,iCurImage->Type);
|
||||
AlphaOff = 4;
|
||||
break;
|
||||
}
|
||||
Size = iCurImage->Width * iCurImage->Height * iCurImage->Depth * iCurImage->Bpp;
|
||||
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
switch (iCurImage->Type)
|
||||
{
|
||||
case IL_BYTE:
|
||||
case IL_UNSIGNED_BYTE:
|
||||
Alpha.alpha_byte = (ILubyte)(AlphaValue * 0x000000FF + .5);
|
||||
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
|
||||
iCurImage->Data[i] = Alpha.alpha_byte;
|
||||
break;
|
||||
case IL_SHORT:
|
||||
case IL_UNSIGNED_SHORT:
|
||||
Alpha.alpha_short = (ILushort)(AlphaValue * 0x0000FFFF + .5);
|
||||
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
|
||||
((ILushort*)iCurImage->Data)[i] = Alpha.alpha_short;
|
||||
break;
|
||||
case IL_INT:
|
||||
case IL_UNSIGNED_INT:
|
||||
Alpha.alpha_int = (ILuint)(AlphaValue * 0xFFFFFFFF + .5);
|
||||
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
|
||||
((ILuint*)iCurImage->Data)[i] = Alpha.alpha_int;
|
||||
break;
|
||||
case IL_FLOAT:
|
||||
Alpha.alpha_float = (ILfloat)AlphaValue;
|
||||
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
|
||||
((ILfloat*)iCurImage->Data)[i] = Alpha.alpha_float;
|
||||
break;
|
||||
case IL_DOUBLE:
|
||||
Alpha.alpha_double = AlphaValue;
|
||||
for (i = AlphaOff-1, j = 0; i < Size; i += AlphaOff, j++)
|
||||
((ILdouble*)iCurImage->Data)[i] = Alpha.alpha_double;
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! Clamps data values of unsigned bytes from 16 to 235 for display on an
|
||||
// NTSC television. Reasoning for this is given at
|
||||
// http://msdn.microsoft.com/en-us/library/bb174608.aspx.
|
||||
ILboolean ILAPIENTRY ilClampNTSC(void)
|
||||
{
|
||||
ILuint x, y, z, c;
|
||||
ILuint Offset = 0;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (iCurImage->Type != IL_UNSIGNED_BYTE) // Should we set an error here?
|
||||
return IL_FALSE;
|
||||
|
||||
for (z = 0; z < iCurImage->Depth; z++) {
|
||||
for (y = 0; y < iCurImage->Height; y++) {
|
||||
for (x = 0; x < iCurImage->Width; x++) {
|
||||
for (c = 0; c < iCurImage->Bpp; c++) {
|
||||
iCurImage->Data[Offset + c] = IL_LIMIT(iCurImage->Data[Offset + c], 16, 235);
|
||||
}
|
||||
Offset += iCurImage->Bpp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_mdl.c
|
||||
//
|
||||
// Description: Reads a Half-Life model file (.mdl).
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_MDL
|
||||
#include "il_mdl.h"
|
||||
|
||||
|
||||
ILboolean iLoadMdlInternal(void);
|
||||
ILboolean iIsValidMdl(void);
|
||||
|
||||
//! Checks if the file specified in FileName is a valid MDL file.
|
||||
ILboolean ilIsValidMdl(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE MdlFile;
|
||||
ILboolean bMdl = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("mdl"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bMdl;
|
||||
}
|
||||
|
||||
MdlFile = iopenr(FileName);
|
||||
if (MdlFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bMdl;
|
||||
}
|
||||
|
||||
bMdl = ilIsValidMdlF(MdlFile);
|
||||
icloser(MdlFile);
|
||||
|
||||
return bMdl;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid MDL file at the current position.
|
||||
ILboolean ilIsValidMdlF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidMdl();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid MDL lump.
|
||||
ILboolean ilIsValidMdlL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidMdl();
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidMdl(void)
|
||||
{
|
||||
ILuint Id, Version;
|
||||
|
||||
Id = GetLittleUInt();
|
||||
Version = GetLittleUInt();
|
||||
iseek(-8, IL_SEEK_CUR); // Restore to previous position.
|
||||
|
||||
// 0x54534449 == "IDST"
|
||||
if (Id != 0x54534449 || Version != 10)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a .mdl file
|
||||
ILboolean ilLoadMdl(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE MdlFile;
|
||||
ILboolean bMdl = IL_FALSE;
|
||||
|
||||
MdlFile = iopenr(FileName);
|
||||
if (MdlFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bMdl;
|
||||
}
|
||||
|
||||
bMdl = ilLoadMdlF(MdlFile);
|
||||
icloser(MdlFile);
|
||||
|
||||
return bMdl;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .mdl file
|
||||
ILboolean ilLoadMdlF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadMdlInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a .mdl
|
||||
ILboolean ilLoadMdlL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadMdlInternal();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadMdlInternal()
|
||||
{
|
||||
ILuint Id, Version, NumTex, TexOff, TexDataOff, Position, ImageNum;
|
||||
ILubyte *TempPal;
|
||||
TEX_HEAD TexHead;
|
||||
ILimage *BaseImage=NULL;
|
||||
ILboolean BaseCreated = IL_FALSE;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Id = GetLittleUInt();
|
||||
Version = GetLittleUInt();
|
||||
|
||||
// 0x54534449 == "IDST"
|
||||
if (Id != 0x54534449 || Version != 10) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Skips the actual model header.
|
||||
iseek(172, IL_SEEK_CUR);
|
||||
|
||||
NumTex = GetLittleUInt();
|
||||
TexOff = GetLittleUInt();
|
||||
TexDataOff = GetLittleUInt();
|
||||
|
||||
if (NumTex == 0 || TexOff == 0 || TexDataOff == 0) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iseek(TexOff, IL_SEEK_SET);
|
||||
|
||||
for (ImageNum = 0; ImageNum < NumTex; ImageNum++) {
|
||||
if (iread(TexHead.Name, 1, 64) != 64)
|
||||
return IL_FALSE;
|
||||
TexHead.Flags = GetLittleUInt();
|
||||
TexHead.Width = GetLittleUInt();
|
||||
TexHead.Height = GetLittleUInt();
|
||||
TexHead.Offset = GetLittleUInt();
|
||||
Position = itell();
|
||||
|
||||
if (TexHead.Offset == 0) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!BaseCreated) {
|
||||
ilTexImage(TexHead.Width, TexHead.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL);
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
BaseCreated = IL_TRUE;
|
||||
BaseImage = iCurImage;
|
||||
//iCurImage->NumNext = NumTex - 1; // Don't count the first image.
|
||||
}
|
||||
else {
|
||||
//iCurImage->Next = ilNewImage(TexHead.Width, TexHead.Height, 1, 1, 1);
|
||||
iCurImage = iCurImage->Next;
|
||||
iCurImage->Format = IL_COLOUR_INDEX;
|
||||
iCurImage->Type = IL_UNSIGNED_BYTE;
|
||||
}
|
||||
|
||||
TempPal = (ILubyte*)ialloc(768);
|
||||
if (TempPal == NULL) {
|
||||
iCurImage = BaseImage;
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Pal.Palette = TempPal;
|
||||
iCurImage->Pal.PalSize = 768;
|
||||
iCurImage->Pal.PalType = IL_PAL_RGB24;
|
||||
|
||||
iseek(TexHead.Offset, IL_SEEK_SET);
|
||||
if (iread(iCurImage->Data, TexHead.Width * TexHead.Height, 1) != 1)
|
||||
return IL_FALSE;
|
||||
if (iread(iCurImage->Pal.Palette, 1, 768) != 768)
|
||||
return IL_FALSE;
|
||||
|
||||
if (ilGetBoolean(IL_CONV_PAL) == IL_TRUE) {
|
||||
ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
|
||||
}
|
||||
|
||||
iseek(Position, IL_SEEK_SET);
|
||||
}
|
||||
|
||||
iCurImage = BaseImage;
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
#endif//IL_NO_MDL
|
||||
@@ -0,0 +1,378 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_mng.c
|
||||
//
|
||||
// Description: Multiple Network Graphics (.mng) functions
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_MNG
|
||||
#define MNG_SUPPORT_READ
|
||||
#define MNG_SUPPORT_WRITE
|
||||
#define MNG_SUPPORT_DISPLAY
|
||||
|
||||
#ifdef _WIN32
|
||||
//#define MNG_USE_SO
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#ifndef _DEBUG
|
||||
#pragma comment(lib, "libmng.lib")
|
||||
#pragma comment(lib, "lcms.lib")
|
||||
#pragma comment(lib, "libjpeg.lib")
|
||||
#pragma comment(lib, "zlib.lib")
|
||||
#else
|
||||
#pragma comment(lib, "libmng-d.lib")
|
||||
#pragma comment(lib, "lcms-d.lib")
|
||||
#pragma comment(lib, "libjpeg-d.lib")
|
||||
#pragma comment(lib, "zlib-d.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4142) // Redefinition in jmorecfg.h
|
||||
#endif
|
||||
|
||||
#include <libmng.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// memory allocation; data must be zeroed
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_ptr MNG_DECL mymngalloc(mng_size_t size)
|
||||
{
|
||||
return (mng_ptr)icalloc(1, size);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// memory deallocation
|
||||
//---------------------------------------------------------------------------------------------
|
||||
void MNG_DECL mymngfree(mng_ptr p, mng_size_t size)
|
||||
{
|
||||
ifree(p);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// Stream open:
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_bool MNG_DECL mymngopenstream(mng_handle mng)
|
||||
{
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// Stream open for Writing:
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_bool MNG_DECL mymngopenstreamwrite(mng_handle mng)
|
||||
{
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// Stream close:
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_bool MNG_DECL mymngclosestream(mng_handle mng)
|
||||
{
|
||||
return MNG_TRUE; // We close the file ourself, mng_cleanup doesnt seem to do it...
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// feed data to the decoder
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_bool MNG_DECL mymngreadstream(mng_handle mng, mng_ptr buffer, mng_size_t size, mng_uint32 *bytesread)
|
||||
{
|
||||
// read the requested amount of data from the file
|
||||
*bytesread = iread(buffer, 1, (ILuint)size);
|
||||
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// callback for writing data
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_bool MNG_DECL mymngwritedata(mng_handle mng, mng_ptr buffer, mng_size_t size, mng_uint32 *byteswritten)
|
||||
{
|
||||
*byteswritten = iwrite(buffer, 1, (ILuint)size);
|
||||
|
||||
if (*byteswritten < size) {
|
||||
ilSetError(IL_FILE_WRITE_ERROR);
|
||||
return MNG_FALSE;
|
||||
}
|
||||
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// the header's been read. set up the display stuff
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_bool MNG_DECL mymngprocessheader(mng_handle mng, mng_uint32 width, mng_uint32 height)
|
||||
{
|
||||
ILuint AlphaDepth;
|
||||
|
||||
AlphaDepth = mng_get_alphadepth(mng);
|
||||
|
||||
if (AlphaDepth == 0) {
|
||||
ilTexImage(width, height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL);
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
mng_set_canvasstyle(mng, MNG_CANVAS_BGR8);
|
||||
}
|
||||
else { // Use alpha channel
|
||||
ilTexImage(width, height, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL);
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
mng_set_canvasstyle(mng, MNG_CANVAS_BGRA8);
|
||||
}
|
||||
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// return a row pointer for the decoder to fill
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_ptr MNG_DECL mymnggetcanvasline(mng_handle mng, mng_uint32 line)
|
||||
{
|
||||
return (mng_ptr)(iCurImage->Data + iCurImage->Bps * line);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// timer
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_uint32 MNG_DECL mymnggetticks(mng_handle mng)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// Refresh:
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_bool MNG_DECL mymngrefresh(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h)
|
||||
{
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// interframe delay callback
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_bool MNG_DECL mymngsettimer(mng_handle mng, mng_uint32 msecs)
|
||||
{
|
||||
return MNG_TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Make this do something different soon!
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
// Error Callback;
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mng_bool MNG_DECL mymngerror(
|
||||
mng_handle mng, mng_int32 code, mng_int8 severity,
|
||||
mng_chunkid chunktype, mng_uint32 chunkseq,
|
||||
mng_int32 extra1, mng_int32 extra2, mng_pchar text
|
||||
)
|
||||
{
|
||||
// error occured;
|
||||
return MNG_FALSE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadMngInternal(void);
|
||||
|
||||
// Reads a file
|
||||
ILboolean ilLoadMng(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE MngFile;
|
||||
ILboolean bMng = IL_FALSE;
|
||||
|
||||
MngFile = iopenr(FileName);
|
||||
if (MngFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bMng;
|
||||
}
|
||||
|
||||
bMng = ilLoadMngF(MngFile);
|
||||
icloser(MngFile);
|
||||
|
||||
return bMng;
|
||||
}
|
||||
|
||||
|
||||
// Reads an already-opened file
|
||||
ILboolean ilLoadMngF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadMngInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
// Reads from a memory "lump"
|
||||
ILboolean ilLoadMngL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadMngInternal();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadMngInternal()
|
||||
{
|
||||
mng_handle mng;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
mng = mng_initialize(MNG_NULL, mymngalloc, mymngfree, MNG_NULL);
|
||||
if (mng == MNG_NULL) {
|
||||
ilSetError(IL_LIB_MNG_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// If .mng background is available, use it.
|
||||
mng_set_usebkgd(mng, MNG_TRUE);
|
||||
|
||||
// Set the callbacks.
|
||||
mng_setcb_errorproc(mng, mymngerror);
|
||||
mng_setcb_openstream(mng, mymngopenstream);
|
||||
mng_setcb_closestream(mng, mymngclosestream);
|
||||
mng_setcb_readdata(mng, (mng_readdata)mymngreadstream);
|
||||
mng_setcb_gettickcount(mng, mymnggetticks);
|
||||
mng_setcb_settimer(mng, mymngsettimer);
|
||||
mng_setcb_processheader(mng, mymngprocessheader);
|
||||
mng_setcb_getcanvasline(mng, mymnggetcanvasline);
|
||||
mng_setcb_refresh(mng, mymngrefresh);
|
||||
|
||||
mng_read(mng);
|
||||
mng_display(mng);
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iSaveMngInternal(void);
|
||||
|
||||
//! Writes a Mng file
|
||||
ILboolean ilSaveMng(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE MngFile;
|
||||
ILuint MngSize;
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
MngFile = iopenw(FileName);
|
||||
if (MngFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
MngSize = ilSaveMngF(MngFile);
|
||||
iclosew(MngFile);
|
||||
|
||||
if (MngSize == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Mng to an already-opened file
|
||||
ILuint ilSaveMngF(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos = itellw();
|
||||
iSetOutputFile(File);
|
||||
if (iSaveMngInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Mng to a memory "lump"
|
||||
ILuint ilSaveMngL(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputLump(Lump, Size);
|
||||
Pos = itellw();
|
||||
if (iSaveMngInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to save the Mng.
|
||||
ILboolean iSaveMngInternal()
|
||||
{
|
||||
//mng_handle mng;
|
||||
|
||||
// Not working yet, so just error out.
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return IL_FALSE;
|
||||
|
||||
//if (iCurImage == NULL) {
|
||||
// ilSetError(IL_ILLEGAL_OPERATION);
|
||||
// return IL_FALSE;
|
||||
//}
|
||||
|
||||
//mng = mng_initialize(MNG_NULL, mymngalloc, mymngfree, MNG_NULL);
|
||||
//if (mng == MNG_NULL) {
|
||||
// ilSetError(IL_LIB_MNG_ERROR);
|
||||
// return IL_FALSE;
|
||||
//}
|
||||
|
||||
//mng_setcb_openstream(mng, mymngopenstreamwrite);
|
||||
//mng_setcb_closestream(mng, mymngclosestream);
|
||||
//mng_setcb_writedata(mng, mymngwritedata);
|
||||
|
||||
//// Write File:
|
||||
// mng_create(mng);
|
||||
|
||||
//// Check return value.
|
||||
//mng_putchunk_mhdr(mng, iCurImage->Width, iCurImage->Height, 1000, 3, 1, 3, 0x0047);
|
||||
//mng_putchunk_basi(mng, iCurImage->Width, iCurImage->Height, 8, MNG_COLORTYPE_RGB, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1);
|
||||
//mng_putchunk_iend(mng);
|
||||
//mng_putimgdata_ihdr(mng, iCurImage->Width, iCurImage->Height, MNG_COLORTYPE_RGB, 8, 0, 0, 0, 0, mymnggetcanvasline);
|
||||
|
||||
//// Now write file:
|
||||
//mng_write(mng);
|
||||
|
||||
//mng_cleanup(&mng);
|
||||
|
||||
//return IL_TRUE;
|
||||
}
|
||||
|
||||
#endif//IL_NO_MNG
|
||||
@@ -0,0 +1,280 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/05/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_mp3.c
|
||||
//
|
||||
// MimeType: Reads from an MPEG-1 Audio Layer 3 (.mp3) file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_MP3
|
||||
|
||||
typedef struct MP3HEAD
|
||||
{
|
||||
char Signature[3];
|
||||
ILubyte VersionMajor;
|
||||
ILubyte VersionMinor;
|
||||
ILubyte Flags;
|
||||
ILuint Length;
|
||||
} MP3HEAD;
|
||||
|
||||
#define MP3_NONE 0
|
||||
#define MP3_JPG 1
|
||||
#define MP3_PNG 2
|
||||
|
||||
ILboolean iLoadMp3Internal(void);
|
||||
ILboolean iIsValidMp3(void);
|
||||
ILboolean iCheckMp3(MP3HEAD *Header);
|
||||
ILboolean iLoadJpegInternal(void);
|
||||
ILboolean iLoadPngInternal(void);
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid MP3 file.
|
||||
ILboolean ilIsValidMp3(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE Mp3File;
|
||||
ILboolean bMp3 = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("mp3"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bMp3;
|
||||
}
|
||||
|
||||
Mp3File = iopenr(FileName);
|
||||
if (Mp3File == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bMp3;
|
||||
}
|
||||
|
||||
bMp3 = ilIsValidMp3F(Mp3File);
|
||||
icloser(Mp3File);
|
||||
|
||||
return bMp3;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid MP3 file at the current position.
|
||||
ILboolean ilIsValidMp3F(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidMp3();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid MP3 lump.
|
||||
ILboolean ilIsValidMp3L(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidMp3();
|
||||
}
|
||||
|
||||
|
||||
ILuint GetSynchInt()
|
||||
{
|
||||
ILuint SynchInt;
|
||||
|
||||
SynchInt = GetBigUInt();
|
||||
|
||||
SynchInt = ((SynchInt & 0x7F000000) >> 3) | ((SynchInt & 0x7F0000) >> 2)
|
||||
| ((SynchInt & 0x7F00) >> 1) | (SynchInt & 0x7F);
|
||||
|
||||
return SynchInt;
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the MP3 header from the current file.
|
||||
ILboolean iGetMp3Head(MP3HEAD *Header)
|
||||
{
|
||||
if (iread(Header->Signature, 3, 1) != 1)
|
||||
return IL_FALSE;
|
||||
Header->VersionMajor = igetc();
|
||||
Header->VersionMinor = igetc();
|
||||
Header->Flags = igetc();
|
||||
Header->Length = GetSynchInt();
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidMp3(void)
|
||||
{
|
||||
MP3HEAD Header;
|
||||
ILuint Pos = itell();
|
||||
|
||||
if (!iGetMp3Head(&Header))
|
||||
return IL_FALSE;
|
||||
// The length of the header varies, so we just go back to the original position.
|
||||
iseek(Pos, IL_SEEK_CUR);
|
||||
|
||||
return iCheckMp3(&Header);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid MP3 header.
|
||||
ILboolean iCheckMp3(MP3HEAD *Header)
|
||||
{
|
||||
if (strncmp(Header->Signature, "ID3", 3))
|
||||
return IL_FALSE;
|
||||
if (Header->VersionMajor != 3 && Header->VersionMinor != 4)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILuint iFindMp3Pic(MP3HEAD *Header)
|
||||
{
|
||||
char ID[4];
|
||||
ILuint FrameSize;
|
||||
ILubyte TextEncoding;
|
||||
ILubyte MimeType[65], Description[65];
|
||||
ILubyte PicType;
|
||||
ILuint i;
|
||||
ILuint Type = MP3_NONE;
|
||||
|
||||
do {
|
||||
if (iread(ID, 4, 1) != 1)
|
||||
return MP3_NONE;
|
||||
if (Header->VersionMajor == 3)
|
||||
FrameSize = GetBigUInt();
|
||||
else
|
||||
FrameSize = GetSynchInt();
|
||||
|
||||
GetBigUShort(); // Skip the flags.
|
||||
|
||||
//@TODO: Support multiple APIC entries in an mp3 file.
|
||||
if (!strncmp(ID, "APIC", 4)) {
|
||||
//@TODO: Use TextEncoding properly - UTF16 strings starting with FFFE or FEFF.
|
||||
TextEncoding = igetc();
|
||||
// Get the MimeType (read until we hit 0).
|
||||
for (i = 0; i < 65; i++) {
|
||||
MimeType[i] = igetc();
|
||||
if (MimeType[i] == 0)
|
||||
break;
|
||||
}
|
||||
// The MimeType must be terminated by 0 in the file by the specs.
|
||||
if (MimeType[i] != 0)
|
||||
return MP3_NONE;
|
||||
if (!strcmp(MimeType, "image/jpeg"))
|
||||
Type = MP3_JPG;
|
||||
else if (!strcmp(MimeType, "image/png"))
|
||||
Type = MP3_PNG;
|
||||
else
|
||||
Type = MP3_NONE;
|
||||
|
||||
PicType = igetc(); // Whether this is a cover, band logo, etc.
|
||||
|
||||
// Skip the description.
|
||||
for (i = 0; i < 65; i++) {
|
||||
Description[i] = igetc();
|
||||
if (Description[i] == 0)
|
||||
break;
|
||||
}
|
||||
if (Description[i] != 0)
|
||||
return MP3_NONE;
|
||||
return Type;
|
||||
}
|
||||
else {
|
||||
iseek(FrameSize, IL_SEEK_CUR);
|
||||
}
|
||||
|
||||
//if (!strncmp(MimeType, "
|
||||
} while (!ieof() && itell() < Header->Length);
|
||||
|
||||
return Type;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a MP3 file
|
||||
ILboolean ilLoadMp3(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE Mp3File;
|
||||
ILboolean bMp3 = IL_FALSE;
|
||||
|
||||
Mp3File = iopenr(FileName);
|
||||
if (Mp3File == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bMp3;
|
||||
}
|
||||
|
||||
bMp3 = ilLoadMp3F(Mp3File);
|
||||
icloser(Mp3File);
|
||||
|
||||
return bMp3;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened MP3 file
|
||||
ILboolean ilLoadMp3F(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadMp3Internal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a MP3
|
||||
ILboolean ilLoadMp3L(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadMp3Internal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the MP3.
|
||||
ILboolean iLoadMp3Internal(void)
|
||||
{
|
||||
MP3HEAD Header;
|
||||
ILuint Type;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!iGetMp3Head(&Header))
|
||||
return IL_FALSE;
|
||||
if (!iCheckMp3(&Header))
|
||||
return IL_FALSE;
|
||||
Type = iFindMp3Pic(&Header);
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
#ifndef IL_NO_JPG
|
||||
case MP3_JPG:
|
||||
return iLoadJpegInternal();
|
||||
#endif//IL_NO_JPG
|
||||
|
||||
#ifndef IL_NO_PNG
|
||||
case MP3_PNG:
|
||||
return iLoadPngInternal();
|
||||
#endif//IL_NO_PNG
|
||||
|
||||
// Either a picture was not found, or the MIME type was not recognized.
|
||||
default:
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
}
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
#endif//IL_NO_MP3
|
||||
|
||||
@@ -0,0 +1,462 @@
|
||||
/* NeuQuant Neural-Net Quantization Algorithm
|
||||
* ------------------------------------------
|
||||
*
|
||||
* Copyright (c) 1994 Anthony Dekker
|
||||
*
|
||||
* NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
|
||||
* See "Kohonen neural networks for optimal colour quantization"
|
||||
* in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
|
||||
* for a discussion of the algorithm.
|
||||
* See also http://www.acm.org/~dekker/NEUQUANT.HTML
|
||||
*
|
||||
* Any party obtaining a copy of these files from the author, directly or
|
||||
* indirectly, is granted, free of charge, a full and unrestricted irrevocable,
|
||||
* world-wide, paid up, royalty-free, nonexclusive right and license to deal
|
||||
* in this software and documentation files (the "Software"), including without
|
||||
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons who receive
|
||||
* copies from any such party to do so, with the only requirement being
|
||||
* that this copyright notice remain intact.
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// by Denton Woods
|
||||
// Last modified: 01/04/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_neuquant.c
|
||||
//
|
||||
// Description: Heavily modified by Denton Woods.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
|
||||
|
||||
// Function definitions
|
||||
void initnet(ILubyte *thepic, ILint len, ILint sample);
|
||||
void unbiasnet();
|
||||
void inxbuild();
|
||||
ILubyte inxsearch(ILint b, ILint g, ILint r);
|
||||
void learn();
|
||||
|
||||
// four primes near 500 - assume no image has a length so large
|
||||
// that it is divisible by all four primes
|
||||
#define prime1 499
|
||||
#define prime2 491
|
||||
#define prime3 487
|
||||
#define prime4 503
|
||||
|
||||
#define minpicturebytes (3*prime4) // minimum size for input image
|
||||
|
||||
|
||||
// Network Definitions
|
||||
// -------------------
|
||||
|
||||
#define netsize 256 // number of colours used
|
||||
#define maxnetpos (netsizethink-1)
|
||||
#define netbiasshift 4 // bias for colour values
|
||||
#define ncycles 100 // no. of learning cycles
|
||||
|
||||
// defs for freq and bias
|
||||
#define intbiasshift 16 // bias for fractions
|
||||
#define intbias (((ILint) 1)<<intbiasshift)
|
||||
#define gammashift 10 // gamma = 1024
|
||||
#define gamma (((ILint) 1)<<gammashift)
|
||||
#define betashift 10
|
||||
#define beta (intbias>>betashift)// beta = 1/1024
|
||||
#define betagamma (intbias<<(gammashift-betashift))
|
||||
|
||||
// defs for decreasing radius factor
|
||||
#define initrad (netsize>>3) // for 256 cols, radius starts
|
||||
#define radiusbiasshift 6 // at 32.0 biased by 6 bits
|
||||
#define radiusbias (((ILint) 1)<<radiusbiasshift)
|
||||
#define initradius (initrad*radiusbias) // and decreases by a
|
||||
#define radiusdec 30 // factor of 1/30 each cycle
|
||||
|
||||
// defs for decreasing alpha factor
|
||||
#define alphabiasshift 10 // alpha starts at 1.0
|
||||
#define initalpha (((ILint) 1)<<alphabiasshift)
|
||||
ILint alphadec; // biased by 10 bits
|
||||
|
||||
// radbias and alpharadbias used for radpower calculation
|
||||
#define radbiasshift 8
|
||||
#define radbias (((ILint) 1)<<radbiasshift)
|
||||
#define alpharadbshift (alphabiasshift+radbiasshift)
|
||||
#define alpharadbias (((ILint) 1)<<alpharadbshift)
|
||||
|
||||
|
||||
// Types and Global Variables
|
||||
// --------------------------
|
||||
|
||||
unsigned char *thepicture; // the input image itself
|
||||
int lengthcount; // lengthcount = H*W*3
|
||||
int samplefac; // sampling factor 1..30
|
||||
typedef int pixel[4]; // BGRc
|
||||
static pixel network[netsize]; // the network itself
|
||||
int netindex[256]; // for network lookup - really 256
|
||||
int bias [netsize]; // bias and freq arrays for learning
|
||||
int freq [netsize];
|
||||
int radpower[initrad]; // radpower for precomputation
|
||||
|
||||
int netsizethink; // number of colors we want to reduce to, 2-256
|
||||
|
||||
// Initialise network in range (0,0,0) to (255,255,255) and set parameters
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
void initnet(ILubyte *thepic, ILint len, ILint sample)
|
||||
{
|
||||
ILint i;
|
||||
ILint *p;
|
||||
|
||||
thepicture = thepic;
|
||||
lengthcount = len;
|
||||
samplefac = sample;
|
||||
|
||||
for (i=0; i<netsizethink; i++) {
|
||||
p = network[i];
|
||||
p[0] = p[1] = p[2] = (i << (netbiasshift+8))/netsize;
|
||||
freq[i] = intbias/netsizethink; // 1/netsize
|
||||
bias[i] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Unbias network to give byte values 0..255 and record position i to prepare for sort
|
||||
// -----------------------------------------------------------------------------------
|
||||
|
||||
void unbiasnet()
|
||||
{
|
||||
ILint i,j;
|
||||
|
||||
for (i=0; i<netsizethink; i++) {
|
||||
for (j=0; j<3; j++)
|
||||
network[i][j] >>= netbiasshift;
|
||||
network[i][3] = i; // record colour no
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Insertion sort of network and building of netindex[0..255] (to do after unbias)
|
||||
// -------------------------------------------------------------------------------
|
||||
|
||||
void inxbuild()
|
||||
{
|
||||
ILint i,j,smallpos,smallval;
|
||||
ILint *p,*q;
|
||||
ILint previouscol,startpos;
|
||||
|
||||
previouscol = 0;
|
||||
startpos = 0;
|
||||
for (i=0; i<netsizethink; i++) {
|
||||
p = network[i];
|
||||
smallpos = i;
|
||||
smallval = p[1]; // index on g
|
||||
// find smallest in i..netsize-1
|
||||
for (j=i+1; j<netsizethink; j++) {
|
||||
q = network[j];
|
||||
if (q[1] < smallval) { // index on g
|
||||
smallpos = j;
|
||||
smallval = q[1]; // index on g
|
||||
}
|
||||
}
|
||||
q = network[smallpos];
|
||||
// swap p (i) and q (smallpos) entries
|
||||
if (i != smallpos) {
|
||||
j = q[0]; q[0] = p[0]; p[0] = j;
|
||||
j = q[1]; q[1] = p[1]; p[1] = j;
|
||||
j = q[2]; q[2] = p[2]; p[2] = j;
|
||||
j = q[3]; q[3] = p[3]; p[3] = j;
|
||||
}
|
||||
// smallval entry is now in position i
|
||||
if (smallval != previouscol) {
|
||||
netindex[previouscol] = (startpos+i)>>1;
|
||||
for (j=previouscol+1; j<smallval; j++) netindex[j] = i;
|
||||
previouscol = smallval;
|
||||
startpos = i;
|
||||
}
|
||||
}
|
||||
netindex[previouscol] = (startpos+maxnetpos)>>1;
|
||||
for (j=previouscol+1; j<256; j++) netindex[j] = maxnetpos; // really 256
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Search for BGR values 0..255 (after net is unbiased) and return colour index
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
ILubyte inxsearch(ILint b, ILint g, ILint r)
|
||||
{
|
||||
ILint i,j,dist,a,bestd;
|
||||
ILint *p;
|
||||
ILint best;
|
||||
|
||||
bestd = 1000; // biggest possible dist is 256*3
|
||||
best = -1;
|
||||
i = netindex[g]; // index on g
|
||||
j = i-1; // start at netindex[g] and work outwards
|
||||
|
||||
while ((i<netsizethink) || (j>=0)) {
|
||||
if (i<netsizethink) {
|
||||
p = network[i];
|
||||
dist = p[1] - g; // inx key
|
||||
if (dist >= bestd) i = netsizethink; // stop iter
|
||||
else {
|
||||
i++;
|
||||
if (dist<0) dist = -dist;
|
||||
a = p[0] - b; if (a<0) a = -a;
|
||||
dist += a;
|
||||
if (dist<bestd) {
|
||||
a = p[2] - r; if (a<0) a = -a;
|
||||
dist += a;
|
||||
if (dist<bestd) {bestd=dist; best=p[3];}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j>=0) {
|
||||
p = network[j];
|
||||
dist = g - p[1]; // inx key - reverse dif
|
||||
if (dist >= bestd) j = -1; // stop iter
|
||||
else {
|
||||
j--;
|
||||
if (dist<0) dist = -dist;
|
||||
a = p[0] - b; if (a<0) a = -a;
|
||||
dist += a;
|
||||
if (dist<bestd) {
|
||||
a = p[2] - r; if (a<0) a = -a;
|
||||
dist += a;
|
||||
if (dist<bestd) {bestd=dist; best=p[3];}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (ILubyte)best;
|
||||
}
|
||||
|
||||
|
||||
// Search for biased BGR values
|
||||
// ----------------------------
|
||||
|
||||
ILint contest(ILint b, ILint g, ILint r)
|
||||
{
|
||||
// finds closest neuron (min dist) and updates freq
|
||||
// finds best neuron (min dist-bias) and returns position
|
||||
// for frequently chosen neurons, freq[i] is high and bias[i] is negative
|
||||
// bias[i] = gamma*((1/netsize)-freq[i])
|
||||
|
||||
ILint i,dist,a,biasdist,betafreq;
|
||||
ILint bestpos,bestbiaspos,bestd,bestbiasd;
|
||||
ILint *p,*f, *n;
|
||||
|
||||
bestd = ~(((ILint) 1)<<31);
|
||||
bestbiasd = bestd;
|
||||
bestpos = -1;
|
||||
bestbiaspos = bestpos;
|
||||
p = bias;
|
||||
f = freq;
|
||||
|
||||
for (i=0; i<netsizethink; i++) {
|
||||
n = network[i];
|
||||
dist = n[0] - b; if (dist<0) dist = -dist;
|
||||
a = n[1] - g; if (a<0) a = -a;
|
||||
dist += a;
|
||||
a = n[2] - r; if (a<0) a = -a;
|
||||
dist += a;
|
||||
if (dist<bestd) {bestd=dist; bestpos=i;}
|
||||
biasdist = dist - ((*p)>>(intbiasshift-netbiasshift));
|
||||
if (biasdist<bestbiasd) {bestbiasd=biasdist; bestbiaspos=i;}
|
||||
betafreq = (*f >> betashift);
|
||||
*f++ -= betafreq;
|
||||
*p++ += (betafreq<<gammashift);
|
||||
}
|
||||
freq[bestpos] += beta;
|
||||
bias[bestpos] -= betagamma;
|
||||
return(bestbiaspos);
|
||||
}
|
||||
|
||||
|
||||
// Move neuron i towards biased (b,g,r) by factor alpha
|
||||
// ----------------------------------------------------
|
||||
|
||||
void altersingle(ILint alpha, ILint i, ILint b, ILint g, ILint r)
|
||||
{
|
||||
ILint *n;
|
||||
|
||||
n = network[i]; // alter hit neuron
|
||||
*n -= (alpha*(*n - b)) / initalpha;
|
||||
n++;
|
||||
*n -= (alpha*(*n - g)) / initalpha;
|
||||
n++;
|
||||
*n -= (alpha*(*n - r)) / initalpha;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|]
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
void alterneigh(ILint rad, ILint i, ILint b, ILint g, ILint r)
|
||||
{
|
||||
ILint j,k,lo,hi,a;
|
||||
ILint *p, *q;
|
||||
|
||||
lo = i-rad; if (lo<-1) lo=-1;
|
||||
hi = i+rad; if (hi>netsizethink) hi=netsizethink;
|
||||
|
||||
j = i+1;
|
||||
k = i-1;
|
||||
q = radpower;
|
||||
while ((j<hi) || (k>lo)) {
|
||||
a = (*(++q));
|
||||
if (j<hi) {
|
||||
p = network[j];
|
||||
*p -= (a*(*p - b)) / alpharadbias;
|
||||
p++;
|
||||
*p -= (a*(*p - g)) / alpharadbias;
|
||||
p++;
|
||||
*p -= (a*(*p - r)) / alpharadbias;
|
||||
j++;
|
||||
}
|
||||
if (k>lo) {
|
||||
p = network[k];
|
||||
*p -= (a*(*p - b)) / alpharadbias;
|
||||
p++;
|
||||
*p -= (a*(*p - g)) / alpharadbias;
|
||||
p++;
|
||||
*p -= (a*(*p - r)) / alpharadbias;
|
||||
k--;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Main Learning Loop
|
||||
// ------------------
|
||||
|
||||
void learn()
|
||||
{
|
||||
ILint i,j,b,g,r;
|
||||
ILint radius,rad,alpha,step,delta,samplepixels;
|
||||
ILubyte *p;
|
||||
ILubyte *lim;
|
||||
|
||||
alphadec = 30 + ((samplefac-1)/3);
|
||||
p = thepicture;
|
||||
lim = thepicture + lengthcount;
|
||||
samplepixels = lengthcount/(3*samplefac);
|
||||
delta = samplepixels/ncycles;
|
||||
alpha = initalpha;
|
||||
radius = initradius;
|
||||
|
||||
rad = radius >> radiusbiasshift;
|
||||
if (rad <= 1) rad = 0;
|
||||
for (i=0; i<rad; i++)
|
||||
radpower[i] = alpha*(((rad*rad - i*i)*radbias)/(rad*rad));
|
||||
|
||||
// beginning 1D learning: initial radius=rad
|
||||
|
||||
if ((lengthcount%prime1) != 0) step = 3*prime1;
|
||||
else {
|
||||
if ((lengthcount%prime2) !=0) step = 3*prime2;
|
||||
else {
|
||||
if ((lengthcount%prime3) !=0) step = 3*prime3;
|
||||
else step = 3*prime4;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < samplepixels) {
|
||||
b = p[0] << netbiasshift;
|
||||
g = p[1] << netbiasshift;
|
||||
r = p[2] << netbiasshift;
|
||||
j = contest(b,g,r);
|
||||
|
||||
altersingle(alpha,j,b,g,r);
|
||||
if (rad) alterneigh(rad,j,b,g,r); // alter neighbours
|
||||
|
||||
p += step;
|
||||
if (p >= lim) p -= lengthcount;
|
||||
|
||||
i++;
|
||||
if (i%delta == 0) {
|
||||
alpha -= alpha / alphadec;
|
||||
radius -= radius / radiusdec;
|
||||
rad = radius >> radiusbiasshift;
|
||||
if (rad <= 1) rad = 0;
|
||||
for (j=0; j<rad; j++)
|
||||
radpower[j] = alpha*(((rad*rad - j*j)*radbias)/(rad*rad));
|
||||
}
|
||||
}
|
||||
// finished 1D learning: final alpha=alpha/initalpha;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILimage *iNeuQuant(ILimage *Image, ILuint NumCols)
|
||||
{
|
||||
ILimage *TempImage, *NewImage;
|
||||
ILuint sample, i, j;
|
||||
|
||||
netsizethink=NumCols;
|
||||
|
||||
NewImage = iCurImage;
|
||||
iCurImage = Image;
|
||||
TempImage = iConvertImage(iCurImage, IL_BGR, IL_UNSIGNED_BYTE);
|
||||
iCurImage = NewImage;
|
||||
sample = ilGetInteger(IL_NEU_QUANT_SAMPLE);
|
||||
|
||||
if (TempImage == NULL)
|
||||
return NULL;
|
||||
|
||||
initnet(TempImage->Data, TempImage->SizeOfData, sample);
|
||||
learn();
|
||||
unbiasnet();
|
||||
|
||||
NewImage = (ILimage*)icalloc(sizeof(ILimage), 1);
|
||||
if (NewImage == NULL) {
|
||||
ilCloseImage(TempImage);
|
||||
return NULL;
|
||||
}
|
||||
NewImage->Data = (ILubyte*)ialloc(TempImage->SizeOfData / 3);
|
||||
if (NewImage->Data == NULL) {
|
||||
ilCloseImage(TempImage);
|
||||
ifree(NewImage);
|
||||
return NULL;
|
||||
}
|
||||
ilCopyImageAttr(NewImage, Image);
|
||||
NewImage->Bpp = 1;
|
||||
NewImage->Bps = Image->Width;
|
||||
NewImage->SizeOfPlane = NewImage->Bps * Image->Height;
|
||||
NewImage->SizeOfData = NewImage->SizeOfPlane;
|
||||
NewImage->Format = IL_COLOUR_INDEX;
|
||||
NewImage->Type = IL_UNSIGNED_BYTE;
|
||||
|
||||
NewImage->Pal.PalSize = netsizethink * 3;
|
||||
NewImage->Pal.PalType = IL_PAL_BGR24;
|
||||
NewImage->Pal.Palette = (ILubyte*)ialloc(256*3);
|
||||
if (NewImage->Pal.Palette == NULL) {
|
||||
ilCloseImage(TempImage);
|
||||
ilCloseImage(NewImage);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < (unsigned)netsizethink; i++, j += 3) {
|
||||
NewImage->Pal.Palette[j ] = network[i][0];
|
||||
NewImage->Pal.Palette[j+1] = network[i][1];
|
||||
NewImage->Pal.Palette[j+2] = network[i][2];
|
||||
}
|
||||
|
||||
inxbuild();
|
||||
for (i = 0, j = 0; j < TempImage->SizeOfData; i++, j += 3) {
|
||||
NewImage->Data[i] = inxsearch(
|
||||
TempImage->Data[j], TempImage->Data[j+1], TempImage->Data[j+2]);
|
||||
}
|
||||
|
||||
ilCloseImage(TempImage);
|
||||
|
||||
return NewImage;
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 01/19/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_nvidia.cpp
|
||||
//
|
||||
// Description: Implements access to the nVidia Texture Tools library.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#include "il_dds.h"
|
||||
#include "il_manip.h"
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
#ifdef IL_USE_DXTC_NVIDIA
|
||||
#include <nvtt/nvtt.h>
|
||||
#include <nvcore/Memory.h>
|
||||
|
||||
using namespace nvtt;
|
||||
|
||||
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#ifndef _DEBUG
|
||||
#pragma comment(lib, "nvcore.lib")
|
||||
#pragma comment(lib, "nvtt.lib")
|
||||
#else
|
||||
#pragma comment(lib, "nvcore-d.lib")
|
||||
#pragma comment(lib, "nvtt-d.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
struct ilOutputHandlerMem : public nvtt::OutputHandler
|
||||
{
|
||||
ilOutputHandlerMem(ILuint Width, ILuint Height, ILenum DxtType)
|
||||
{
|
||||
Width = Width + (4 - (Width % 4)) % 4; // Operates on 4x4 blocks,
|
||||
Height = Height + (4 - (Height % 4)) % 4; // so gives extra room.
|
||||
|
||||
switch (DxtType)
|
||||
{
|
||||
case IL_DXT1:
|
||||
case IL_DXT1A:
|
||||
Size = Width * Height / 2;
|
||||
break;
|
||||
case IL_DXT3:
|
||||
case IL_DXT5:
|
||||
Size = Width * Height;
|
||||
break;
|
||||
|
||||
default: // NVTT does not accept DXT2 or DXT4.
|
||||
// Should error somehow...
|
||||
break;
|
||||
}
|
||||
NewData = (ILubyte*)ialloc(Size);
|
||||
if (NewData == NULL)
|
||||
return;
|
||||
Temp = NewData;
|
||||
}
|
||||
|
||||
virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
|
||||
{
|
||||
// ignore.
|
||||
}
|
||||
virtual bool writeData(const void *data, int size)
|
||||
{
|
||||
memcpy(Temp, data, size);
|
||||
Temp += size;
|
||||
return true;
|
||||
}
|
||||
|
||||
ILubyte *NewData, *Temp;
|
||||
ILuint Size;
|
||||
};
|
||||
|
||||
|
||||
//! Compresses data to a DXT format using nVidia's Texture Tools library.
|
||||
// The data must be in unsigned byte RGBA format. The alpha channel will be ignored if DxtType is IL_DXT1.
|
||||
// DxtSize is used to return the size in bytes of the DXTC data returned.
|
||||
ILAPI ILubyte* ILAPIENTRY ilNVidiaCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat, ILuint *DxtSize)
|
||||
{
|
||||
if (Data == NULL) { // We cannot operate on a null pointer.
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The nVidia Texture Tools library does not support volume textures yet.
|
||||
if (Depth != 1) {
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InputOptions inputOptions;
|
||||
inputOptions.setTextureLayout(TextureType_2D, Width, Height);
|
||||
inputOptions.setMipmapData(Data, Width, Height);
|
||||
inputOptions.setMipmapGeneration(false, -1); //@TODO: Use this in certain cases.
|
||||
|
||||
OutputOptions outputOptions;
|
||||
ilOutputHandlerMem outputHandler(Width, Height, DxtFormat);
|
||||
outputOptions.setOutputHeader(false);
|
||||
outputOptions.setOutputHandler(&outputHandler);
|
||||
|
||||
if (outputHandler.NewData == NULL)
|
||||
return NULL;
|
||||
|
||||
CompressionOptions compressionOptions;
|
||||
switch (DxtFormat)
|
||||
{
|
||||
case IL_DXT1:
|
||||
compressionOptions.setFormat(Format_DXT1);
|
||||
break;
|
||||
case IL_DXT1A:
|
||||
compressionOptions.setFormat(Format_DXT1a);
|
||||
break;
|
||||
case IL_DXT3:
|
||||
compressionOptions.setFormat(Format_DXT1);
|
||||
break;
|
||||
case IL_DXT5:
|
||||
compressionOptions.setFormat(Format_DXT5);
|
||||
break;
|
||||
default: // Does not support DXT2 or DXT4.
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
break;
|
||||
}
|
||||
|
||||
Compressor compressor;
|
||||
compressor.process(inputOptions, compressionOptions, outputOptions);
|
||||
|
||||
*DxtSize = outputHandler.Size;
|
||||
return outputHandler.NewData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// The following is just a repeat of above, but it works generically on file streams or lumps.
|
||||
// @TODO: Merge these two together.
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
struct ilOutputHandlerFile : public nvtt::OutputHandler
|
||||
{
|
||||
ilOutputHandlerFile(ILuint Width, ILuint Height, ILenum DxtType)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
|
||||
{
|
||||
// ignore.
|
||||
}
|
||||
virtual bool writeData(const void *data, int size)
|
||||
{
|
||||
if (iwrite(data, 1, size) == size)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//! Compresses data to a DXT format using nVidia's Texture Tools library.
|
||||
// This version is supposed to be completely internal to DevIL.
|
||||
// The data must be in unsigned byte RGBA format. The alpha channel will be ignored if DxtType is IL_DXT1.
|
||||
ILuint ilNVidiaCompressDXTFile(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat)
|
||||
{
|
||||
ILuint FilePos = itellw();
|
||||
|
||||
// The nVidia Texture Tools library does not support volume textures yet.
|
||||
if (Depth != 1) {
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
InputOptions inputOptions;
|
||||
inputOptions.setTextureLayout(TextureType_2D, Width, Height);
|
||||
inputOptions.setMipmapData(Data, Width, Height);
|
||||
inputOptions.setMipmapGeneration(false, -1); //@TODO: Use this in certain cases.
|
||||
|
||||
OutputOptions outputOptions;
|
||||
ilOutputHandlerFile outputHandler(Width, Height, DxtFormat);
|
||||
outputOptions.setOutputHeader(false);
|
||||
outputOptions.setOutputHandler(&outputHandler);
|
||||
|
||||
CompressionOptions compressionOptions;
|
||||
switch (DxtFormat)
|
||||
{
|
||||
case IL_DXT1:
|
||||
compressionOptions.setFormat(Format_DXT1);
|
||||
break;
|
||||
case IL_DXT1A:
|
||||
compressionOptions.setFormat(Format_DXT1a);
|
||||
break;
|
||||
case IL_DXT3:
|
||||
compressionOptions.setFormat(Format_DXT1);
|
||||
break;
|
||||
case IL_DXT5:
|
||||
compressionOptions.setFormat(Format_DXT5);
|
||||
break;
|
||||
default: // Does not support DXT2 or DXT4.
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
break;
|
||||
}
|
||||
|
||||
Compressor compressor;
|
||||
compressor.process(inputOptions, compressionOptions, outputOptions);
|
||||
|
||||
return itellw() - FilePos; // Return the number of characters written.
|
||||
}
|
||||
|
||||
#else
|
||||
// Let's have this so that the function is always created and exported, even if it does nothing.
|
||||
ILAPI ILubyte* ILAPIENTRY ilNVidiaCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat, ILuint *DxtSize)
|
||||
{
|
||||
//@TODO: Do we need to set an error message?
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif//IL_NO_DXTC_NVIDIA
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,207 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_pcd.c
|
||||
//
|
||||
// Description: Reads from a Kodak PhotoCD (.pcd) file.
|
||||
// Note: The code here is sloppy - I had to convert it from Pascal,
|
||||
// which I've never even attempted to read before...enjoy! =)
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_PCD
|
||||
#include "il_manip.h"
|
||||
|
||||
|
||||
ILboolean iLoadPcdInternal(void);
|
||||
|
||||
//! Reads a .pcd file
|
||||
ILboolean ilLoadPcd(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PcdFile;
|
||||
ILboolean bPcd = IL_FALSE;
|
||||
|
||||
PcdFile = iopenr(FileName);
|
||||
if (PcdFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPcd;
|
||||
}
|
||||
|
||||
bPcd = ilLoadPcdF(PcdFile);
|
||||
icloser(PcdFile);
|
||||
|
||||
return bPcd;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .pcd file
|
||||
ILboolean ilLoadPcdF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadPcdInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a .pcd file
|
||||
ILboolean ilLoadPcdL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadPcdInternal();
|
||||
}
|
||||
|
||||
|
||||
void YCbCr2RGB(ILubyte Y, ILubyte Cb, ILubyte Cr, ILubyte *r, ILubyte *g, ILubyte *b)
|
||||
{
|
||||
static const ILdouble c11 = 0.0054980*256;
|
||||
static const ILdouble c12 = 0.0000000*256;
|
||||
static const ILdouble c13 = 0.0051681*256;
|
||||
static const ILdouble c21 = 0.0054980*256;
|
||||
static const ILdouble c22 =-0.0015446*256;
|
||||
static const ILdouble c23 =-0.0026325*256;
|
||||
static const ILdouble c31 = 0.0054980*256;
|
||||
static const ILdouble c32 = 0.0079533*256;
|
||||
static const ILdouble c33 = 0.0000000*256;
|
||||
ILint r1, g1, b1;
|
||||
|
||||
r1 = (ILint)(c11*Y + c12*(Cb-156) + c13*(Cr-137));
|
||||
g1 = (ILint)(c21*Y + c22*(Cb-156) + c23*(Cr-137));
|
||||
b1 = (ILint)(c31*Y + c32*(Cb-156) + c33*(Cr-137));
|
||||
|
||||
if (r1 < 0)
|
||||
*r = 0;
|
||||
else if (r1 > 255)
|
||||
*r = 255;
|
||||
else
|
||||
*r = r1;
|
||||
|
||||
if (g1 < 0)
|
||||
*g = 0;
|
||||
else if (g1 > 255)
|
||||
*g = 255;
|
||||
else
|
||||
*g = g1;
|
||||
|
||||
if (b1 < 0)
|
||||
*b = 0;
|
||||
else if (b1 > 255)
|
||||
*b = 255;
|
||||
else
|
||||
*b = b1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadPcdInternal()
|
||||
{
|
||||
ILubyte VertOrientation;
|
||||
ILuint Width, Height, i, Total, x, CurPos = 0;
|
||||
ILubyte *Y1=NULL, *Y2=NULL, *CbCr=NULL, r = 0, g = 0, b = 0;
|
||||
ILuint PicNum;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iseek(72, IL_SEEK_CUR);
|
||||
if (iread(&VertOrientation, 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
|
||||
iseek(-72, IL_SEEK_CUR); // Can't rewind
|
||||
|
||||
PicNum = iGetInt(IL_PCD_PICNUM);
|
||||
|
||||
switch (PicNum)
|
||||
{
|
||||
case 0:
|
||||
iseek(0x02000, IL_SEEK_CUR);
|
||||
Width = 192;
|
||||
Height = 128;
|
||||
break;
|
||||
case 1:
|
||||
iseek(0x0b800, IL_SEEK_CUR);
|
||||
Width = 384;
|
||||
Height = 256;
|
||||
break;
|
||||
case 2:
|
||||
iseek(0x30000, IL_SEEK_CUR);
|
||||
Width = 768;
|
||||
Height = 512;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (itell() == IL_EOF) // Supposed to have data here.
|
||||
return IL_FALSE;
|
||||
|
||||
Y1 = (ILubyte*)ialloc(Width);
|
||||
Y2 = (ILubyte*)ialloc(Width);
|
||||
CbCr = (ILubyte*)ialloc(Width);
|
||||
if (Y1 == NULL || Y2 == NULL || CbCr == NULL) {
|
||||
ifree(Y1);
|
||||
ifree(Y2);
|
||||
ifree(CbCr);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!ilTexImage(Width, Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
|
||||
Total = Height >> 1;
|
||||
for (i = 0; i < Total; i++) {
|
||||
iread(Y1, 1, Width);
|
||||
iread(Y2, 1, Width);
|
||||
if (iread(CbCr, 1, Width) != Width) { // Only really need to check the last one.
|
||||
ifree(Y1);
|
||||
ifree(Y2);
|
||||
ifree(CbCr);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
for (x = 0; x < Width; x++) {
|
||||
YCbCr2RGB(Y1[x], CbCr[x / 2], CbCr[(Width / 2) + (x / 2)], &r, &g, &b);
|
||||
iCurImage->Data[CurPos++] = r;
|
||||
iCurImage->Data[CurPos++] = g;
|
||||
iCurImage->Data[CurPos++] = b;
|
||||
}
|
||||
|
||||
for (x = 0; x < Width; x++) {
|
||||
YCbCr2RGB(Y2[x], CbCr[x / 2], CbCr[(Width / 2) + (x / 2)], &r, &g, &b);
|
||||
iCurImage->Data[CurPos++] = r;
|
||||
iCurImage->Data[CurPos++] = g;
|
||||
iCurImage->Data[CurPos++] = b;
|
||||
}
|
||||
}
|
||||
|
||||
ifree(Y1);
|
||||
ifree(Y2);
|
||||
ifree(CbCr);
|
||||
|
||||
// Not sure how it is...the documentation is hard to understand
|
||||
if ((VertOrientation & 0x3F) != 8)
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
else
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_PCD
|
||||
@@ -0,0 +1,740 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_pcx.c
|
||||
//
|
||||
// Description: Reads and writes from/to a .pcx file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_PCX
|
||||
#include "il_pcx.h"
|
||||
#include "il_manip.h"
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid .pcx file.
|
||||
ILboolean ilIsValidPcx(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PcxFile;
|
||||
ILboolean bPcx = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("pcx"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bPcx;
|
||||
}
|
||||
|
||||
PcxFile = iopenr(FileName);
|
||||
if (PcxFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPcx;
|
||||
}
|
||||
|
||||
bPcx = ilIsValidPcxF(PcxFile);
|
||||
icloser(PcxFile);
|
||||
|
||||
return bPcx;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid .pcx file at the current position.
|
||||
ILboolean ilIsValidPcxF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidPcx();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid .pcx lump.
|
||||
ILboolean ilIsValidPcxL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidPcx();
|
||||
}
|
||||
|
||||
|
||||
// Internal function obtain the .pcx header from the current file.
|
||||
ILboolean iGetPcxHead(PCXHEAD *Head)
|
||||
{
|
||||
Head->Manufacturer = igetc();
|
||||
Head->Version = igetc();
|
||||
Head->Encoding = igetc();
|
||||
Head->Bpp = igetc();
|
||||
Head->Xmin = GetLittleUShort();
|
||||
Head->Ymin = GetLittleUShort();
|
||||
Head->Xmax = GetLittleUShort();
|
||||
Head->Ymax = GetLittleUShort();
|
||||
Head->HDpi = GetLittleUShort();
|
||||
Head->VDpi = GetLittleUShort();
|
||||
iread(Head->ColMap, 1, 48);
|
||||
Head->Reserved = igetc();
|
||||
Head->NumPlanes = igetc();
|
||||
Head->Bps = GetLittleUShort();
|
||||
Head->PaletteInfo = GetLittleUShort();
|
||||
Head->HScreenSize = GetLittleUShort();
|
||||
Head->VScreenSize = GetLittleUShort();
|
||||
iread(Head->Filler, 1, 54);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidPcx()
|
||||
{
|
||||
PCXHEAD Head;
|
||||
|
||||
if (!iGetPcxHead(&Head))
|
||||
return IL_FALSE;
|
||||
iseek(-(ILint)sizeof(PCXHEAD), IL_SEEK_CUR);
|
||||
|
||||
return iCheckPcx(&Head);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid .pcx header.
|
||||
// Should we also do a check on Header->Bpp?
|
||||
ILboolean iCheckPcx(PCXHEAD *Header)
|
||||
{
|
||||
ILuint Test;
|
||||
|
||||
// Got rid of the Reserved check, because I've seen some .pcx files with invalid values in it.
|
||||
if (Header->Manufacturer != 10 || Header->Encoding != 1/* || Header->Reserved != 0*/)
|
||||
return IL_FALSE;
|
||||
|
||||
// Try to support all pcx versions, as they only differ in allowed formats...
|
||||
// Let's hope it works.
|
||||
if(Header->Version != 5 && Header->Version != 0 && Header->Version != 2 &&
|
||||
Header->VDpi != 3 && Header->VDpi != 4)
|
||||
return IL_FALSE;
|
||||
|
||||
// See if the padding size is correct
|
||||
Test = Header->Xmax - Header->Xmin + 1;
|
||||
if (Header->Bpp >= 8) {
|
||||
if (Test & 1) {
|
||||
if (Header->Bps != Test + 1)
|
||||
return IL_FALSE;
|
||||
}
|
||||
else {
|
||||
if (Header->Bps != Test) // No padding
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* for (i = 0; i < 54; i++) { useless check
|
||||
if (Header->Filler[i] != 0)
|
||||
return IL_FALSE;
|
||||
} */
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a .pcx file
|
||||
ILboolean ilLoadPcx(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PcxFile;
|
||||
ILboolean bPcx = IL_FALSE;
|
||||
|
||||
PcxFile = iopenr(FileName);
|
||||
if (PcxFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPcx;
|
||||
}
|
||||
|
||||
bPcx = ilLoadPcxF(PcxFile);
|
||||
icloser(PcxFile);
|
||||
|
||||
return bPcx;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .pcx file
|
||||
ILboolean ilLoadPcxF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadPcxInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a .pcx
|
||||
ILboolean ilLoadPcxL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadPcxInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the .pcx.
|
||||
ILboolean iLoadPcxInternal()
|
||||
{
|
||||
PCXHEAD Header;
|
||||
ILboolean bPcx = IL_FALSE;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return bPcx;
|
||||
}
|
||||
|
||||
if (!iGetPcxHead(&Header))
|
||||
return IL_FALSE;
|
||||
if (!iCheckPcx(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
bPcx = iUncompressPcx(&Header);
|
||||
|
||||
if (!bPcx)
|
||||
return IL_FALSE;
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
// Internal function to uncompress the .pcx (all .pcx files are rle compressed)
|
||||
ILboolean iUncompressPcx(PCXHEAD *Header)
|
||||
{
|
||||
//changed decompression loop 2003-09-01
|
||||
//From the pcx spec: "There should always
|
||||
//be a decoding break at the end of each scan line.
|
||||
//But there will not be a decoding break at the end of
|
||||
//each plane within each scan line."
|
||||
//This is now handled correctly (hopefully ;) )
|
||||
|
||||
ILubyte ByteHead, Colour, *ScanLine /* For all planes */;
|
||||
ILuint ScanLineSize;
|
||||
ILuint c, i, x, y;
|
||||
|
||||
if (Header->Bpp < 8) {
|
||||
/*ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;*/
|
||||
return iUncompressSmall(Header);
|
||||
}
|
||||
|
||||
if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 0, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
switch (iCurImage->Bpp)
|
||||
{
|
||||
case 1:
|
||||
iCurImage->Format = IL_COLOUR_INDEX;
|
||||
iCurImage->Pal.PalType = IL_PAL_RGB24;
|
||||
iCurImage->Pal.PalSize = 256 * 3; // Need to find out for sure...
|
||||
iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
|
||||
if (iCurImage->Pal.Palette == NULL) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
//case 2: // No 16-bit images in the pcx format!
|
||||
case 3:
|
||||
iCurImage->Format = IL_RGB;
|
||||
iCurImage->Pal.Palette = NULL;
|
||||
iCurImage->Pal.PalSize = 0;
|
||||
iCurImage->Pal.PalType = IL_PAL_NONE;
|
||||
break;
|
||||
case 4:
|
||||
iCurImage->Format = IL_RGBA;
|
||||
iCurImage->Pal.Palette = NULL;
|
||||
iCurImage->Pal.PalSize = 0;
|
||||
iCurImage->Pal.PalType = IL_PAL_NONE;
|
||||
break;
|
||||
|
||||
default:
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
ScanLineSize = iCurImage->Bpp*Header->Bps;
|
||||
ScanLine = (ILubyte*)ialloc(ScanLineSize);
|
||||
if (ScanLine == NULL) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
//changed 2003-09-01
|
||||
//having the decoding code twice is error-prone,
|
||||
//so I made iUnCache() smart enough to grasp
|
||||
//if iPreCache() wasn't called and call it
|
||||
//anyways.
|
||||
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
|
||||
iPreCache(iCurImage->SizeOfData / 4);
|
||||
|
||||
for (y = 0; y < iCurImage->Height; y++) {
|
||||
x = 0;
|
||||
//read scanline
|
||||
while (x < ScanLineSize) {
|
||||
if (iread(&ByteHead, 1, 1) != 1) {
|
||||
iUnCache();
|
||||
goto file_read_error;
|
||||
}
|
||||
if ((ByteHead & 0xC0) == 0xC0) {
|
||||
ByteHead &= 0x3F;
|
||||
if (iread(&Colour, 1, 1) != 1) {
|
||||
iUnCache();
|
||||
goto file_read_error;
|
||||
}
|
||||
if (x + ByteHead > ScanLineSize) {
|
||||
iUnCache();
|
||||
goto file_read_error;
|
||||
}
|
||||
for (i = 0; i < ByteHead; i++) {
|
||||
ScanLine[x++] = Colour;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ScanLine[x++] = ByteHead;
|
||||
}
|
||||
}
|
||||
|
||||
//convert plane-separated scanline into index, rgb or rgba pixels.
|
||||
//there might be a padding byte at the end of each scanline...
|
||||
for (x = 0; x < iCurImage->Width; x++) {
|
||||
for(c = 0; c < iCurImage->Bpp; c++) {
|
||||
iCurImage->Data[y * iCurImage->Bps + x * iCurImage->Bpp + c] =
|
||||
ScanLine[x + c * Header->Bps];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iUnCache();
|
||||
|
||||
// Read in the palette
|
||||
if (Header->Version == 5 && iCurImage->Bpp == 1) {
|
||||
x = itell();
|
||||
if (iread(&ByteHead, 1, 1) == 0) { // If true, assume that we have a luminance image.
|
||||
ilGetError(); // Get rid of the IL_FILE_READ_ERROR.
|
||||
iCurImage->Format = IL_LUMINANCE;
|
||||
if (iCurImage->Pal.Palette)
|
||||
ifree(iCurImage->Pal.Palette);
|
||||
iCurImage->Pal.PalSize = 0;
|
||||
iCurImage->Pal.PalType = IL_PAL_NONE;
|
||||
}
|
||||
else {
|
||||
if (ByteHead != 12) // Some Quake2 .pcx files don't have this byte for some reason.
|
||||
iseek(-1, IL_SEEK_CUR);
|
||||
if (iread(iCurImage->Pal.Palette, 1, iCurImage->Pal.PalSize) != iCurImage->Pal.PalSize)
|
||||
goto file_read_error;
|
||||
}
|
||||
}
|
||||
|
||||
ifree(ScanLine);
|
||||
|
||||
return IL_TRUE;
|
||||
|
||||
file_read_error:
|
||||
ifree(ScanLine);
|
||||
|
||||
//added 2003-09-01
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean iUncompressSmall(PCXHEAD *Header)
|
||||
{
|
||||
ILuint i = 0, j, k, c, d, x, y, Bps;
|
||||
ILubyte HeadByte, Colour, Data = 0, *ScanLine;
|
||||
|
||||
if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, 1, 0, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
switch (Header->NumPlanes)
|
||||
{
|
||||
case 1:
|
||||
iCurImage->Format = IL_LUMINANCE;
|
||||
break;
|
||||
case 4:
|
||||
iCurImage->Format = IL_COLOUR_INDEX;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (Header->NumPlanes == 1 && Header->Bpp == 1) {
|
||||
for (j = 0; j < iCurImage->Height; j++) {
|
||||
i = 0; //number of written pixels
|
||||
while (i < iCurImage->Width) {
|
||||
if (iread(&HeadByte, 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
if (HeadByte >= 192) {
|
||||
HeadByte -= 192;
|
||||
if (iread(&Data, 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
|
||||
for (c = 0; c < HeadByte; c++) {
|
||||
k = 128;
|
||||
for (d = 0; d < 8 && i < iCurImage->Width; d++) {
|
||||
iCurImage->Data[j * iCurImage->Width + i++] = ((Data & k) != 0 ? 255 : 0);
|
||||
k >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
k = 128;
|
||||
for (c = 0; c < 8 && i < iCurImage->Width; c++) {
|
||||
iCurImage->Data[j * iCurImage->Width + i++] = ((HeadByte & k) != 0 ? 255 : 0);
|
||||
k >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if(Data != 0)
|
||||
//changed 2003-09-01:
|
||||
//There has to be an even number of bytes per line in a pcx.
|
||||
//One byte can hold up to 8 bits, so Width/8 bytes
|
||||
//are needed to hold a 1 bit per pixel image line.
|
||||
//If Width/8 is even no padding is needed,
|
||||
//one pad byte has to be read otherwise.
|
||||
//(let's hope the above is true ;-))
|
||||
if(!((iCurImage->Width >> 3) & 0x1))
|
||||
igetc(); // Skip pad byte
|
||||
}
|
||||
}
|
||||
else if (Header->NumPlanes == 4 && Header->Bpp == 1){ // 4-bit images
|
||||
//changed decoding 2003-09-10 (was buggy)...could need a speedup
|
||||
|
||||
Bps = Header->Bps * Header->NumPlanes * 8;
|
||||
iCurImage->Pal.Palette = (ILubyte*)ialloc(16 * 3); // Size of palette always (48 bytes).
|
||||
ScanLine = (ILubyte*)ialloc(Bps);
|
||||
if (iCurImage->Pal.Palette == NULL || ScanLine == NULL) {
|
||||
ifree(ScanLine);
|
||||
ifree(iCurImage->Pal.Palette);
|
||||
return IL_FALSE;
|
||||
}
|
||||
memcpy(iCurImage->Pal.Palette, Header->ColMap, 16 * 3);
|
||||
iCurImage->Pal.PalSize = 16 * 3;
|
||||
iCurImage->Pal.PalType = IL_PAL_RGB24;
|
||||
|
||||
memset(iCurImage->Data, 0, iCurImage->SizeOfData);
|
||||
|
||||
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
|
||||
iPreCache(iCurImage->SizeOfData / 4);
|
||||
for (y = 0; y < iCurImage->Height; y++) {
|
||||
x = 0;
|
||||
while (x < Bps) {
|
||||
if (iread(&HeadByte, 1, 1) != 1) {
|
||||
iUnCache();
|
||||
ifree(ScanLine);
|
||||
return IL_FALSE;
|
||||
}
|
||||
if ((HeadByte & 0xC0) == 0xC0) {
|
||||
HeadByte &= 0x3F;
|
||||
if (iread(&Colour, 1, 1) != 1) {
|
||||
iUnCache();
|
||||
ifree(ScanLine);
|
||||
return IL_FALSE;
|
||||
}
|
||||
for (i = 0; i < HeadByte; i++) {
|
||||
k = 128;
|
||||
for (j = 0; j < 8 && x < Bps; j++) {
|
||||
ScanLine[x++] = (Colour & k)?1:0;
|
||||
k >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
k = 128;
|
||||
for (j = 0; j < 8 && x < Bps; j++) {
|
||||
ScanLine[x++] = (HeadByte & k)?1:0;
|
||||
k >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < iCurImage->Width; x++) { // 'Cleverly' ignores the pad bytes. ;)
|
||||
for(c = 0; c < Header->NumPlanes; c++)
|
||||
iCurImage->Data[y * iCurImage->Width + x] |= ScanLine[x + c*Header->Bps*8] << c;
|
||||
}
|
||||
}
|
||||
iUnCache();
|
||||
ifree(ScanLine);
|
||||
}
|
||||
else {
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a .pcx file
|
||||
ILboolean ilSavePcx(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE PcxFile;
|
||||
ILuint PcxSize;
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PcxFile = iopenw(FileName);
|
||||
if (PcxFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
PcxSize = ilSavePcxF(PcxFile);
|
||||
iclosew(PcxFile);
|
||||
|
||||
if (PcxSize == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a .pcx to an already-opened file
|
||||
ILuint ilSavePcxF(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputFile(File);
|
||||
Pos = itellw();
|
||||
if (iSavePcxInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes a .pcx to a memory "lump"
|
||||
ILuint ilSavePcxL(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputLump(Lump, Size);
|
||||
Pos = itellw();
|
||||
if (iSavePcxInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to save the .pcx.
|
||||
ILboolean iSavePcxInternal()
|
||||
{
|
||||
ILuint i, c, PalSize;
|
||||
ILpal *TempPal;
|
||||
ILimage *TempImage = iCurImage;
|
||||
ILubyte *TempData;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
switch (iCurImage->Format)
|
||||
{
|
||||
case IL_LUMINANCE:
|
||||
TempImage = iConvertImage(iCurImage, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE);
|
||||
if (TempImage == NULL)
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case IL_BGR:
|
||||
TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
|
||||
if (TempImage == NULL)
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case IL_BGRA:
|
||||
TempImage = iConvertImage(iCurImage, IL_RGBA, IL_UNSIGNED_BYTE);
|
||||
if (TempImage == NULL)
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (iCurImage->Bpc > 1) {
|
||||
TempImage = iConvertImage(iCurImage, iCurImage->Format, IL_UNSIGNED_BYTE);
|
||||
if (TempImage == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
|
||||
TempData = iGetFlipped(TempImage);
|
||||
if (TempData == NULL) {
|
||||
if (TempImage != iCurImage) {
|
||||
ilCloseImage(TempImage);
|
||||
}
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
TempData = TempImage->Data;
|
||||
}
|
||||
|
||||
|
||||
iputc(0xA); // Manufacturer - always 10
|
||||
iputc(0x5); // Version Number - always 5
|
||||
iputc(0x1); // Encoding - always 1
|
||||
iputc(0x8); // Bits per channel
|
||||
SaveLittleUShort(0); // X Minimum
|
||||
SaveLittleUShort(0); // Y Minimum
|
||||
SaveLittleUShort((ILushort)(iCurImage->Width - 1));
|
||||
SaveLittleUShort((ILushort)(iCurImage->Height - 1));
|
||||
SaveLittleUShort(0);
|
||||
SaveLittleUShort(0);
|
||||
|
||||
// Useless palette info?
|
||||
for (i = 0; i < 48; i++) {
|
||||
iputc(0);
|
||||
}
|
||||
iputc(0x0); // Reserved - always 0
|
||||
|
||||
iputc(iCurImage->Bpp); // Number of planes - only 1 is supported right now
|
||||
|
||||
SaveLittleUShort((ILushort)(iCurImage->Width & 1 ? iCurImage->Width + 1 : iCurImage->Width)); // Bps
|
||||
SaveLittleUShort(0x1); // Palette type - ignored?
|
||||
|
||||
// Mainly filler info
|
||||
for (i = 0; i < 58; i++) {
|
||||
iputc(0x0);
|
||||
}
|
||||
|
||||
// Output data
|
||||
for (i = 0; i < TempImage->Height; i++) {
|
||||
for (c = 0; c < TempImage->Bpp; c++) {
|
||||
encLine(TempData + TempImage->Bps * i + c, TempImage->Width, (ILubyte)(TempImage->Bpp - 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Automatically assuming we have a palette...dangerous!
|
||||
// Also assuming 3 bpp palette
|
||||
iputc(0xC); // Pad byte must have this value
|
||||
|
||||
// If the current image has a palette, take care of it
|
||||
if (TempImage->Format == IL_COLOUR_INDEX) {
|
||||
// If the palette in .pcx format, write it directly
|
||||
if (TempImage->Pal.PalType == IL_PAL_RGB24) {
|
||||
iwrite(TempImage->Pal.Palette, 1, TempImage->Pal.PalSize);
|
||||
}
|
||||
else {
|
||||
TempPal = iConvertPal(&TempImage->Pal, IL_PAL_RGB24);
|
||||
if (TempPal == NULL) {
|
||||
if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
|
||||
ifree(TempData);
|
||||
if (TempImage != iCurImage)
|
||||
ilCloseImage(TempImage);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iwrite(TempPal->Palette, 1, TempPal->PalSize);
|
||||
ifree(TempPal->Palette);
|
||||
ifree(TempPal);
|
||||
}
|
||||
}
|
||||
|
||||
// If the palette is not all 256 colours, we have to pad it.
|
||||
PalSize = 768 - iCurImage->Pal.PalSize;
|
||||
for (i = 0; i < PalSize; i++) {
|
||||
iputc(0x0);
|
||||
}
|
||||
|
||||
if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
|
||||
ifree(TempData);
|
||||
if (TempImage != iCurImage)
|
||||
ilCloseImage(TempImage);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Routine used from ZSoft's pcx documentation
|
||||
ILuint encput(ILubyte byt, ILubyte cnt)
|
||||
{
|
||||
if (cnt) {
|
||||
if ((cnt == 1) && (0xC0 != (0xC0 & byt))) {
|
||||
if (IL_EOF == iputc(byt))
|
||||
return(0); /* disk write error (probably full) */
|
||||
return(1);
|
||||
}
|
||||
else {
|
||||
if (IL_EOF == iputc((ILubyte)((ILuint)0xC0 | cnt)))
|
||||
return (0); /* disk write error */
|
||||
if (IL_EOF == iputc(byt))
|
||||
return (0); /* disk write error */
|
||||
return (2);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
// This subroutine encodes one scanline and writes it to a file.
|
||||
// It returns number of bytes written into outBuff, 0 if failed.
|
||||
ILuint encLine(ILubyte *inBuff, ILint inLen, ILubyte Stride)
|
||||
{
|
||||
ILubyte _this, last;
|
||||
ILint srcIndex, i;
|
||||
ILint total;
|
||||
ILubyte runCount; // max single runlength is 63
|
||||
total = 0;
|
||||
runCount = 1;
|
||||
last = *(inBuff);
|
||||
|
||||
// Find the pixel dimensions of the image by calculating
|
||||
//[XSIZE = Xmax - Xmin + 1] and [YSIZE = Ymax - Ymin + 1].
|
||||
//Then calculate how many bytes are in a "run"
|
||||
|
||||
for (srcIndex = 1; srcIndex < inLen; srcIndex++) {
|
||||
inBuff += Stride;
|
||||
_this = *(++inBuff);
|
||||
if (_this == last) { // There is a "run" in the data, encode it
|
||||
runCount++;
|
||||
if (runCount == 63) {
|
||||
if (! (i = encput(last, runCount)))
|
||||
return (0);
|
||||
total += i;
|
||||
runCount = 0;
|
||||
}
|
||||
}
|
||||
else { // No "run" - _this != last
|
||||
if (runCount) {
|
||||
if (! (i = encput(last, runCount)))
|
||||
return(0);
|
||||
total += i;
|
||||
}
|
||||
last = _this;
|
||||
runCount = 1;
|
||||
}
|
||||
} // endloop
|
||||
|
||||
if (runCount) { // finish up
|
||||
if (! (i = encput(last, runCount)))
|
||||
return (0);
|
||||
if (inLen % 2)
|
||||
iputc(0);
|
||||
return (total + i);
|
||||
}
|
||||
else {
|
||||
if (inLen % 2)
|
||||
iputc(0);
|
||||
}
|
||||
|
||||
return (total);
|
||||
}
|
||||
|
||||
#endif//IL_NO_PCX
|
||||
@@ -0,0 +1,426 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_pic.c
|
||||
//
|
||||
// Description: Softimage Pic (.pic) functions
|
||||
// Lots of this code is taken from Paul Bourke's Softimage Pic code at
|
||||
// http://local.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_PIC
|
||||
#include "il_pic.h"
|
||||
#include "il_manip.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid .pic file.
|
||||
ILboolean ilIsValidPic(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PicFile;
|
||||
ILboolean bPic = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("pic"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bPic;
|
||||
}
|
||||
|
||||
PicFile = iopenr(FileName);
|
||||
if (PicFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPic;
|
||||
}
|
||||
|
||||
bPic = ilIsValidPicF(PicFile);
|
||||
icloser(PicFile);
|
||||
|
||||
return bPic;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid .pic file at the current position.
|
||||
ILboolean ilIsValidPicF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidPic();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid .pic lump.
|
||||
ILboolean ilIsValidPicL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidPic();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the .pic header from the current file.
|
||||
ILboolean iGetPicHead(PIC_HEAD *Header)
|
||||
{
|
||||
Header->Magic = GetBigInt();
|
||||
Header->Version = GetBigFloat();
|
||||
iread(Header->Comment, 1, 80);
|
||||
iread(Header->Id, 1, 4);
|
||||
Header->Width = GetBigShort();
|
||||
Header->Height = GetBigShort();
|
||||
Header->Ratio = GetBigFloat();
|
||||
Header->Fields = GetBigShort();
|
||||
Header->Padding = GetBigShort();
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidPic()
|
||||
{
|
||||
PIC_HEAD Head;
|
||||
|
||||
if (!iGetPicHead(&Head))
|
||||
return IL_FALSE;
|
||||
iseek(-(ILint)sizeof(PIC_HEAD), IL_SEEK_CUR); // Go ahead and restore to previous state
|
||||
|
||||
return iCheckPic(&Head);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the header is a valid .pic header.
|
||||
ILboolean iCheckPic(PIC_HEAD *Header)
|
||||
{
|
||||
if (Header->Magic != 0x5380F634)
|
||||
return IL_FALSE;
|
||||
if (strncmp((const char*)Header->Id, "PICT", 4))
|
||||
return IL_FALSE;
|
||||
if (Header->Width == 0)
|
||||
return IL_FALSE;
|
||||
if (Header->Height == 0)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a .pic file
|
||||
ILboolean ilLoadPic(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PicFile;
|
||||
ILboolean bPic = IL_FALSE;
|
||||
|
||||
PicFile = iopenr(FileName);
|
||||
if (PicFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPic;
|
||||
}
|
||||
|
||||
bPic = ilLoadPicF(PicFile);
|
||||
icloser(PicFile);
|
||||
|
||||
return bPic;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .pic file
|
||||
ILboolean ilLoadPicF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadPicInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a .pic
|
||||
ILboolean ilLoadPicL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadPicInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the .pic
|
||||
ILboolean iLoadPicInternal()
|
||||
{
|
||||
ILuint Alpha = IL_FALSE;
|
||||
ILubyte Chained;
|
||||
CHANNEL *Channel = NULL, *Channels = NULL, *Prev;
|
||||
PIC_HEAD Header;
|
||||
ILboolean Read;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!iGetPicHead(&Header))
|
||||
return IL_FALSE;
|
||||
if (!iCheckPic(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Read channels
|
||||
do {
|
||||
if (Channel == NULL) {
|
||||
Channel = Channels = (CHANNEL*)ialloc(sizeof(CHANNEL));
|
||||
if (Channels == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
else {
|
||||
Channels->Next = (CHANNEL*)ialloc(sizeof(CHANNEL));
|
||||
if (Channels->Next == NULL) {
|
||||
// Clean up the list before erroring out.
|
||||
while (Channel) {
|
||||
Prev = Channel;
|
||||
Channel = (CHANNEL*)Channel->Next;
|
||||
ifree(Prev);
|
||||
}
|
||||
return IL_FALSE;
|
||||
}
|
||||
Channels = (CHANNEL*)Channels->Next;
|
||||
}
|
||||
Channels->Next = NULL;
|
||||
|
||||
Chained = igetc();
|
||||
Channels->Size = igetc();
|
||||
Channels->Type = igetc();
|
||||
Channels->Chan = igetc();
|
||||
if (ieof()) {
|
||||
Read = IL_FALSE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// See if we have an alpha channel in there
|
||||
if (Channels->Chan & PIC_ALPHA_CHANNEL)
|
||||
Alpha = IL_TRUE;
|
||||
|
||||
} while (Chained);
|
||||
|
||||
if (Alpha) { // Has an alpha channel
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
|
||||
Read = IL_FALSE;
|
||||
goto finish; // Have to destroy Channels first.
|
||||
}
|
||||
}
|
||||
else { // No alpha channel
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
|
||||
Read = IL_FALSE;
|
||||
goto finish; // Have to destroy Channels first.
|
||||
}
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
|
||||
Read = readScanlines((ILuint*)iCurImage->Data, Header.Width, Header.Height, Channel, Alpha);
|
||||
|
||||
finish:
|
||||
// Destroy channels
|
||||
while (Channel) {
|
||||
Prev = Channel;
|
||||
Channel = (CHANNEL*)Channel->Next;
|
||||
ifree(Prev);
|
||||
}
|
||||
|
||||
if (Read == IL_FALSE)
|
||||
return IL_FALSE;
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
ILboolean readScanlines(ILuint *image, ILint width, ILint height, CHANNEL *channel, ILuint alpha)
|
||||
{
|
||||
ILint i;
|
||||
ILuint *scan;
|
||||
|
||||
(void)alpha;
|
||||
|
||||
for (i = height - 1; i >= 0; i--) {
|
||||
scan = image + i * width;
|
||||
|
||||
if (!readScanline((ILubyte *)scan, width, channel, alpha ? 4 : 3)) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILuint readScanline(ILubyte *scan, ILint width, CHANNEL *channel, ILint bytes)
|
||||
{
|
||||
ILint noCol;
|
||||
ILint off[4];
|
||||
ILuint status=0;
|
||||
|
||||
while (channel) {
|
||||
noCol = 0;
|
||||
if(channel->Chan & PIC_RED_CHANNEL) {
|
||||
off[noCol] = 0;
|
||||
noCol++;
|
||||
}
|
||||
if(channel->Chan & PIC_GREEN_CHANNEL) {
|
||||
off[noCol] = 1;
|
||||
noCol++;
|
||||
}
|
||||
if(channel->Chan & PIC_BLUE_CHANNEL) {
|
||||
off[noCol] = 2;
|
||||
noCol++;
|
||||
}
|
||||
if(channel->Chan & PIC_ALPHA_CHANNEL) {
|
||||
off[noCol] = 3;
|
||||
noCol++;
|
||||
//@TODO: Find out if this is possible.
|
||||
if (bytes == 3) // Alpha channel in a 24-bit image. Do not know what to do with this.
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(channel->Type & 0x0F)
|
||||
{
|
||||
case PIC_UNCOMPRESSED:
|
||||
status = channelReadRaw(scan, width, noCol, off, bytes);
|
||||
break;
|
||||
case PIC_PURE_RUN_LENGTH:
|
||||
status = channelReadPure(scan, width, noCol, off, bytes);
|
||||
break;
|
||||
case PIC_MIXED_RUN_LENGTH:
|
||||
status = channelReadMixed(scan, width, noCol, off, bytes);
|
||||
break;
|
||||
}
|
||||
if (!status)
|
||||
break;
|
||||
|
||||
channel = (CHANNEL*)channel->Next;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
ILboolean channelReadRaw(ILubyte *scan, ILint width, ILint noCol, ILint *off, ILint bytes)
|
||||
{
|
||||
ILint i, j;
|
||||
|
||||
for (i = 0; i < width; i++) {
|
||||
if (ieof())
|
||||
return IL_FALSE;
|
||||
for (j = 0; j < noCol; j++)
|
||||
if (iread(&scan[off[j]], 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
scan += bytes;
|
||||
}
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean channelReadPure(ILubyte *scan, ILint width, ILint noCol, ILint *off, ILint bytes)
|
||||
{
|
||||
ILubyte col[4];
|
||||
ILint count;
|
||||
int i, j, k;
|
||||
|
||||
for (i = width; i > 0; ) {
|
||||
count = igetc();
|
||||
if (count == IL_EOF)
|
||||
return IL_FALSE;
|
||||
if (count > width)
|
||||
count = width;
|
||||
i -= count;
|
||||
|
||||
if (ieof())
|
||||
return IL_FALSE;
|
||||
|
||||
for (j = 0; j < noCol; j++)
|
||||
if (iread(&col[j], 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
|
||||
for (k = 0; k < count; k++, scan += bytes) {
|
||||
for(j = 0; j < noCol; j++)
|
||||
scan[off[j] + k] = col[j];
|
||||
}
|
||||
}
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean channelReadMixed(ILubyte *scan, ILint width, ILint noCol, ILint *off, ILint bytes)
|
||||
{
|
||||
ILint count;
|
||||
int i, j, k;
|
||||
ILubyte col[4];
|
||||
|
||||
for(i = 0; i < width; i += count) {
|
||||
if (ieof())
|
||||
return IL_FALSE;
|
||||
|
||||
count = igetc();
|
||||
if (count == IL_EOF)
|
||||
return IL_FALSE;
|
||||
|
||||
if (count >= 128) { // Repeated sequence
|
||||
if (count == 128) { // Long run
|
||||
count = GetBigUShort();
|
||||
if (ieof()) {
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
count -= 127;
|
||||
|
||||
// We've run past...
|
||||
if ((i + count) > width) {
|
||||
//fprintf(stderr, "ERROR: FF_PIC_load(): Overrun scanline (Repeat) [%d + %d > %d] (NC=%d)\n", i, count, width, noCol);
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
for (j = 0; j < noCol; j++)
|
||||
if (iread(&col[j], 1, 1) != 1) {
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
for (k = 0; k < count; k++, scan += bytes) {
|
||||
for (j = 0; j < noCol; j++)
|
||||
scan[off[j]] = col[j];
|
||||
}
|
||||
} else { // Raw sequence
|
||||
count++;
|
||||
if ((i + count) > width) {
|
||||
//fprintf(stderr, "ERROR: FF_PIC_load(): Overrun scanline (Raw) [%d + %d > %d] (NC=%d)\n", i, count, width, noCol);
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
for (k = count; k > 0; k--, scan += bytes) {
|
||||
for (j = 0; j < noCol; j++)
|
||||
if (iread(&scan[off[j]], 1, 1) != 1) {
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_PIC
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_pix.c
|
||||
//
|
||||
// Description: Reads from an Alias | Wavefront .pix file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_PIX
|
||||
#include "il_manip.h"
|
||||
#include "il_endian.h"
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, pix_struct, 1)
|
||||
#endif
|
||||
typedef struct PIXHEAD
|
||||
{
|
||||
ILushort Width;
|
||||
ILushort Height;
|
||||
ILushort OffX;
|
||||
ILushort OffY;
|
||||
ILushort Bpp;
|
||||
} IL_PACKSTRUCT PIXHEAD;
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop, pix_struct)
|
||||
#endif
|
||||
|
||||
ILboolean iCheckPix(PIXHEAD *Header);
|
||||
ILboolean iLoadPixInternal(void);
|
||||
|
||||
|
||||
// Internal function used to get the Pix header from the current file.
|
||||
ILboolean iGetPixHead(PIXHEAD *Header)
|
||||
{
|
||||
Header->Width = GetBigUShort();
|
||||
Header->Height = GetBigUShort();
|
||||
Header->OffX = GetBigUShort();
|
||||
Header->OffY = GetBigUShort();
|
||||
Header->Bpp = GetBigUShort();
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidPix()
|
||||
{
|
||||
PIXHEAD Head;
|
||||
|
||||
if (!iGetPixHead(&Head))
|
||||
return IL_FALSE;
|
||||
iseek(-(ILint)sizeof(PIXHEAD), IL_SEEK_CUR);
|
||||
|
||||
return iCheckPix(&Head);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid Pix header.
|
||||
ILboolean iCheckPix(PIXHEAD *Header)
|
||||
{
|
||||
if (Header->Width == 0 || Header->Height == 0)
|
||||
return IL_FALSE;
|
||||
if (Header->Bpp != 24)
|
||||
return IL_FALSE;
|
||||
//if (Header->OffY != Header->Height)
|
||||
// return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a Pix file
|
||||
ILboolean ilLoadPix(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PixFile;
|
||||
ILboolean bPix = IL_FALSE;
|
||||
|
||||
PixFile = iopenr(FileName);
|
||||
if (PixFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPix;
|
||||
}
|
||||
|
||||
bPix = ilLoadPixF(PixFile);
|
||||
icloser(PixFile);
|
||||
|
||||
return bPix;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened Pix file
|
||||
ILboolean ilLoadPixF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadPixInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a Pix
|
||||
ILboolean ilLoadPixL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadPixInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the Pix.
|
||||
ILboolean iLoadPixInternal()
|
||||
{
|
||||
PIXHEAD Header;
|
||||
ILuint i, j;
|
||||
ILubyte ByteHead, Colour[3];
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!iGetPixHead(&Header))
|
||||
return IL_FALSE;
|
||||
if (!iCheckPix(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
|
||||
for (i = 0; i < iCurImage->SizeOfData; ) {
|
||||
ByteHead = igetc();
|
||||
if (iread(Colour, 1, 3) != 3)
|
||||
return IL_FALSE;
|
||||
for (j = 0; j < ByteHead; j++) {
|
||||
iCurImage->Data[i++] = Colour[0];
|
||||
iCurImage->Data[i++] = Colour[1];
|
||||
iCurImage->Data[i++] = Colour[2];
|
||||
}
|
||||
}
|
||||
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
#endif//IL_NO_PIX
|
||||
@@ -0,0 +1,729 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_png.c
|
||||
//
|
||||
// Description: Portable network graphics file (.png) functions
|
||||
//
|
||||
// 20040223 XIX : now may spit out pngs with a transparent index, this is mostly a hack
|
||||
// but the proper way of doing it would be to change the pal stuff to think in argb rather than rgb
|
||||
// which is something of a bigger job.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Most of the comments are left in this file from libpng's excellent example.c
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_PNG
|
||||
#include <png.h>
|
||||
#include "il_manip.h"
|
||||
#include <stdlib.h>
|
||||
#if PNG_LIBPNG_VER < 10200
|
||||
#warning DevIL was designed with libpng 1.2.0 or higher in mind. Consider upgrading at www.libpng.org.
|
||||
#endif
|
||||
|
||||
#if (defined(_WIN32) || defined(_WIN64)) && defined(IL_USE_PRAGMA_LIBS)
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#ifndef _DEBUG
|
||||
#pragma comment(lib, "libpng.lib")
|
||||
#pragma comment(lib, "zlib.lib")
|
||||
#else
|
||||
#pragma comment(lib, "libpng-d.lib")
|
||||
#pragma comment(lib, "zlib-d.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
ILboolean iIsValidPng(void);
|
||||
ILboolean iLoadPngInternal(void);
|
||||
ILboolean iSavePngInternal(void);
|
||||
|
||||
ILint readpng_init(void);
|
||||
ILboolean readpng_get_image(ILdouble display_exponent);
|
||||
void readpng_cleanup(void);
|
||||
|
||||
png_structp png_ptr = NULL;
|
||||
png_infop info_ptr = NULL;
|
||||
ILint png_color_type;
|
||||
|
||||
#define GAMMA_CORRECTION 1.0 // Doesn't seem to be doing anything...
|
||||
|
||||
|
||||
ILboolean ilIsValidPng(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PngFile;
|
||||
ILboolean bPng = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("png"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bPng;
|
||||
}
|
||||
|
||||
PngFile = iopenr(FileName);
|
||||
if (PngFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPng;
|
||||
}
|
||||
|
||||
bPng = ilIsValidPngF(PngFile);
|
||||
icloser(PngFile);
|
||||
|
||||
return bPng;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ilIsValidPngF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidPng();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ilIsValidPngL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidPng();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iIsValidPng()
|
||||
{
|
||||
ILubyte Signature[8];
|
||||
ILint Read;
|
||||
|
||||
Read = iread(Signature, 1, 8);
|
||||
iseek(-Read, IL_SEEK_CUR);
|
||||
|
||||
return png_check_sig(Signature, 8);
|
||||
}
|
||||
|
||||
|
||||
// Reads a file
|
||||
ILboolean ilLoadPng(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PngFile;
|
||||
ILboolean bPng = IL_FALSE;
|
||||
|
||||
PngFile = iopenr(FileName);
|
||||
if (PngFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPng;
|
||||
}
|
||||
|
||||
bPng = ilLoadPngF(PngFile);
|
||||
icloser(PngFile);
|
||||
|
||||
return bPng;
|
||||
}
|
||||
|
||||
|
||||
// Reads an already-opened file
|
||||
ILboolean ilLoadPngF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadPngInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
// Reads from a memory "lump"
|
||||
ILboolean ilLoadPngL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadPngInternal();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadPngInternal()
|
||||
{
|
||||
png_ptr = NULL;
|
||||
info_ptr = NULL;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (!iIsValidPng()) {
|
||||
ilSetError(IL_INVALID_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (readpng_init())
|
||||
return IL_FALSE;
|
||||
if (!readpng_get_image(GAMMA_CORRECTION))
|
||||
return IL_FALSE;
|
||||
|
||||
readpng_cleanup();
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
static void png_read(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
(void)png_ptr;
|
||||
iread(data, 1, (ILuint)length);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void png_error_func(png_structp png_ptr, png_const_charp message)
|
||||
{
|
||||
ilSetError(IL_LIB_PNG_ERROR);
|
||||
|
||||
/*
|
||||
changed 20040224
|
||||
From the libpng docs:
|
||||
"Errors handled through png_error() are fatal, meaning that png_error()
|
||||
should never return to its caller. Currently, this is handled via
|
||||
setjmp() and longjmp()"
|
||||
*/
|
||||
//return;
|
||||
longjmp(png_jmpbuf(png_ptr), 1);
|
||||
}
|
||||
|
||||
static void png_warn_func(png_structp png_ptr, png_const_charp message)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILint readpng_init()
|
||||
{
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_func, png_warn_func);
|
||||
if (!png_ptr)
|
||||
return 4; /* out of memory */
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) {
|
||||
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||
return 4; /* out of memory */
|
||||
}
|
||||
|
||||
|
||||
/* we could create a second info struct here (end_info), but it's only
|
||||
* useful if we want to keep pre- and post-IDAT chunk info separated
|
||||
* (mainly for PNG-aware image editors and converters) */
|
||||
|
||||
|
||||
/* setjmp() must be called in every function that calls a PNG-reading
|
||||
* libpng function */
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
png_set_read_fn(png_ptr, NULL, png_read);
|
||||
png_set_error_fn(png_ptr, NULL, png_error_func, png_warn_func);
|
||||
|
||||
// png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */
|
||||
|
||||
png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */
|
||||
|
||||
|
||||
/* alternatively, could make separate calls to png_get_image_width(),
|
||||
* etc., but want bit_depth and png_color_type for later [don't care about
|
||||
* compression_type and filter_type => NULLs] */
|
||||
|
||||
/* OK, that's all we need for now; return happy */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* display_exponent == LUT_exponent * CRT_exponent */
|
||||
|
||||
ILboolean readpng_get_image(ILdouble display_exponent)
|
||||
{
|
||||
png_bytepp row_pointers = NULL;
|
||||
png_uint_32 width, height; // Changed the type to fix AMD64 bit problems, thanks to Eric Werness
|
||||
ILdouble screen_gamma = 1.0;
|
||||
ILuint i, channels;
|
||||
ILenum format;
|
||||
png_colorp palette;
|
||||
ILint num_palette, j, bit_depth;
|
||||
#if _WIN32 || DJGPP
|
||||
ILdouble image_gamma;
|
||||
#endif
|
||||
|
||||
/* setjmp() must be called in every function that calls a PNG-reading
|
||||
* libpng function */
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)&width, (png_uint_32*)&height,
|
||||
&bit_depth, &png_color_type, NULL, NULL, NULL);
|
||||
|
||||
// Expand low-bit-depth grayscale images to 8 bits
|
||||
if (png_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
|
||||
png_set_gray_1_2_4_to_8(png_ptr);
|
||||
}
|
||||
|
||||
// Expand RGB images with transparency to full alpha channels
|
||||
// so the data will be available as RGBA quartets.
|
||||
// But don't expand paletted images, since we want alpha palettes!
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) && !(png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)))
|
||||
png_set_tRNS_to_alpha(png_ptr);
|
||||
|
||||
//refresh information (added 20040224)
|
||||
png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)&width, (png_uint_32*)&height,
|
||||
&bit_depth, &png_color_type, NULL, NULL, NULL);
|
||||
|
||||
if (bit_depth < 8) { // Expanded earlier for grayscale, now take care of palette and rgb
|
||||
bit_depth = 8;
|
||||
png_set_packing(png_ptr);
|
||||
}
|
||||
|
||||
// Perform gamma correction.
|
||||
// @TODO: Determine if we should call png_set_gamma if image_gamma is 1.0.
|
||||
#if _WIN32 || DJGPP
|
||||
screen_gamma = 2.2;
|
||||
if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
|
||||
png_set_gamma(png_ptr, screen_gamma, image_gamma);
|
||||
#else
|
||||
screen_gamma = screen_gamma;
|
||||
#endif
|
||||
|
||||
//fix endianess
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
if (bit_depth == 16)
|
||||
png_set_swap(png_ptr);
|
||||
#endif
|
||||
|
||||
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
channels = (ILint)png_get_channels(png_ptr, info_ptr);
|
||||
//added 20040224: update png_color_type so that it has the correct value
|
||||
//in iLoadPngInternal (globals rule...)
|
||||
png_color_type = png_get_color_type(png_ptr, info_ptr);
|
||||
|
||||
//determine internal format
|
||||
switch(png_color_type)
|
||||
{
|
||||
case PNG_COLOR_TYPE_PALETTE:
|
||||
format = IL_COLOUR_INDEX;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_GRAY:
|
||||
format = IL_LUMINANCE;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
||||
format = IL_LUMINANCE_ALPHA;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
format = IL_RGB;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
format = IL_RGBA;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!ilTexImage(width, height, 1, (ILubyte)channels, format, ilGetTypeBpc((ILubyte)(bit_depth >> 3)), NULL)) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
//copy palette
|
||||
if (format == IL_COLOUR_INDEX) {
|
||||
int chans;
|
||||
png_bytep trans = NULL;
|
||||
int num_trans = -1;
|
||||
if (!png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
chans = 3;
|
||||
iCurImage->Pal.PalType = IL_PAL_RGB24;
|
||||
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
|
||||
png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
|
||||
iCurImage->Pal.PalType = IL_PAL_RGBA32;
|
||||
chans = 4;
|
||||
}
|
||||
|
||||
iCurImage->Pal.PalSize = num_palette * chans;
|
||||
|
||||
iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
|
||||
|
||||
for (j = 0; j < num_palette; ++j) {
|
||||
iCurImage->Pal.Palette[chans*j + 0] = palette[j].red;
|
||||
iCurImage->Pal.Palette[chans*j + 1] = palette[j].green;
|
||||
iCurImage->Pal.Palette[chans*j + 2] = palette[j].blue;
|
||||
if (trans!=NULL) {
|
||||
if (j<num_trans)
|
||||
iCurImage->Pal.Palette[chans*j + 3] = trans[j];
|
||||
else
|
||||
iCurImage->Pal.Palette[chans*j + 3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//allocate row pointers
|
||||
if ((row_pointers = (png_bytepp)ialloc(height * sizeof(png_bytep))) == NULL) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// Set the individual row_pointers to point at the correct offsets */
|
||||
for (i = 0; i < height; i++)
|
||||
row_pointers[i] = iCurImage->Data + i * iCurImage->Bps;
|
||||
|
||||
|
||||
// Now we can go ahead and just read the whole image
|
||||
png_read_image(png_ptr, row_pointers);
|
||||
|
||||
|
||||
/* and we're done! (png_read_end() can be omitted if no processing of
|
||||
* post-IDAT text/time/etc. is desired) */
|
||||
//png_read_end(png_ptr, NULL);
|
||||
ifree(row_pointers);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
void readpng_cleanup()
|
||||
{
|
||||
if (png_ptr && info_ptr) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
png_ptr = NULL;
|
||||
info_ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Png file
|
||||
ILboolean ilSavePng(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE PngFile;
|
||||
ILuint PngSize;
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PngFile = iopenw(FileName);
|
||||
if (PngFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
PngSize = ilSavePngF(PngFile);
|
||||
iclosew(PngFile);
|
||||
|
||||
if (PngSize == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Png to an already-opened file
|
||||
ILuint ilSavePngF(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputFile(File);
|
||||
Pos = itellw();
|
||||
if (iSavePngInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Png to a memory "lump"
|
||||
ILuint ilSavePngL(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputLump(Lump, Size);
|
||||
Pos = itellw();
|
||||
if (iSavePngInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
void png_write(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
(void)png_ptr;
|
||||
iwrite(data, 1, (ILuint)length);
|
||||
return;
|
||||
}
|
||||
|
||||
void flush_data(png_structp png_ptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to save the Png.
|
||||
ILboolean iSavePngInternal()
|
||||
{
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_text text[4];
|
||||
ILenum PngType;
|
||||
ILuint BitDepth, i, j;
|
||||
ILubyte **RowPtr = NULL;
|
||||
ILimage *Temp = NULL;
|
||||
ILpal *TempPal = NULL;
|
||||
|
||||
//XIX alpha
|
||||
ILubyte transpart[1];
|
||||
ILint trans;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
/* Create and initialize the png_struct with the desired error handler
|
||||
* functions. If you want to use the default stderr and longjump method,
|
||||
* you can supply NULL for the last three parameters. We also check that
|
||||
* the library version is compatible with the one used at compile time,
|
||||
* in case we are using dynamically linked libraries. REQUIRED.
|
||||
*/
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_func, png_warn_func);
|
||||
if (png_ptr == NULL) {
|
||||
ilSetError(IL_LIB_PNG_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Allocate/initialize the image information data. REQUIRED
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == NULL) {
|
||||
ilSetError(IL_LIB_PNG_ERROR);
|
||||
goto error_label;
|
||||
}
|
||||
|
||||
/*// Set error handling. REQUIRED if you aren't supplying your own
|
||||
// error handling functions in the png_create_write_struct() call.
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
// If we get here, we had a problem reading the file
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
ilSetError(IL_LIB_PNG_ERROR);
|
||||
return IL_FALSE;
|
||||
}*/
|
||||
|
||||
// png_init_io(png_ptr, PngFile);
|
||||
png_set_write_fn(png_ptr, NULL, png_write, flush_data);
|
||||
|
||||
switch (iCurImage->Type)
|
||||
{
|
||||
case IL_BYTE:
|
||||
case IL_UNSIGNED_BYTE:
|
||||
Temp = iCurImage;
|
||||
BitDepth = 8;
|
||||
break;
|
||||
case IL_SHORT:
|
||||
case IL_UNSIGNED_SHORT:
|
||||
Temp = iCurImage;
|
||||
BitDepth = 16;
|
||||
break;
|
||||
case IL_INT:
|
||||
case IL_UNSIGNED_INT:
|
||||
Temp = iConvertImage(iCurImage, iCurImage->Format, IL_UNSIGNED_SHORT);
|
||||
if (Temp == NULL) {
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
return IL_FALSE;
|
||||
}
|
||||
BitDepth = 16;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INTERNAL_ERROR);
|
||||
goto error_label;
|
||||
}
|
||||
|
||||
switch (iCurImage->Format)
|
||||
{
|
||||
case IL_COLOUR_INDEX:
|
||||
PngType = PNG_COLOR_TYPE_PALETTE;
|
||||
break;
|
||||
case IL_LUMINANCE:
|
||||
PngType = PNG_COLOR_TYPE_GRAY;
|
||||
break;
|
||||
case IL_LUMINANCE_ALPHA: //added 20050328
|
||||
PngType = PNG_COLOR_TYPE_GRAY_ALPHA;
|
||||
break;
|
||||
case IL_RGB:
|
||||
case IL_BGR:
|
||||
PngType = PNG_COLOR_TYPE_RGB;
|
||||
break;
|
||||
case IL_RGBA:
|
||||
case IL_BGRA:
|
||||
PngType = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INTERNAL_ERROR);
|
||||
goto error_label;
|
||||
}
|
||||
|
||||
// Set the image information here. Width and height are up to 2^31,
|
||||
// bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
|
||||
// the png_color_type selected. png_color_type is one of PNG_COLOR_TYPE_GRAY,
|
||||
// PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
|
||||
// or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
|
||||
// PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
|
||||
// currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
|
||||
if (iGetInt(IL_PNG_INTERLACE) == IL_TRUE) {
|
||||
png_set_IHDR(png_ptr, info_ptr, iCurImage->Width, iCurImage->Height, BitDepth, PngType,
|
||||
PNG_INTERLACE_ADAM7, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
}
|
||||
else {
|
||||
png_set_IHDR(png_ptr, info_ptr, iCurImage->Width, iCurImage->Height, BitDepth, PngType,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
}
|
||||
|
||||
if (iCurImage->Format == IL_COLOUR_INDEX) {
|
||||
// set the palette if there is one. REQUIRED for indexed-color images.
|
||||
TempPal = iConvertPal(&iCurImage->Pal, IL_PAL_RGB24);
|
||||
png_set_PLTE(png_ptr, info_ptr, (png_colorp)TempPal->Palette,
|
||||
ilGetInteger(IL_PALETTE_NUM_COLS));
|
||||
|
||||
//XIX alpha
|
||||
trans=iGetInt(IL_PNG_ALPHA_INDEX);
|
||||
if ( trans>=0)
|
||||
{
|
||||
transpart[0]=(ILubyte)trans;
|
||||
png_set_tRNS(png_ptr, info_ptr, transpart, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// optional significant bit chunk
|
||||
// if we are dealing with a grayscale image then
|
||||
sig_bit.gray = true_bit_depth;
|
||||
// otherwise, if we are dealing with a color image then
|
||||
sig_bit.red = true_red_bit_depth;
|
||||
sig_bit.green = true_green_bit_depth;
|
||||
sig_bit.blue = true_blue_bit_depth;
|
||||
// if the image has an alpha channel then
|
||||
sig_bit.alpha = true_alpha_bit_depth;
|
||||
png_set_sBIT(png_ptr, info_ptr, sig_bit);*/
|
||||
|
||||
|
||||
/* Optional gamma chunk is strongly suggested if you have any guess
|
||||
* as to the correct gamma of the image.
|
||||
*/
|
||||
//png_set_gAMA(png_ptr, info_ptr, gamma);
|
||||
|
||||
// Optionally write comments into the image.
|
||||
imemclear(text, sizeof(png_text) * 4);
|
||||
text[0].key = "Generated by";
|
||||
text[0].text = "Generated by the Developer's Image Library (DevIL)";
|
||||
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text[1].key = "Author";
|
||||
text[1].text = (char*)iGetString(IL_PNG_AUTHNAME_STRING); // Will not actually be modified!
|
||||
text[1].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text[2].key = "Description";
|
||||
text[2].text = iGetString(IL_PNG_DESCRIPTION_STRING);
|
||||
text[2].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text[3].key = "Title";
|
||||
text[3].text = iGetString(IL_PNG_TITLE_STRING);
|
||||
text[3].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
png_set_text(png_ptr, info_ptr, text, 3);
|
||||
|
||||
// Write the file header information. REQUIRED.
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
// Free up our user-defined text.
|
||||
if (text[1].text)
|
||||
ifree(text[1].text);
|
||||
if (text[2].text)
|
||||
ifree(text[2].text);
|
||||
if (text[3].text)
|
||||
ifree(text[3].text);
|
||||
|
||||
/* Shift the pixels up to a legal bit depth and fill in
|
||||
* as appropriate to correctly scale the image.
|
||||
*/
|
||||
//png_set_shift(png_ptr, &sig_bit);
|
||||
|
||||
/* pack pixels into bytes */
|
||||
//png_set_packing(png_ptr);
|
||||
|
||||
// swap location of alpha bytes from ARGB to RGBA
|
||||
//png_set_swap_alpha(png_ptr);
|
||||
|
||||
// flip BGR pixels to RGB
|
||||
if (iCurImage->Format == IL_BGR || iCurImage->Format == IL_BGRA)
|
||||
png_set_bgr(png_ptr);
|
||||
|
||||
// swap bytes of 16-bit files to most significant byte first
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
png_set_swap(png_ptr);
|
||||
#endif//__LITTLE_ENDIAN__
|
||||
|
||||
RowPtr = (ILubyte**)ialloc(iCurImage->Height * sizeof(ILubyte*));
|
||||
if (RowPtr == NULL)
|
||||
goto error_label;
|
||||
if (iCurImage->Origin == IL_ORIGIN_UPPER_LEFT) {
|
||||
for (i = 0; i < iCurImage->Height; i++) {
|
||||
RowPtr[i] = Temp->Data + i * Temp->Bps;
|
||||
}
|
||||
}
|
||||
else {
|
||||
j = iCurImage->Height - 1;
|
||||
for (i = 0; i < iCurImage->Height; i++, j--) {
|
||||
RowPtr[i] = Temp->Data + j * Temp->Bps;
|
||||
}
|
||||
}
|
||||
|
||||
// Writes the image.
|
||||
png_write_image(png_ptr, RowPtr);
|
||||
|
||||
// It is REQUIRED to call this to finish writing the rest of the file
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
|
||||
// clean up after the write, and ifree any memory allocated
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
ifree(RowPtr);
|
||||
|
||||
if (Temp != iCurImage)
|
||||
ilCloseImage(Temp);
|
||||
ilClosePal(TempPal);
|
||||
|
||||
return IL_TRUE;
|
||||
|
||||
error_label:
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
ifree(RowPtr);
|
||||
if (Temp != iCurImage)
|
||||
ilCloseImage(Temp);
|
||||
ilClosePal(TempPal);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_PNG
|
||||
@@ -0,0 +1,698 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_pnm.c
|
||||
//
|
||||
// Description: Reads/writes to/from pbm/pgm/ppm formats (enough slashes? =)
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_PNM
|
||||
#include "il_pnm.h"
|
||||
#include <limits.h> // for maximum values
|
||||
#include <ctype.h>
|
||||
#include "il_manip.h"
|
||||
#include "il_bits.h"
|
||||
|
||||
// According to the ppm specs, it's 70, but PSP
|
||||
// likes to output longer lines.
|
||||
#define MAX_BUFFER 180
|
||||
static ILbyte LineBuffer[MAX_BUFFER];
|
||||
static ILbyte SmallBuff[MAX_BUFFER];
|
||||
|
||||
// Can't read direct bits from a lump yet
|
||||
ILboolean IsLump = IL_FALSE;
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid .pnm file.
|
||||
ILboolean ilIsValidPnm(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PnmFile;
|
||||
ILboolean bPnm = IL_FALSE;
|
||||
|
||||
if ( !iCheckExtension(FileName, IL_TEXT("pbm"))
|
||||
&& !iCheckExtension(FileName, IL_TEXT("pgm"))
|
||||
&& !iCheckExtension(FileName, IL_TEXT("ppm"))
|
||||
&& !iCheckExtension(FileName, IL_TEXT("pnm"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bPnm;
|
||||
}
|
||||
|
||||
PnmFile = iopenr(FileName);
|
||||
if (PnmFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPnm;
|
||||
}
|
||||
|
||||
bPnm = ilIsValidPnmF(PnmFile);
|
||||
icloser(PnmFile);
|
||||
|
||||
return bPnm;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid .pnm file at the current position.
|
||||
ILboolean ilIsValidPnmF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidPnm();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid .pnm lump.
|
||||
ILboolean ilIsValidPnmL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidPnm();
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidPnm()
|
||||
{
|
||||
char Head[2];
|
||||
ILint Read;
|
||||
|
||||
Read = iread(Head, 1, 2);
|
||||
iseek(-Read, IL_SEEK_CUR); // Go ahead and restore to previous state
|
||||
if (Read != 2)
|
||||
return IL_FALSE;
|
||||
|
||||
return iCheckPnm(Head);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid .pnm header.
|
||||
ILboolean iCheckPnm(char Header[2])
|
||||
{
|
||||
if (Header[0] != 'P')
|
||||
return IL_FALSE;
|
||||
switch (Header[1])
|
||||
{
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// Reads a file
|
||||
ILboolean ilLoadPnm(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PnmFile;
|
||||
ILboolean bPnm = IL_FALSE;
|
||||
|
||||
PnmFile = iopenr(FileName);
|
||||
if (PnmFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPnm;
|
||||
}
|
||||
|
||||
bPnm = ilLoadPnmF(PnmFile);
|
||||
icloser(PnmFile);
|
||||
|
||||
return bPnm;
|
||||
}
|
||||
|
||||
|
||||
// Reads an already-opened file
|
||||
ILboolean ilLoadPnmF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadPnmInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
// Reads from a memory "lump"
|
||||
ILboolean ilLoadPnmL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadPnmInternal();
|
||||
}
|
||||
|
||||
|
||||
// Load either a pgm or a ppm
|
||||
ILboolean iLoadPnmInternal()
|
||||
{
|
||||
ILimage *PmImage = NULL;
|
||||
PPMINFO Info;
|
||||
// ILuint LineInc = 0, SmallInc = 0;
|
||||
|
||||
Info.Type = 0;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Find out what type of pgm/ppm this is
|
||||
if (iGetWord(IL_FALSE) == IL_FALSE)
|
||||
return IL_FALSE;
|
||||
|
||||
if (SmallBuff[0] != 'P') {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
switch( SmallBuff[1] ) {
|
||||
case '1':
|
||||
Info.Type = IL_PBM_ASCII;
|
||||
break;
|
||||
case '2':
|
||||
Info.Type = IL_PGM_ASCII;
|
||||
break;
|
||||
case '3':
|
||||
Info.Type = IL_PPM_ASCII;
|
||||
break;
|
||||
case '4':
|
||||
Info.Type = IL_PBM_BINARY;
|
||||
if (IsLump) {
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
case '5':
|
||||
Info.Type = IL_PGM_BINARY;
|
||||
break;
|
||||
case '6':
|
||||
Info.Type = IL_PPM_BINARY;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Retrieve the width and height
|
||||
if (iGetWord(IL_FALSE) == IL_FALSE)
|
||||
return IL_FALSE;
|
||||
Info.Width = atoi((const char*)SmallBuff);
|
||||
if (Info.Width == 0) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (iGetWord(IL_FALSE) == IL_FALSE)
|
||||
return IL_FALSE;
|
||||
Info.Height = atoi((const char*)SmallBuff);
|
||||
if (Info.Height == 0) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Retrieve the maximum colour component value
|
||||
if (Info.Type != IL_PBM_ASCII && Info.Type != IL_PBM_BINARY) {
|
||||
if (iGetWord(IL_TRUE) == IL_FALSE)
|
||||
return IL_FALSE;
|
||||
if ((Info.MaxColour = atoi((const char*)SmallBuff)) == 0) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
} else {
|
||||
Info.MaxColour = 1;
|
||||
}
|
||||
|
||||
if (Info.Type == IL_PBM_ASCII || Info.Type == IL_PBM_BINARY ||
|
||||
Info.Type == IL_PGM_ASCII || Info.Type == IL_PGM_BINARY) {
|
||||
if (Info.Type == IL_PGM_ASCII) {
|
||||
Info.Bpp = Info.MaxColour < 256 ? 1 : 2;
|
||||
} else {
|
||||
Info.Bpp = 1;
|
||||
}
|
||||
} else {
|
||||
Info.Bpp = 3;
|
||||
}
|
||||
|
||||
switch (Info.Type) {
|
||||
case IL_PBM_ASCII:
|
||||
case IL_PGM_ASCII:
|
||||
case IL_PPM_ASCII:
|
||||
PmImage = ilReadAsciiPpm(&Info);
|
||||
break;
|
||||
case IL_PBM_BINARY:
|
||||
PmImage = ilReadBitPbm(&Info);
|
||||
break;
|
||||
case IL_PGM_BINARY:
|
||||
case IL_PPM_BINARY:
|
||||
PmImage = ilReadBinaryPpm(&Info);
|
||||
break;
|
||||
default:
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (PmImage == NULL) {
|
||||
iCurImage->Format = ilGetFormatBpp(iCurImage->Bpp);
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Is this conversion needed? Just 0's and 1's shows up as all black
|
||||
if (Info.Type == IL_PBM_ASCII) {
|
||||
PbmMaximize(PmImage);
|
||||
}
|
||||
|
||||
if (Info.MaxColour > 255)
|
||||
PmImage->Type = IL_UNSIGNED_SHORT;
|
||||
PmImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
if (Info.Type == IL_PBM_ASCII || Info.Type == IL_PBM_BINARY ||
|
||||
Info.Type == IL_PGM_ASCII || Info.Type == IL_PGM_BINARY)
|
||||
PmImage->Format = IL_LUMINANCE;
|
||||
else
|
||||
PmImage->Format = IL_RGB;
|
||||
PmImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
if (PmImage == NULL)
|
||||
return IL_FALSE;
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
|
||||
ILimage *ilReadAsciiPpm(PPMINFO *Info)
|
||||
{
|
||||
ILint LineInc = 0, SmallInc = 0, DataInc = 0, Size;
|
||||
// ILint BytesRead = 0;
|
||||
|
||||
if (Info->MaxColour > 255)
|
||||
Info->Bpp *= 2;
|
||||
|
||||
Size = Info->Width * Info->Height * Info->Bpp;
|
||||
|
||||
if (!ilTexImage(Info->Width, Info->Height, 1, (ILubyte)(Info->Bpp), 0, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
if (Info->MaxColour > 255)
|
||||
iCurImage->Type = IL_UNSIGNED_SHORT;
|
||||
|
||||
while (DataInc < Size) { // && !feof(File)) {
|
||||
LineInc = 0;
|
||||
|
||||
if (iFgets((char *)LineBuffer, MAX_BUFFER) == NULL) {
|
||||
//ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
//return NULL;
|
||||
//return iCurImage;
|
||||
break;
|
||||
}
|
||||
if (LineBuffer[0] == '#') { // Comment
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((LineBuffer[LineInc] != NUL) && (LineBuffer[LineInc] != '\n')) {
|
||||
|
||||
SmallInc = 0;
|
||||
while (!isalnum(LineBuffer[LineInc])) { // Skip any whitespace
|
||||
LineInc++;
|
||||
}
|
||||
while (isalnum(LineBuffer[LineInc])) {
|
||||
SmallBuff[SmallInc] = LineBuffer[LineInc];
|
||||
SmallInc++;
|
||||
LineInc++;
|
||||
}
|
||||
SmallBuff[SmallInc] = NUL;
|
||||
iCurImage->Data[DataInc] = atoi((const char*)SmallBuff); // Convert from string to colour
|
||||
|
||||
// PSP likes to put whitespace at the end of lines...figures. =/
|
||||
while (!isalnum(LineBuffer[LineInc]) && LineBuffer[LineInc] != NUL) { // Skip any whitespace
|
||||
LineInc++;
|
||||
}
|
||||
|
||||
// We should set some kind of state flag that enables this
|
||||
//Image->Data[DataInc] *= (ILubyte)(255 / Info->MaxColour); // Scales to 0-255
|
||||
if (Info->MaxColour > 255)
|
||||
DataInc++;
|
||||
DataInc++;
|
||||
}
|
||||
}
|
||||
|
||||
// If we read less than what we should have...
|
||||
if (DataInc < Size) {
|
||||
//ilCloseImage(iCurImage);
|
||||
//ilSetCurImage(NULL);
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return iCurImage;
|
||||
}
|
||||
|
||||
|
||||
ILimage *ilReadBinaryPpm(PPMINFO *Info)
|
||||
{
|
||||
ILuint Size;
|
||||
|
||||
Size = Info->Width * Info->Height * Info->Bpp;
|
||||
|
||||
if (!ilTexImage(Info->Width, Info->Height, 1, (ILubyte)(Info->Bpp), 0, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
/* 4/3/2007 Dario Meloni
|
||||
Here it seems we have eaten too much bytes and it is needed to fix
|
||||
the starting point
|
||||
works well on various images
|
||||
|
||||
No more need of this workaround. fixed iGetWord
|
||||
iseek(0,IL_SEEK_END);
|
||||
ILuint size = itell();
|
||||
iseek(size-Size,IL_SEEK_SET);
|
||||
*/
|
||||
if (iread(iCurImage->Data, 1, Size ) != Size) {
|
||||
ilCloseImage(iCurImage);
|
||||
return NULL;
|
||||
}
|
||||
return iCurImage;
|
||||
}
|
||||
|
||||
|
||||
ILimage *ilReadBitPbm(PPMINFO *Info)
|
||||
{
|
||||
ILuint m, j, x, CurrByte;
|
||||
|
||||
if (!ilTexImage(Info->Width, Info->Height, 1, (ILubyte)(Info->Bpp), 0, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
x = 0;
|
||||
for (j = 0; j < iCurImage->SizeOfData;) {
|
||||
CurrByte = igetc();
|
||||
for (m = 128; m > 0 && x < Info->Width; m >>= 1, ++x, ++j) {
|
||||
iCurImage->Data[j] = (CurrByte & m)?255:0;
|
||||
}
|
||||
if (x == Info->Width)
|
||||
x = 0;
|
||||
}
|
||||
|
||||
return iCurImage;
|
||||
}
|
||||
|
||||
|
||||
ILboolean iGetWord(ILboolean final)
|
||||
{
|
||||
ILint WordPos = 0;
|
||||
ILint Current = 0;
|
||||
ILboolean Started = IL_FALSE;
|
||||
ILboolean Looping = IL_TRUE;
|
||||
|
||||
if (ieof())
|
||||
return IL_FALSE;
|
||||
|
||||
while (Looping) {
|
||||
while ((Current = igetc()) != IL_EOF && Current != '\n' && Current != '#' && Current != ' ') {
|
||||
if (WordPos >= MAX_BUFFER) // We have hit the maximum line length.
|
||||
return IL_FALSE;
|
||||
|
||||
if (!isalnum(Current)) {
|
||||
if (Started) {
|
||||
Looping = IL_FALSE;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Looping)
|
||||
SmallBuff[WordPos++] = Current;
|
||||
}
|
||||
if (Current == IL_EOF)
|
||||
return IL_FALSE;
|
||||
SmallBuff[WordPos] = 0; // 08-17-2008 - was NULL, changed to avoid warning
|
||||
if (final == IL_TRUE)
|
||||
break;
|
||||
|
||||
if (!Looping)
|
||||
break;
|
||||
|
||||
if (Current == '#') { // '#' is a comment...read until end of line
|
||||
while ((Current = igetc()) != IL_EOF && Current != '\n');
|
||||
}
|
||||
|
||||
// Get rid of any erroneous spaces
|
||||
while ((Current = igetc()) != IL_EOF) {
|
||||
if (Current != ' ')
|
||||
break;
|
||||
}
|
||||
iseek(-1, IL_SEEK_CUR);
|
||||
|
||||
if (WordPos > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (Current == -1 || WordPos == 0) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILstring FName = NULL;
|
||||
|
||||
//! Writes a Pnm file
|
||||
ILboolean ilSavePnm(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE PnmFile;
|
||||
ILuint PnmSize;
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PnmFile = iopenw(FileName);
|
||||
if (PnmFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
PnmSize = ilSavePnmF(PnmFile);
|
||||
iclosew(PnmFile);
|
||||
|
||||
if (PnmSize == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Pnm to an already-opened file
|
||||
ILuint ilSavePnmF(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputFile(File);
|
||||
Pos = itellw();
|
||||
if (iSavePnmInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Pnm to a memory "lump"
|
||||
ILuint ilSavePnmL(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos;
|
||||
FName = NULL;
|
||||
iSetOutputLump(Lump, Size);
|
||||
Pos = itellw();
|
||||
if (iSavePnmInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to save the Pnm.
|
||||
ILboolean iSavePnmInternal()
|
||||
{
|
||||
ILuint Bpp, MaxVal = UCHAR_MAX, i = 0, j, k;
|
||||
ILenum Type = 0;
|
||||
ILuint LinePos = 0; // Cannot exceed 70 for pnm's!
|
||||
ILboolean Binary;
|
||||
ILimage *TempImage;
|
||||
ILubyte *TempData;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (iCheckExtension(FName, IL_TEXT("pbm")))
|
||||
Type = IL_PBM_ASCII;
|
||||
else if (iCheckExtension(FName, IL_TEXT("pgm")))
|
||||
Type = IL_PGM_ASCII;
|
||||
else if (iCheckExtension(FName, IL_TEXT("ppm")))
|
||||
Type = IL_PPM_ASCII;
|
||||
else
|
||||
Type = IL_PPM_ASCII;
|
||||
|
||||
/*if (!Type) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return IL_FALSE;
|
||||
}*/
|
||||
|
||||
if (iGetHint(IL_COMPRESSION_HINT) == IL_USE_COMPRESSION) {
|
||||
Type += 3;
|
||||
Binary = IL_TRUE;
|
||||
}
|
||||
else {
|
||||
Binary = IL_FALSE;
|
||||
}
|
||||
|
||||
if (iCurImage->Type == IL_UNSIGNED_BYTE) {
|
||||
MaxVal = UCHAR_MAX;
|
||||
}
|
||||
else if (iCurImage->Type == IL_UNSIGNED_SHORT) {
|
||||
MaxVal = USHRT_MAX;
|
||||
}
|
||||
else {
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (MaxVal > UCHAR_MAX && Type >= IL_PBM_BINARY) { // binary cannot be higher than 255
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case IL_PBM_ASCII:
|
||||
Bpp = 1;
|
||||
ilprintf("P1\n");
|
||||
TempImage = iConvertImage(iCurImage, IL_LUMINANCE, IL_UNSIGNED_BYTE);
|
||||
break;
|
||||
//case IL_PBM_BINARY: // Don't want to mess with saving bits just yet...
|
||||
//Bpp = 1;
|
||||
//ilprintf("P4\n");
|
||||
//break;
|
||||
case IL_PBM_BINARY:
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
case IL_PGM_ASCII:
|
||||
Bpp = 1;
|
||||
ilprintf("P2\n");
|
||||
TempImage = iConvertImage(iCurImage, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE);
|
||||
break;
|
||||
case IL_PGM_BINARY:
|
||||
Bpp = 1;
|
||||
ilprintf("P5\n");
|
||||
TempImage = iConvertImage(iCurImage, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE);
|
||||
break;
|
||||
case IL_PPM_ASCII:
|
||||
Bpp = 3;
|
||||
ilprintf("P3\n");
|
||||
TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
|
||||
break;
|
||||
case IL_PPM_BINARY:
|
||||
Bpp = 3;
|
||||
ilprintf("P6\n");
|
||||
TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INTERNAL_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (TempImage == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
if (Bpp != TempImage->Bpp) {
|
||||
ilSetError(IL_INVALID_CONVERSION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
|
||||
TempData = iGetFlipped(TempImage);
|
||||
if (TempData == NULL) {
|
||||
ilCloseImage(TempImage);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
TempData = TempImage->Data;
|
||||
}
|
||||
|
||||
ilprintf("%d %d\n", TempImage->Width, TempImage->Height);
|
||||
if (Type != IL_PBM_BINARY && Type != IL_PBM_ASCII) // not needed for .pbm's (only 0 and 1)
|
||||
ilprintf("%d\n", MaxVal);
|
||||
|
||||
while (i < TempImage->SizeOfPlane) {
|
||||
for (j = 0; j < Bpp; j++) {
|
||||
if (Binary) {
|
||||
if (Type == IL_PBM_BINARY) {
|
||||
iputc((ILubyte)(TempData[i] > 127 ? 1 : 0));
|
||||
}
|
||||
else {
|
||||
iputc(TempData[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (TempImage->Type == IL_UNSIGNED_BYTE)
|
||||
k = TempData[i];
|
||||
else // IL_UNSIGNED_SHORT
|
||||
k = *((ILushort*)TempData + i);
|
||||
if (Type == IL_PBM_ASCII) {
|
||||
LinePos += ilprintf("%d ", TempData[i] > 127 ? 1 : 0);
|
||||
}
|
||||
else {
|
||||
LinePos += ilprintf("%d ", TempData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (TempImage->Type == IL_UNSIGNED_SHORT)
|
||||
i++;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (LinePos > 65) { // Just a good number =]
|
||||
ilprintf("\n");
|
||||
LinePos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT)
|
||||
ifree(TempData);
|
||||
ilCloseImage(TempImage);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Converts a .pbm to something viewable.
|
||||
void PbmMaximize(ILimage *Image)
|
||||
{
|
||||
ILuint i = 0;
|
||||
for (i = 0; i < Image->SizeOfPlane; i++)
|
||||
if (Image->Data[i] == 1)
|
||||
Image->Data[i] = 0xFF;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_PNM
|
||||
@@ -0,0 +1,174 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2002 by Denton Woods
|
||||
// Last modified: 01/23/2001 <--Y2K Compliant! =]
|
||||
//
|
||||
// Filename: src-IL/src/il_profiles.c
|
||||
//
|
||||
// Description: Colour profile handler
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_LCMS
|
||||
|
||||
#ifdef PACKAGE_NAME
|
||||
#define IL_PACKAGE_NAME PACKAGE_NAME;
|
||||
#undef PACKAGE_NAME
|
||||
#endif
|
||||
|
||||
#if (!defined(_WIN32) && !defined(_WIN64))
|
||||
#define NON_WINDOWS 1
|
||||
#ifdef LCMS_NODIRINCLUDE
|
||||
#include <lcms.h>
|
||||
#else
|
||||
#include <lcms/lcms.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if defined(IL_USE_PRAGMA_LIBS)
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#ifndef _DEBUG
|
||||
#pragma comment(lib, "lcms.lib")
|
||||
#else
|
||||
#pragma comment(lib, "lcms-d.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <lcms.h>
|
||||
#endif//_WIN32
|
||||
|
||||
#ifdef PACKAGE_NAME
|
||||
#undef PACKAGE_NAME
|
||||
#endif
|
||||
|
||||
#ifdef IL_PACKAGE_NAME
|
||||
#define PACKAGE_NAME IL_PACKAGE_NAME
|
||||
#undef IL_PACKAGE_NAME
|
||||
#endif
|
||||
|
||||
#endif//IL_NO_LCMS
|
||||
|
||||
ILboolean ILAPIENTRY ilApplyProfile(ILstring InProfile, ILstring OutProfile)
|
||||
{
|
||||
#ifndef IL_NO_LCMS
|
||||
cmsHPROFILE hInProfile, hOutProfile;
|
||||
cmsHTRANSFORM hTransform;
|
||||
ILubyte *Temp;
|
||||
ILint Format=0;
|
||||
#ifdef _UNICODE
|
||||
char AnsiName[512];
|
||||
#endif//_UNICODE
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
switch (iCurImage->Type)
|
||||
{
|
||||
case IL_BYTE:
|
||||
case IL_UNSIGNED_BYTE:
|
||||
switch (iCurImage->Format)
|
||||
{
|
||||
case IL_LUMINANCE:
|
||||
Format = TYPE_GRAY_8;
|
||||
break;
|
||||
case IL_RGB:
|
||||
Format = TYPE_RGB_8;
|
||||
break;
|
||||
case IL_BGR:
|
||||
Format = TYPE_BGR_8;
|
||||
break;
|
||||
case IL_RGBA:
|
||||
Format = TYPE_RGBA_8;
|
||||
break;
|
||||
case IL_BGRA:
|
||||
Format = TYPE_BGRA_8;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INTERNAL_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case IL_SHORT:
|
||||
case IL_UNSIGNED_SHORT:
|
||||
switch (iCurImage->Format)
|
||||
{
|
||||
case IL_LUMINANCE:
|
||||
Format = TYPE_GRAY_16;
|
||||
break;
|
||||
case IL_RGB:
|
||||
Format = TYPE_RGB_16;
|
||||
break;
|
||||
case IL_BGR:
|
||||
Format = TYPE_BGR_16;
|
||||
break;
|
||||
case IL_RGBA:
|
||||
Format = TYPE_RGBA_16;
|
||||
break;
|
||||
case IL_BGRA:
|
||||
Format = TYPE_BGRA_16;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INTERNAL_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
// These aren't supported right now.
|
||||
case IL_INT:
|
||||
case IL_UNSIGNED_INT:
|
||||
case IL_FLOAT:
|
||||
case IL_DOUBLE:
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (InProfile == NULL) {
|
||||
if (!iCurImage->Profile || !iCurImage->ProfileSize) {
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
return IL_FALSE;
|
||||
}
|
||||
hInProfile = iCurImage->Profile;
|
||||
}
|
||||
else {
|
||||
#ifndef _UNICODE
|
||||
hInProfile = cmsOpenProfileFromFile(InProfile, "r");
|
||||
#else
|
||||
wcstombs(AnsiName, InProfile, 512);
|
||||
hInProfile = cmsOpenProfileFromFile(AnsiName, "r");
|
||||
#endif//_UNICODE
|
||||
}
|
||||
#ifndef _UNICODE
|
||||
hOutProfile = cmsOpenProfileFromFile(OutProfile, "r");
|
||||
#else
|
||||
wcstombs(AnsiName, OutProfile, 512);
|
||||
hOutProfile = cmsOpenProfileFromFile(AnsiName, "r");
|
||||
#endif//_UNICODE
|
||||
|
||||
hTransform = cmsCreateTransform(hInProfile, Format, hOutProfile, Format, INTENT_PERCEPTUAL, 0);
|
||||
|
||||
Temp = (ILubyte*)ialloc(iCurImage->SizeOfData);
|
||||
if (Temp == NULL) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
cmsDoTransform(hTransform, iCurImage->Data, Temp, iCurImage->SizeOfData / 3);
|
||||
|
||||
ifree(iCurImage->Data);
|
||||
iCurImage->Data = Temp;
|
||||
|
||||
cmsDeleteTransform(hTransform);
|
||||
if (InProfile != NULL)
|
||||
cmsCloseProfile(hInProfile);
|
||||
cmsCloseProfile(hOutProfile);
|
||||
|
||||
#endif//IL_NO_LCMS
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,712 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_psp.c
|
||||
//
|
||||
// Description: Reads a Paint Shop Pro file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#include "il_psp.h"
|
||||
#ifndef IL_NO_PSP
|
||||
|
||||
|
||||
ILubyte PSPSignature[32] = {
|
||||
0x50, 0x61, 0x69, 0x6E, 0x74, 0x20, 0x53, 0x68, 0x6F, 0x70, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x49,
|
||||
0x6D, 0x61, 0x67, 0x65, 0x20, 0x46, 0x69, 0x6C, 0x65, 0x0A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
ILubyte GenAttHead[4] = {
|
||||
0x7E, 0x42, 0x4B, 0x00
|
||||
};
|
||||
|
||||
|
||||
// Make these global, since they contain most of the image information.
|
||||
GENATT_CHUNK AttChunk;
|
||||
PSPHEAD Header;
|
||||
ILuint NumChannels;
|
||||
ILubyte **Channels = NULL;
|
||||
ILubyte *Alpha = NULL;
|
||||
ILpal Pal;
|
||||
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid Psp file.
|
||||
ILboolean ilIsValidPsp(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PspFile;
|
||||
ILboolean bPsp = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("psp"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bPsp;
|
||||
}
|
||||
|
||||
PspFile = iopenr(FileName);
|
||||
if (PspFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPsp;
|
||||
}
|
||||
|
||||
bPsp = ilIsValidPspF(PspFile);
|
||||
icloser(PspFile);
|
||||
|
||||
return bPsp;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid Psp file at the current position.
|
||||
ILboolean ilIsValidPspF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidPsp();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid Psp lump.
|
||||
ILboolean ilIsValidPspL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidPsp();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the Psp header from the current file.
|
||||
ILboolean iGetPspHead()
|
||||
{
|
||||
if (iread(Header.FileSig, 1, 32) != 32)
|
||||
return IL_FALSE;
|
||||
Header.MajorVersion = GetLittleUShort();
|
||||
Header.MinorVersion = GetLittleUShort();
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidPsp()
|
||||
{
|
||||
if (!iGetPspHead())
|
||||
return IL_FALSE;
|
||||
iseek(-(ILint)sizeof(PSPHEAD), IL_SEEK_CUR);
|
||||
|
||||
return iCheckPsp();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid Psp header.
|
||||
ILboolean iCheckPsp()
|
||||
{
|
||||
if (stricmp(Header.FileSig, "Paint Shop Pro Image File\n\x1a"))
|
||||
return IL_FALSE;
|
||||
if (Header.MajorVersion < 3 || Header.MajorVersion > 5)
|
||||
return IL_FALSE;
|
||||
if (Header.MinorVersion != 0)
|
||||
return IL_FALSE;
|
||||
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a PSP file
|
||||
ILboolean ilLoadPsp(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PSPFile;
|
||||
ILboolean bPsp = IL_FALSE;
|
||||
|
||||
PSPFile = iopenr(FileName);
|
||||
if (PSPFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPsp;
|
||||
}
|
||||
|
||||
bPsp = ilLoadPspF(PSPFile);
|
||||
icloser(PSPFile);
|
||||
|
||||
return bPsp;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened PSP file
|
||||
ILboolean ilLoadPspF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadPspInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a PSP
|
||||
ILboolean ilLoadPspL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadPspInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the PSP.
|
||||
ILboolean iLoadPspInternal()
|
||||
{
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Channels = NULL;
|
||||
Alpha = NULL;
|
||||
Pal.Palette = NULL;
|
||||
|
||||
if (!iGetPspHead())
|
||||
return IL_FALSE;
|
||||
if (!iCheckPsp()) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!ReadGenAttributes())
|
||||
return IL_FALSE;
|
||||
if (!ParseChunks())
|
||||
return IL_FALSE;
|
||||
if (!AssembleImage())
|
||||
return IL_FALSE;
|
||||
|
||||
Cleanup();
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
ILboolean ReadGenAttributes()
|
||||
{
|
||||
BLOCKHEAD AttHead;
|
||||
ILint Padding;
|
||||
ILuint ChunkLen;
|
||||
|
||||
if (iread(&AttHead, sizeof(AttHead), 1) != 1)
|
||||
return IL_FALSE;
|
||||
UShort(&AttHead.BlockID);
|
||||
UInt(&AttHead.BlockLen);
|
||||
|
||||
if (AttHead.HeadID[0] != 0x7E || AttHead.HeadID[1] != 0x42 ||
|
||||
AttHead.HeadID[2] != 0x4B || AttHead.HeadID[3] != 0x00) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (AttHead.BlockID != PSP_IMAGE_BLOCK) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
ChunkLen = GetLittleUInt();
|
||||
if (Header.MajorVersion != 3)
|
||||
ChunkLen -= 4;
|
||||
if (iread(&AttChunk, IL_MIN(sizeof(AttChunk), ChunkLen), 1) != 1)
|
||||
return IL_FALSE;
|
||||
|
||||
// Can have new entries in newer versions of the spec (4.0).
|
||||
Padding = (ChunkLen) - sizeof(AttChunk);
|
||||
if (Padding > 0)
|
||||
iseek(Padding, IL_SEEK_CUR);
|
||||
|
||||
// @TODO: Anything but 24 not supported yet...
|
||||
if (AttChunk.BitDepth != 24 && AttChunk.BitDepth != 8) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// @TODO; Add support for compression...
|
||||
if (AttChunk.Compression != PSP_COMP_NONE && AttChunk.Compression != PSP_COMP_RLE) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// @TODO: Check more things in the general attributes chunk here.
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ParseChunks()
|
||||
{
|
||||
BLOCKHEAD Block;
|
||||
ILuint Pos;
|
||||
|
||||
do {
|
||||
if (iread(&Block, 1, sizeof(Block)) != sizeof(Block)) {
|
||||
ilGetError(); // Get rid of the erroneous IL_FILE_READ_ERROR.
|
||||
return IL_TRUE;
|
||||
}
|
||||
if (Header.MajorVersion == 3)
|
||||
Block.BlockLen = GetLittleUInt();
|
||||
else
|
||||
UInt(&Block.BlockLen);
|
||||
|
||||
if (Block.HeadID[0] != 0x7E || Block.HeadID[1] != 0x42 ||
|
||||
Block.HeadID[2] != 0x4B || Block.HeadID[3] != 0x00) {
|
||||
return IL_TRUE;
|
||||
}
|
||||
UShort(&Block.BlockID);
|
||||
UInt(&Block.BlockLen);
|
||||
|
||||
Pos = itell();
|
||||
|
||||
switch (Block.BlockID)
|
||||
{
|
||||
case PSP_LAYER_START_BLOCK:
|
||||
if (!ReadLayerBlock(Block.BlockLen))
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case PSP_ALPHA_BANK_BLOCK:
|
||||
if (!ReadAlphaBlock(Block.BlockLen))
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case PSP_COLOR_BLOCK:
|
||||
if (!ReadPalette(Block.BlockLen))
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
// Gets done in the next iseek, so this is now commented out.
|
||||
//default:
|
||||
//iseek(Block.BlockLen, IL_SEEK_CUR);
|
||||
}
|
||||
|
||||
// Skip to next block just in case we didn't read the entire block.
|
||||
iseek(Pos + Block.BlockLen, IL_SEEK_SET);
|
||||
|
||||
// @TODO: Do stuff here.
|
||||
|
||||
} while (1);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ReadLayerBlock(ILuint BlockLen)
|
||||
{
|
||||
BLOCKHEAD Block;
|
||||
LAYERINFO_CHUNK LayerInfo;
|
||||
LAYERBITMAP_CHUNK Bitmap;
|
||||
ILuint ChunkSize, Padding, i, j;
|
||||
ILushort NumChars;
|
||||
|
||||
BlockLen;
|
||||
|
||||
// Layer sub-block header
|
||||
if (iread(&Block, 1, sizeof(Block)) != sizeof(Block))
|
||||
return IL_FALSE;
|
||||
if (Header.MajorVersion == 3)
|
||||
Block.BlockLen = GetLittleUInt();
|
||||
else
|
||||
UInt(&Block.BlockLen);
|
||||
|
||||
if (Block.HeadID[0] != 0x7E || Block.HeadID[1] != 0x42 ||
|
||||
Block.HeadID[2] != 0x4B || Block.HeadID[3] != 0x00) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (Block.BlockID != PSP_LAYER_BLOCK)
|
||||
return IL_FALSE;
|
||||
|
||||
|
||||
if (Header.MajorVersion == 3) {
|
||||
iseek(256, IL_SEEK_CUR); // We don't care about the name of the layer.
|
||||
iread(&LayerInfo, sizeof(LayerInfo), 1);
|
||||
if (iread(&Bitmap, sizeof(Bitmap), 1) != 1)
|
||||
return IL_FALSE;
|
||||
}
|
||||
else { // Header.MajorVersion >= 4
|
||||
ChunkSize = GetLittleUInt();
|
||||
NumChars = GetLittleUShort();
|
||||
iseek(NumChars, IL_SEEK_CUR); // We don't care about the layer's name.
|
||||
|
||||
ChunkSize -= (2 + 4 + NumChars);
|
||||
|
||||
if (iread(&LayerInfo, IL_MIN(sizeof(LayerInfo), ChunkSize), 1) != 1)
|
||||
return IL_FALSE;
|
||||
|
||||
// Can have new entries in newer versions of the spec (5.0).
|
||||
Padding = (ChunkSize) - sizeof(LayerInfo);
|
||||
if (Padding > 0)
|
||||
iseek(Padding, IL_SEEK_CUR);
|
||||
|
||||
ChunkSize = GetLittleUInt();
|
||||
if (iread(&Bitmap, sizeof(Bitmap), 1) != 1)
|
||||
return IL_FALSE;
|
||||
Padding = (ChunkSize - 4) - sizeof(Bitmap);
|
||||
if (Padding > 0)
|
||||
iseek(Padding, IL_SEEK_CUR);
|
||||
}
|
||||
|
||||
|
||||
Channels = (ILubyte**)ialloc(sizeof(ILubyte*) * Bitmap.NumChannels);
|
||||
if (Channels == NULL) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
NumChannels = Bitmap.NumChannels;
|
||||
|
||||
for (i = 0; i < NumChannels; i++) {
|
||||
Channels[i] = GetChannel();
|
||||
if (Channels[i] == NULL) {
|
||||
for (j = 0; j < i; j++)
|
||||
ifree(Channels[j]);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ReadAlphaBlock(ILuint BlockLen)
|
||||
{
|
||||
BLOCKHEAD Block;
|
||||
ALPHAINFO_CHUNK AlphaInfo;
|
||||
ALPHA_CHUNK AlphaChunk;
|
||||
ILushort NumAlpha, StringSize;
|
||||
ILuint ChunkSize, Padding;
|
||||
|
||||
if (Header.MajorVersion == 3) {
|
||||
NumAlpha = GetLittleUShort();
|
||||
}
|
||||
else {
|
||||
ChunkSize = GetLittleUInt();
|
||||
NumAlpha = GetLittleUShort();
|
||||
Padding = (ChunkSize - 4 - 2);
|
||||
if (Padding > 0)
|
||||
iseek(Padding, IL_SEEK_CUR);
|
||||
}
|
||||
|
||||
// Alpha channel header
|
||||
if (iread(&Block, 1, sizeof(Block)) != sizeof(Block))
|
||||
return IL_FALSE;
|
||||
if (Header.MajorVersion == 3)
|
||||
Block.BlockLen = GetLittleUInt();
|
||||
else
|
||||
UInt(&Block.BlockLen);
|
||||
|
||||
if (Block.HeadID[0] != 0x7E || Block.HeadID[1] != 0x42 ||
|
||||
Block.HeadID[2] != 0x4B || Block.HeadID[3] != 0x00) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (Block.BlockID != PSP_ALPHA_CHANNEL_BLOCK)
|
||||
return IL_FALSE;
|
||||
|
||||
|
||||
if (Header.MajorVersion >= 4) {
|
||||
ChunkSize = GetLittleUInt();
|
||||
StringSize = GetLittleUShort();
|
||||
iseek(StringSize, IL_SEEK_CUR);
|
||||
if (iread(&AlphaInfo, sizeof(AlphaInfo), 1) != 1)
|
||||
return IL_FALSE;
|
||||
Padding = (ChunkSize - 4 - 2 - StringSize - sizeof(AlphaInfo));
|
||||
if (Padding > 0)
|
||||
iseek(Padding, IL_SEEK_CUR);
|
||||
|
||||
ChunkSize = GetLittleUInt();
|
||||
if (iread(&AlphaChunk, sizeof(AlphaChunk), 1) != 1)
|
||||
return IL_FALSE;
|
||||
Padding = (ChunkSize - 4 - sizeof(AlphaChunk));
|
||||
if (Padding > 0)
|
||||
iseek(Padding, IL_SEEK_CUR);
|
||||
}
|
||||
else {
|
||||
iseek(256, IL_SEEK_CUR);
|
||||
iread(&AlphaInfo, sizeof(AlphaInfo), 1);
|
||||
if (iread(&AlphaChunk, sizeof(AlphaChunk), 1) != 1)
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*Alpha = (ILubyte*)ialloc(AlphaInfo.AlphaRect.x2 * AlphaInfo.AlphaRect.y2);
|
||||
if (Alpha == NULL) {
|
||||
return IL_FALSE;
|
||||
}*/
|
||||
|
||||
|
||||
Alpha = GetChannel();
|
||||
if (Alpha == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILubyte *GetChannel()
|
||||
{
|
||||
BLOCKHEAD Block;
|
||||
CHANNEL_CHUNK Channel;
|
||||
ILubyte *CompData, *Data;
|
||||
ILuint ChunkSize, Padding;
|
||||
|
||||
if (iread(&Block, 1, sizeof(Block)) != sizeof(Block))
|
||||
return NULL;
|
||||
if (Header.MajorVersion == 3)
|
||||
Block.BlockLen = GetLittleUInt();
|
||||
else
|
||||
UInt(&Block.BlockLen);
|
||||
|
||||
if (Block.HeadID[0] != 0x7E || Block.HeadID[1] != 0x42 ||
|
||||
Block.HeadID[2] != 0x4B || Block.HeadID[3] != 0x00) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return NULL;
|
||||
}
|
||||
if (Block.BlockID != PSP_CHANNEL_BLOCK) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (Header.MajorVersion >= 4) {
|
||||
ChunkSize = GetLittleUInt();
|
||||
if (iread(&Channel, sizeof(Channel), 1) != 1)
|
||||
return NULL;
|
||||
|
||||
Padding = (ChunkSize - 4) - sizeof(Channel);
|
||||
if (Padding > 0)
|
||||
iseek(Padding, IL_SEEK_CUR);
|
||||
}
|
||||
else {
|
||||
if (iread(&Channel, sizeof(Channel), 1) != 1)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
CompData = (ILubyte*)ialloc(Channel.CompLen);
|
||||
Data = (ILubyte*)ialloc(AttChunk.Width * AttChunk.Height);
|
||||
if (CompData == NULL || Data == NULL) {
|
||||
ifree(Data);
|
||||
ifree(CompData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (iread(CompData, 1, Channel.CompLen) != Channel.CompLen) {
|
||||
ifree(CompData);
|
||||
ifree(Data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (AttChunk.Compression)
|
||||
{
|
||||
case PSP_COMP_NONE:
|
||||
ifree(Data);
|
||||
return CompData;
|
||||
break;
|
||||
|
||||
case PSP_COMP_RLE:
|
||||
if (!UncompRLE(CompData, Data, Channel.CompLen)) {
|
||||
ifree(CompData);
|
||||
ifree(Data);
|
||||
return IL_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ifree(CompData);
|
||||
ifree(Data);
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ifree(CompData);
|
||||
|
||||
return Data;
|
||||
}
|
||||
|
||||
|
||||
ILboolean UncompRLE(ILubyte *CompData, ILubyte *Data, ILuint CompLen)
|
||||
{
|
||||
ILubyte Run, Colour;
|
||||
ILint i, /*x, y,*/ Count/*, Total = 0*/;
|
||||
|
||||
/*for (y = 0; y < AttChunk.Height; y++) {
|
||||
for (x = 0, Count = 0; x < AttChunk.Width; ) {
|
||||
Run = *CompData++;
|
||||
if (Run > 128) {
|
||||
Run -= 128;
|
||||
Colour = *CompData++;
|
||||
memset(Data, Colour, Run);
|
||||
Data += Run;
|
||||
Count += 2;
|
||||
}
|
||||
else {
|
||||
memcpy(Data, CompData, Run);
|
||||
CompData += Run;
|
||||
Data += Run;
|
||||
Count += Run;
|
||||
}
|
||||
x += Run;
|
||||
}
|
||||
|
||||
Total += Count;
|
||||
|
||||
if (Count % 4) { // Has to be on a 4-byte boundary.
|
||||
CompData += (4 - (Count % 4)) % 4;
|
||||
Total += (4 - (Count % 4)) % 4;
|
||||
}
|
||||
|
||||
if (Total >= CompLen)
|
||||
return IL_FALSE;
|
||||
}*/
|
||||
|
||||
for (i = 0, Count = 0; i < (ILint)CompLen; ) {
|
||||
Run = *CompData++;
|
||||
i++;
|
||||
if (Run > 128) {
|
||||
Run -= 128;
|
||||
Colour = *CompData++;
|
||||
i++;
|
||||
memset(Data, Colour, Run);
|
||||
}
|
||||
else {
|
||||
memcpy(Data, CompData, Run);
|
||||
CompData += Run;
|
||||
i += Run;
|
||||
}
|
||||
Data += Run;
|
||||
Count += Run;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ReadPalette(ILuint BlockLen)
|
||||
{
|
||||
ILuint ChunkSize, PalCount, Padding;
|
||||
|
||||
if (Header.MajorVersion >= 4) {
|
||||
ChunkSize = GetLittleUInt();
|
||||
PalCount = GetLittleUInt();
|
||||
Padding = (ChunkSize - 4 - 4);
|
||||
if (Padding > 0)
|
||||
iseek(Padding, IL_SEEK_CUR);
|
||||
}
|
||||
else {
|
||||
PalCount = GetLittleUInt();
|
||||
}
|
||||
|
||||
Pal.PalSize = PalCount * 4;
|
||||
Pal.PalType = IL_PAL_BGRA32;
|
||||
Pal.Palette = (ILubyte*)ialloc(Pal.PalSize);
|
||||
if (Pal.Palette == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
if (iread(Pal.Palette, Pal.PalSize, 1) != 1) {
|
||||
ifree(Pal.Palette);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean AssembleImage()
|
||||
{
|
||||
ILuint Size, i, j;
|
||||
|
||||
Size = AttChunk.Width * AttChunk.Height;
|
||||
|
||||
if (NumChannels == 1) {
|
||||
ilTexImage(AttChunk.Width, AttChunk.Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL);
|
||||
for (i = 0; i < Size; i++) {
|
||||
iCurImage->Data[i] = Channels[0][i];
|
||||
}
|
||||
|
||||
if (Pal.Palette) {
|
||||
iCurImage->Format = IL_COLOUR_INDEX;
|
||||
iCurImage->Pal.PalSize = Pal.PalSize;
|
||||
iCurImage->Pal.PalType = Pal.PalType;
|
||||
iCurImage->Pal.Palette = Pal.Palette;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (Alpha) {
|
||||
ilTexImage(AttChunk.Width, AttChunk.Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
|
||||
for (i = 0, j = 0; i < Size; i++, j += 4) {
|
||||
iCurImage->Data[j ] = Channels[0][i];
|
||||
iCurImage->Data[j+1] = Channels[1][i];
|
||||
iCurImage->Data[j+2] = Channels[2][i];
|
||||
iCurImage->Data[j+3] = Alpha[i];
|
||||
}
|
||||
}
|
||||
|
||||
else if (NumChannels == 4) {
|
||||
|
||||
ilTexImage(AttChunk.Width, AttChunk.Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
for (i = 0, j = 0; i < Size; i++, j += 4) {
|
||||
|
||||
iCurImage->Data[j ] = Channels[0][i];
|
||||
|
||||
iCurImage->Data[j+1] = Channels[1][i];
|
||||
|
||||
iCurImage->Data[j+2] = Channels[2][i];
|
||||
|
||||
iCurImage->Data[j+3] = Channels[3][i];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if (NumChannels == 3) {
|
||||
ilTexImage(AttChunk.Width, AttChunk.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
|
||||
for (i = 0, j = 0; i < Size; i++, j += 3) {
|
||||
iCurImage->Data[j ] = Channels[0][i];
|
||||
iCurImage->Data[j+1] = Channels[1][i];
|
||||
iCurImage->Data[j+2] = Channels[2][i];
|
||||
}
|
||||
}
|
||||
else
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean Cleanup()
|
||||
{
|
||||
ILuint i;
|
||||
|
||||
if (Channels) {
|
||||
for (i = 0; i < NumChannels; i++) {
|
||||
ifree(Channels[i]);
|
||||
}
|
||||
ifree(Channels);
|
||||
}
|
||||
|
||||
if (Alpha) {
|
||||
ifree(Alpha);
|
||||
}
|
||||
|
||||
Channels = NULL;
|
||||
Alpha = NULL;
|
||||
Pal.Palette = NULL;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif//IL_NO_PSP
|
||||
@@ -0,0 +1,120 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2002 by Denton Woods
|
||||
// Last modified: 05/26/2002 <--Y2K Compliant! =]
|
||||
//
|
||||
// Filename: src-IL/src/il_pxr.c
|
||||
//
|
||||
// Description: Reads from a Pxrar (.pxr) file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_PXR
|
||||
#include "il_manip.h"
|
||||
#include "il_endian.h"
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, pxr_struct, 1)
|
||||
#endif
|
||||
typedef struct PIXHEAD
|
||||
{
|
||||
ILushort Signature;
|
||||
ILubyte Reserved1[413];
|
||||
ILushort Height;
|
||||
ILushort Width;
|
||||
ILubyte Reserved2[4];
|
||||
ILubyte BppInfo;
|
||||
ILubyte Reserved3[598];
|
||||
} IL_PACKSTRUCT PIXHEAD;
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop, pxr_struct)
|
||||
#endif
|
||||
|
||||
ILboolean iLoadPxrInternal(void);
|
||||
|
||||
|
||||
//! Reads a Pxr file
|
||||
ILboolean ilLoadPxr(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE PxrFile;
|
||||
ILboolean bPxr = IL_FALSE;
|
||||
|
||||
PxrFile = iopenr(FileName);
|
||||
if (PxrFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bPxr;
|
||||
}
|
||||
|
||||
bPxr = ilLoadPxrF(PxrFile);
|
||||
icloser(PxrFile);
|
||||
|
||||
return bPxr;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened Pxr file
|
||||
ILboolean ilLoadPxrF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadPxrInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a Pxr
|
||||
ILboolean ilLoadPxrL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadPxrInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the Pxr.
|
||||
ILboolean iLoadPxrInternal()
|
||||
{
|
||||
ILushort Width, Height;
|
||||
ILubyte Bpp;
|
||||
|
||||
Width = sizeof(PIXHEAD);
|
||||
|
||||
iseek(416, IL_SEEK_SET);
|
||||
Height = GetLittleUShort();
|
||||
Width = GetLittleUShort();
|
||||
iseek(424, IL_SEEK_SET);
|
||||
Bpp = (ILubyte)igetc();
|
||||
|
||||
switch (Bpp)
|
||||
{
|
||||
case 0x08:
|
||||
ilTexImage(Width, Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL);
|
||||
break;
|
||||
case 0x0E:
|
||||
ilTexImage(Width, Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
|
||||
break;
|
||||
case 0x0F:
|
||||
ilTexImage(Width, Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iseek(1024, IL_SEEK_SET);
|
||||
iread(iCurImage->Data, 1, iCurImage->SizeOfData);
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_PXR
|
||||
@@ -0,0 +1,643 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// Color Quantization Demo
|
||||
//
|
||||
// Author: Roman Podobedov
|
||||
// Email: romka@ut.ee
|
||||
// Romka Graphics: www.ut.ee/~romka
|
||||
//
|
||||
// Also in this file implemented Wu's Color Quantizer algorithm (v. 2)
|
||||
// For details see Graphics Gems vol. II, pp. 126-133
|
||||
//
|
||||
// Wu's Color Quantizer Algorithm:
|
||||
// Author: Xiaolin Wu
|
||||
// Dept. of Computer Science
|
||||
// Univ. of Western Ontario
|
||||
// London, Ontario N6A 5B7
|
||||
// wu@csd.uwo.ca
|
||||
// http://www.csd.uwo.ca/faculty/wu/
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// by Denton Woods
|
||||
// Last modified: 01/04/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_quantizer.c
|
||||
//
|
||||
// Description: Heavily modified by Denton Woods.
|
||||
//
|
||||
// 20040223 XIX : Modified so it works better with color requests < 256
|
||||
// pallete always has memory space for 256 entries
|
||||
// used so we can quant down to 255 colors then add a transparent color in there.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
|
||||
#define MAXCOLOR 256
|
||||
#define RED 2
|
||||
#define GREEN 1
|
||||
#define BLUE 0
|
||||
|
||||
typedef struct Box
|
||||
{
|
||||
ILint r0; // min value, exclusive
|
||||
ILint r1; // max value, inclusive
|
||||
ILint g0;
|
||||
ILint g1;
|
||||
ILint b0;
|
||||
ILint b1;
|
||||
ILint vol;
|
||||
} Box;
|
||||
|
||||
/* Histogram is in elements 1..HISTSIZE along each axis,
|
||||
* element 0 is for base or marginal value
|
||||
* NB: these must start out 0!
|
||||
*/
|
||||
|
||||
ILfloat gm2[33][33][33];
|
||||
ILint wt[33][33][33], mr[33][33][33], mg[33][33][33], mb[33][33][33];
|
||||
ILuint size; //image size
|
||||
ILint K; //colour look-up table size
|
||||
ILushort *Qadd;
|
||||
|
||||
|
||||
ILint WindW, WindH, WindD;
|
||||
ILint i;
|
||||
ILubyte *buffer;
|
||||
static ILint Width, Height, Depth, Comp;
|
||||
/*ILint TotalColors;
|
||||
ILint a, b;
|
||||
ILubyte *buf1, *buf2;*/
|
||||
|
||||
ILuint n2(ILint s)
|
||||
{
|
||||
ILint i;
|
||||
ILint res;
|
||||
|
||||
res = 1;
|
||||
for (i = 0; i < s; i++) {
|
||||
res = res*2;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Build 3-D color histogram of counts, r/g/b, c^2
|
||||
ILboolean Hist3d(ILubyte *Ir, ILubyte *Ig, ILubyte *Ib, ILint *vwt, ILint *vmr, ILint *vmg, ILint *vmb, ILfloat *m2)
|
||||
{
|
||||
ILint ind, r, g, b;
|
||||
ILint inr, ing, inb, table[2560];
|
||||
ILuint i;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
table[i] = i * i;
|
||||
}
|
||||
Qadd = (ILushort*)ialloc(sizeof(ILushort) * size);
|
||||
if (Qadd == NULL)
|
||||
{
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
imemclear(Qadd, sizeof(ILushort) * size);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
r = Ir[i]; g = Ig[i]; b = Ib[i];
|
||||
inr = (r>>3) + 1;
|
||||
ing = (g>>3) + 1;
|
||||
inb = (b>>3) + 1;
|
||||
Qadd[i] = ind = (inr<<10)+(inr<<6)+inr+(ing<<5)+ing+inb;
|
||||
//[inr][ing][inb]
|
||||
vwt[ind]++;
|
||||
vmr[ind] += r;
|
||||
vmg[ind] += g;
|
||||
vmb[ind] += b;
|
||||
m2[ind] += (ILfloat)(table[r]+table[g]+table[b]);
|
||||
}
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
/* At conclusion of the histogram step, we can interpret
|
||||
* wt[r][g][b] = sum over voxel of P(c)
|
||||
* mr[r][g][b] = sum over voxel of r*P(c) , similarly for mg, mb
|
||||
* m2[r][g][b] = sum over voxel of c^2*P(c)
|
||||
* Actually each of these should be divided by 'size' to give the usual
|
||||
* interpretation of P() as ranging from 0 to 1, but we needn't do that here.
|
||||
*/
|
||||
|
||||
/* We now convert histogram into moments so that we can rapidly calculate
|
||||
* the sums of the above quantities over any desired Box.
|
||||
*/
|
||||
|
||||
|
||||
// Compute cumulative moments
|
||||
void M3d(ILint *vwt, ILint *vmr, ILint *vmg, ILint *vmb, ILfloat *m2)
|
||||
{
|
||||
ILushort ind1, ind2;
|
||||
ILubyte i, r, g, b;
|
||||
ILint line, line_r, line_g, line_b, area[33], area_r[33], area_g[33], area_b[33];
|
||||
ILfloat line2, area2[33];
|
||||
|
||||
for (r = 1; r <= 32; r++) {
|
||||
for (i = 0; i <= 32; i++) {
|
||||
area2[i] = 0.0f;
|
||||
area[i]=area_r[i]=area_g[i]=area_b[i]=0;
|
||||
}
|
||||
for (g = 1; g <= 32; g++) {
|
||||
line2 = 0.0f;
|
||||
line = line_r = line_g = line_b = 0;
|
||||
for (b = 1; b <= 32; b++) {
|
||||
ind1 = (r<<10) + (r<<6) + r + (g<<5) + g + b; // [r][g][b]
|
||||
line += vwt[ind1];
|
||||
line_r += vmr[ind1];
|
||||
line_g += vmg[ind1];
|
||||
line_b += vmb[ind1];
|
||||
line2 += m2[ind1];
|
||||
area[b] += line;
|
||||
area_r[b] += line_r;
|
||||
area_g[b] += line_g;
|
||||
area_b[b] += line_b;
|
||||
area2[b] += line2;
|
||||
ind2 = ind1 - 1089; // [r-1][g][b]
|
||||
vwt[ind1] = vwt[ind2] + area[b];
|
||||
vmr[ind1] = vmr[ind2] + area_r[b];
|
||||
vmg[ind1] = vmg[ind2] + area_g[b];
|
||||
vmb[ind1] = vmb[ind2] + area_b[b];
|
||||
m2[ind1] = m2[ind2] + area2[b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Compute sum over a Box of any given statistic
|
||||
ILint Vol(Box *cube, ILint mmt[33][33][33])
|
||||
{
|
||||
return( mmt[cube->r1][cube->g1][cube->b1]
|
||||
-mmt[cube->r1][cube->g1][cube->b0]
|
||||
-mmt[cube->r1][cube->g0][cube->b1]
|
||||
+mmt[cube->r1][cube->g0][cube->b0]
|
||||
-mmt[cube->r0][cube->g1][cube->b1]
|
||||
+mmt[cube->r0][cube->g1][cube->b0]
|
||||
+mmt[cube->r0][cube->g0][cube->b1]
|
||||
-mmt[cube->r0][cube->g0][cube->b0] );
|
||||
}
|
||||
|
||||
/* The next two routines allow a slightly more efficient calculation
|
||||
* of Vol() for a proposed subBox of a given Box. The sum of Top()
|
||||
* and Bottom() is the Vol() of a subBox split in the given direction
|
||||
* and with the specified new upper bound.
|
||||
*/
|
||||
|
||||
// Compute part of Vol(cube, mmt) that doesn't depend on r1, g1, or b1
|
||||
// (depending on dir)
|
||||
ILint Bottom(Box *cube, ILubyte dir, ILint mmt[33][33][33])
|
||||
{
|
||||
switch(dir)
|
||||
{
|
||||
case RED:
|
||||
return( -mmt[cube->r0][cube->g1][cube->b1]
|
||||
+mmt[cube->r0][cube->g1][cube->b0]
|
||||
+mmt[cube->r0][cube->g0][cube->b1]
|
||||
-mmt[cube->r0][cube->g0][cube->b0] );
|
||||
break;
|
||||
case GREEN:
|
||||
return( -mmt[cube->r1][cube->g0][cube->b1]
|
||||
+mmt[cube->r1][cube->g0][cube->b0]
|
||||
+mmt[cube->r0][cube->g0][cube->b1]
|
||||
-mmt[cube->r0][cube->g0][cube->b0] );
|
||||
break;
|
||||
case BLUE:
|
||||
return( -mmt[cube->r1][cube->g1][cube->b0]
|
||||
+mmt[cube->r1][cube->g0][cube->b0]
|
||||
+mmt[cube->r0][cube->g1][cube->b0]
|
||||
-mmt[cube->r0][cube->g0][cube->b0] );
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Compute remainder of Vol(cube, mmt), substituting pos for
|
||||
// r1, g1, or b1 (depending on dir)
|
||||
ILint Top(Box *cube, ILubyte dir, ILint pos, ILint mmt[33][33][33])
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case RED:
|
||||
return( mmt[pos][cube->g1][cube->b1]
|
||||
-mmt[pos][cube->g1][cube->b0]
|
||||
-mmt[pos][cube->g0][cube->b1]
|
||||
+mmt[pos][cube->g0][cube->b0] );
|
||||
break;
|
||||
case GREEN:
|
||||
return( mmt[cube->r1][pos][cube->b1]
|
||||
-mmt[cube->r1][pos][cube->b0]
|
||||
-mmt[cube->r0][pos][cube->b1]
|
||||
+mmt[cube->r0][pos][cube->b0] );
|
||||
break;
|
||||
case BLUE:
|
||||
return( mmt[cube->r1][cube->g1][pos]
|
||||
-mmt[cube->r1][cube->g0][pos]
|
||||
-mmt[cube->r0][cube->g1][pos]
|
||||
+mmt[cube->r0][cube->g0][pos] );
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Compute the weighted variance of a Box
|
||||
// NB: as with the raw statistics, this is really the variance * size
|
||||
ILfloat Var(Box *cube)
|
||||
{
|
||||
ILfloat dr, dg, db, xx;
|
||||
|
||||
dr = (ILfloat)Vol(cube, mr);
|
||||
dg = (ILfloat)Vol(cube, mg);
|
||||
db = (ILfloat)Vol(cube, mb);
|
||||
xx = gm2[cube->r1][cube->g1][cube->b1]
|
||||
-gm2[cube->r1][cube->g1][cube->b0]
|
||||
-gm2[cube->r1][cube->g0][cube->b1]
|
||||
+gm2[cube->r1][cube->g0][cube->b0]
|
||||
-gm2[cube->r0][cube->g1][cube->b1]
|
||||
+gm2[cube->r0][cube->g1][cube->b0]
|
||||
+gm2[cube->r0][cube->g0][cube->b1]
|
||||
-gm2[cube->r0][cube->g0][cube->b0];
|
||||
|
||||
return xx - (dr*dr+dg*dg+db*db) / (ILfloat)Vol(cube, wt);
|
||||
}
|
||||
|
||||
/* We want to minimize the sum of the variances of two subBoxes.
|
||||
* The sum(c^2) terms can be ignored since their sum over both subBoxes
|
||||
* is the same (the sum for the whole Box) no matter where we split.
|
||||
* The remaining terms have a minus sign in the variance formula,
|
||||
* so we drop the minus sign and MAXIMIZE the sum of the two terms.
|
||||
*/
|
||||
|
||||
ILfloat Maximize(Box *cube, ILubyte dir, ILint first, ILint last, ILint *cut,
|
||||
ILint whole_r, ILint whole_g, ILint whole_b, ILint whole_w)
|
||||
{
|
||||
ILint half_r, half_g, half_b, half_w;
|
||||
ILint base_r, base_g, base_b, base_w;
|
||||
ILint i;
|
||||
ILfloat temp, max;
|
||||
|
||||
base_r = Bottom(cube, dir, mr);
|
||||
base_g = Bottom(cube, dir, mg);
|
||||
base_b = Bottom(cube, dir, mb);
|
||||
base_w = Bottom(cube, dir, wt);
|
||||
max = 0.0;
|
||||
*cut = -1;
|
||||
|
||||
for (i = first; i < last; ++i) {
|
||||
half_r = base_r + Top(cube, dir, i, mr);
|
||||
half_g = base_g + Top(cube, dir, i, mg);
|
||||
half_b = base_b + Top(cube, dir, i, mb);
|
||||
half_w = base_w + Top(cube, dir, i, wt);
|
||||
// Now half_x is sum over lower half of Box, if split at i
|
||||
if (half_w == 0) { // subBox could be empty of pixels!
|
||||
continue; // never split into an empty Box
|
||||
}
|
||||
else {
|
||||
temp = ((ILfloat)half_r*half_r + (ILfloat)half_g * half_g +
|
||||
(ILfloat)half_b*half_b) / half_w;
|
||||
}
|
||||
|
||||
half_r = whole_r - half_r;
|
||||
half_g = whole_g - half_g;
|
||||
half_b = whole_b - half_b;
|
||||
half_w = whole_w - half_w;
|
||||
if (half_w == 0) { // subBox could be empty of pixels!
|
||||
continue; // never split into an empty Box
|
||||
}
|
||||
else {
|
||||
temp += ((ILfloat)half_r*half_r + (ILfloat)half_g * half_g +
|
||||
(ILfloat)half_b*half_b) / half_w;
|
||||
}
|
||||
|
||||
if (temp > max) {
|
||||
max = temp;
|
||||
*cut = i;
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
ILint Cut(Box *set1, Box *set2)
|
||||
{
|
||||
ILubyte dir;
|
||||
ILint cutr, cutg, cutb;
|
||||
ILfloat maxr, maxg, maxb;
|
||||
ILint whole_r, whole_g, whole_b, whole_w;
|
||||
|
||||
whole_r = Vol(set1, mr);
|
||||
whole_g = Vol(set1, mg);
|
||||
whole_b = Vol(set1, mb);
|
||||
whole_w = Vol(set1, wt);
|
||||
|
||||
maxr = Maximize(set1, RED, set1->r0+1, set1->r1, &cutr, whole_r, whole_g, whole_b, whole_w);
|
||||
maxg = Maximize(set1, GREEN, set1->g0+1, set1->g1, &cutg, whole_r, whole_g, whole_b, whole_w);
|
||||
maxb = Maximize(set1, BLUE, set1->b0+1, set1->b1, &cutb, whole_r, whole_g, whole_b, whole_w);
|
||||
|
||||
if ((maxr >= maxg) && (maxr >= maxb)) {
|
||||
dir = RED;
|
||||
if (cutr < 0)
|
||||
return 0; // can't split the Box
|
||||
}
|
||||
else if ((maxg >= maxr) && (maxg >= maxb))
|
||||
dir = GREEN;
|
||||
else
|
||||
dir = BLUE;
|
||||
|
||||
set2->r1 = set1->r1;
|
||||
set2->g1 = set1->g1;
|
||||
set2->b1 = set1->b1;
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case RED:
|
||||
set2->r0 = set1->r1 = cutr;
|
||||
set2->g0 = set1->g0;
|
||||
set2->b0 = set1->b0;
|
||||
break;
|
||||
case GREEN:
|
||||
set2->g0 = set1->g1 = cutg;
|
||||
set2->r0 = set1->r0;
|
||||
set2->b0 = set1->b0;
|
||||
break;
|
||||
case BLUE:
|
||||
set2->b0 = set1->b1 = cutb;
|
||||
set2->r0 = set1->r0;
|
||||
set2->g0 = set1->g0;
|
||||
break;
|
||||
}
|
||||
|
||||
set1->vol = (set1->r1-set1->r0) * (set1->g1-set1->g0) * (set1->b1-set1->b0);
|
||||
set2->vol = (set2->r1-set2->r0) * (set2->g1-set2->g0) * (set2->b1-set2->b0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void Mark(struct Box *cube, int label, unsigned char *tag)
|
||||
{
|
||||
ILint r, g, b;
|
||||
|
||||
for (r = cube->r0 + 1; r <= cube->r1; r++) {
|
||||
for (g = cube->g0 + 1; g <= cube->g1; g++) {
|
||||
for (b = cube->b0 + 1; b <= cube->b1; b++) {
|
||||
tag[(r<<10) + (r<<6) + r + (g<<5) + g + b] = label;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILimage *iQuantizeImage(ILimage *Image, ILuint NumCols)
|
||||
{
|
||||
Box cube[MAXCOLOR];
|
||||
ILubyte *tag = NULL;
|
||||
ILubyte lut_r[MAXCOLOR], lut_g[MAXCOLOR], lut_b[MAXCOLOR];
|
||||
ILint next;
|
||||
ILint weight;
|
||||
ILuint k;
|
||||
ILfloat vv[MAXCOLOR], temp;
|
||||
//ILint color_num;
|
||||
ILubyte *NewData = NULL, *Palette = NULL;
|
||||
ILimage *TempImage = NULL, *NewImage = NULL;
|
||||
ILubyte *Ir = NULL, *Ig = NULL, *Ib = NULL;
|
||||
|
||||
ILint num_alloced_colors; // number of colors we allocated space for in palette, as NumCols but will not be less than 256
|
||||
|
||||
num_alloced_colors=NumCols;
|
||||
if(num_alloced_colors<256) { num_alloced_colors=256; }
|
||||
|
||||
|
||||
NewImage = iCurImage;
|
||||
iCurImage = Image;
|
||||
TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
|
||||
iCurImage = NewImage;
|
||||
|
||||
|
||||
|
||||
if (TempImage == NULL)
|
||||
return NULL;
|
||||
|
||||
buffer = Image->Data;
|
||||
WindW = Width = Image->Width;
|
||||
WindH = Height = Image->Height;
|
||||
WindD = Depth = Image->Depth;
|
||||
Comp = Image->Bpp;
|
||||
Qadd = NULL;
|
||||
|
||||
//color_num = ImagePrecalculate(Image);
|
||||
|
||||
NewData = (ILubyte*)ialloc(Image->Width * Image->Height * Image->Depth);
|
||||
Palette = (ILubyte*)ialloc(3 * num_alloced_colors);
|
||||
if (!NewData || !Palette) {
|
||||
ifree(NewData);
|
||||
ifree(Palette);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Ir = (ILubyte*)ialloc(Width * Height * Depth);
|
||||
Ig = (ILubyte*)ialloc(Width * Height * Depth);
|
||||
Ib = (ILubyte*)ialloc(Width * Height * Depth);
|
||||
if (!Ir || !Ig || !Ib) {
|
||||
ifree(Ir);
|
||||
ifree(Ig);
|
||||
ifree(Ib);
|
||||
ifree(NewData);
|
||||
ifree(Palette);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = Width * Height * Depth;
|
||||
|
||||
#ifdef ALTIVEC_GCC
|
||||
register ILuint v_size = size>>4;
|
||||
register ILuint pos = 0;
|
||||
v_size = v_size /3;
|
||||
register vector unsigned char d0,d1,d2;
|
||||
register vector unsigned char red[3],blu[3],green[3];
|
||||
|
||||
register union{
|
||||
vector unsigned char vec;
|
||||
vector unsigned int load;
|
||||
} mask_1, mask_2, mask_3;
|
||||
|
||||
mask_1.load = (vector unsigned int){0xFF0000FF,0x0000FF00,0x00FF0000,0xFF0000FF};
|
||||
mask_2.load = (vector unsigned int){0x00FF0000,0xFF0000FF,0x0000FF00,0x00FF0000};
|
||||
mask_2.load = (vector unsigned int){0x0000FF00,0x00FF0000,0xFF0000FF,0x0000FF00};
|
||||
|
||||
while( v_size >= 0 ) {
|
||||
d0 = vec_ld(pos,TempImage->Data);
|
||||
d1 = vec_ld(pos+16,TempImage->Data);
|
||||
d2 = vec_ld(pos+32,TempImage->Data);
|
||||
|
||||
red[0] = vec_and(d0,mask_1.vec);
|
||||
green[0] = vec_and(d0,mask_2.vec);
|
||||
blu[0] = vec_and(d0,mask_3.vec);
|
||||
|
||||
red[1] = vec_and(d1,mask_3.vec);
|
||||
green[1] = vec_and(d1,mask_1.vec);
|
||||
blu[1] = vec_and(d1,mask_2.vec);
|
||||
|
||||
red[2] = vec_and(d2,mask_2.vec);
|
||||
green[2] = vec_and(d2,mask_3.vec);
|
||||
blu[2] = vec_and(d2,mask_1.vec);
|
||||
|
||||
vec_st(red[0],pos,Ir);
|
||||
vec_st(red[1],pos+16,Ir);
|
||||
vec_st(red[2],pos+32,Ir);
|
||||
|
||||
vec_st(blu[0],pos,Ib);
|
||||
vec_st(blu[1],pos+16,Ib);
|
||||
vec_st(blu[2],pos+32,Ib);
|
||||
|
||||
vec_st(green[0],pos,Ig);
|
||||
vec_st(green[1],pos+16,Ig);
|
||||
vec_st(green[2],pos+32,Ig);
|
||||
|
||||
pos += 48;
|
||||
}
|
||||
size -= pos;
|
||||
#endif
|
||||
|
||||
for (k = 0; k < size; k++) {
|
||||
Ir[k] = TempImage->Data[k * 3];
|
||||
Ig[k] = TempImage->Data[k * 3 + 1];
|
||||
Ib[k] = TempImage->Data[k * 3 + 2];
|
||||
}
|
||||
|
||||
#ifdef ALTIVEC_GCC
|
||||
size = Width * Height * Depth;
|
||||
#endif
|
||||
|
||||
// Set new colors number
|
||||
K = NumCols;
|
||||
|
||||
if (K <= 256) {
|
||||
// Begin Wu's color quantization algorithm
|
||||
|
||||
// May have "leftovers" from a previous run.
|
||||
|
||||
imemclear(gm2, 33 * 33 * 33 * sizeof(ILfloat));
|
||||
imemclear(wt, 33 * 33 * 33 * sizeof(ILint));
|
||||
imemclear(mr, 33 * 33 * 33 * sizeof(ILint));
|
||||
imemclear(mg, 33 * 33 * 33 * sizeof(ILint));
|
||||
imemclear(mb, 33 * 33 * 33 * sizeof(ILint));
|
||||
|
||||
if (!Hist3d(Ir, Ig, Ib, (ILint*)wt, (ILint*)mr, (ILint*)mg, (ILint*)mb, (ILfloat*)gm2))
|
||||
goto error_label;
|
||||
|
||||
M3d((ILint*)wt, (ILint*)mr, (ILint*)mg, (ILint*)mb, (ILfloat*)gm2);
|
||||
|
||||
cube[0].r0 = cube[0].g0 = cube[0].b0 = 0;
|
||||
cube[0].r1 = cube[0].g1 = cube[0].b1 = 32;
|
||||
next = 0;
|
||||
for (i = 1; i < K; ++i) {
|
||||
if (Cut(&cube[next], &cube[i])) { // volume test ensures we won't try to cut one-cell Box */
|
||||
vv[next] = (cube[next].vol>1) ? Var(&cube[next]) : 0.0f;
|
||||
vv[i] = (cube[i].vol>1) ? Var(&cube[i]) : 0.0f;
|
||||
}
|
||||
else {
|
||||
vv[next] = 0.0; // don't try to split this Box again
|
||||
i--; // didn't create Box i
|
||||
}
|
||||
next = 0;
|
||||
temp = vv[0];
|
||||
for (k = 1; (ILint)k <= i; ++k) {
|
||||
if (vv[k] > temp) {
|
||||
temp = vv[k]; next = k;
|
||||
}
|
||||
}
|
||||
|
||||
if (temp <= 0.0) {
|
||||
K = i+1;
|
||||
// Only got K Boxes
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tag = (ILubyte*)ialloc(33 * 33 * 33 * sizeof(ILubyte));
|
||||
if (tag == NULL)
|
||||
goto error_label;
|
||||
for (k = 0; (ILint)k < K; k++) {
|
||||
Mark(&cube[k], k, tag);
|
||||
weight = Vol(&cube[k], wt);
|
||||
if (weight) {
|
||||
lut_r[k] = (ILubyte)(Vol(&cube[k], mr) / weight);
|
||||
lut_g[k] = (ILubyte)(Vol(&cube[k], mg) / weight);
|
||||
lut_b[k] = (ILubyte)(Vol(&cube[k], mb) / weight);
|
||||
}
|
||||
else {
|
||||
// Bogus Box
|
||||
lut_r[k] = lut_g[k] = lut_b[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < (ILint)size; i++) {
|
||||
NewData[i] = tag[Qadd[i]];
|
||||
}
|
||||
ifree(tag);
|
||||
ifree(Qadd);
|
||||
|
||||
for (k = 0; k < NumCols; k++) {
|
||||
Palette[k * 3] = lut_b[k];
|
||||
Palette[k * 3 + 1] = lut_g[k];
|
||||
Palette[k * 3 + 2] = lut_r[k];
|
||||
}
|
||||
}
|
||||
else { // If colors more than 256
|
||||
// Begin Octree quantization
|
||||
//Quant_Octree(Image->Width, Image->Height, Image->Bpp, buffer2, NewData, Palette, K);
|
||||
ilSetError(IL_INTERNAL_ERROR); // Can't get much more specific than this.
|
||||
goto error_label;
|
||||
}
|
||||
|
||||
ifree(Ig);
|
||||
ifree(Ib);
|
||||
ifree(Ir);
|
||||
ilCloseImage(TempImage);
|
||||
|
||||
NewImage = (ILimage*)icalloc(sizeof(ILimage), 1);
|
||||
if (NewImage == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ilCopyImageAttr(NewImage, Image);
|
||||
NewImage->Bpp = 1;
|
||||
NewImage->Bps = Image->Width;
|
||||
NewImage->SizeOfPlane = NewImage->Bps * Image->Height;
|
||||
NewImage->SizeOfData = NewImage->SizeOfPlane;
|
||||
NewImage->Format = IL_COLOUR_INDEX;
|
||||
NewImage->Type = IL_UNSIGNED_BYTE;
|
||||
|
||||
NewImage->Pal.Palette = Palette;
|
||||
NewImage->Pal.PalSize = 256 * 3;
|
||||
NewImage->Pal.PalType = IL_PAL_BGR24;
|
||||
NewImage->Data = NewData;
|
||||
|
||||
return NewImage;
|
||||
|
||||
error_label:
|
||||
ifree(NewData);
|
||||
ifree(Palette);
|
||||
ifree(Ig);
|
||||
ifree(Ib);
|
||||
ifree(Ir);
|
||||
ifree(tag);
|
||||
ifree(Qadd);
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_raw.c
|
||||
//
|
||||
// Description: "Raw" file functions
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_RAW
|
||||
|
||||
|
||||
ILboolean iLoadRawInternal(void);
|
||||
ILboolean iSaveRawInternal(void);
|
||||
|
||||
|
||||
//! Reads a raw file
|
||||
ILboolean ilLoadRaw(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE RawFile;
|
||||
ILboolean bRaw = IL_FALSE;
|
||||
|
||||
// No need to check for raw
|
||||
/*if (!iCheckExtension(FileName, "raw")) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bRaw;
|
||||
}*/
|
||||
|
||||
RawFile = iopenr(FileName);
|
||||
if (RawFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bRaw;
|
||||
}
|
||||
|
||||
bRaw = ilLoadRawF(RawFile);
|
||||
icloser(RawFile);
|
||||
|
||||
return bRaw;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened raw file
|
||||
ILboolean ilLoadRawF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadRawInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a raw memory "lump"
|
||||
ILboolean ilLoadRawL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadRawInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function to load a raw image
|
||||
ILboolean iLoadRawInternal()
|
||||
{
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
iCurImage->Width = GetLittleUInt();
|
||||
|
||||
iCurImage->Height = GetLittleUInt();
|
||||
|
||||
iCurImage->Depth = GetLittleUInt();
|
||||
|
||||
iCurImage->Bpp = (ILubyte)igetc();
|
||||
|
||||
if (iread(&iCurImage->Bpc, 1, 1) != 1)
|
||||
return IL_FALSE;
|
||||
|
||||
if (!ilTexImage(iCurImage->Width, iCurImage->Height, iCurImage->Depth, iCurImage->Bpp, 0, ilGetTypeBpc(iCurImage->Bpc), NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
|
||||
// Tries to read the correct amount of data
|
||||
if (iread(iCurImage->Data, 1, iCurImage->SizeOfData) < iCurImage->SizeOfData)
|
||||
return IL_FALSE;
|
||||
|
||||
if (ilIsEnabled(IL_ORIGIN_SET)) {
|
||||
iCurImage->Origin = ilGetInteger(IL_ORIGIN_MODE);
|
||||
}
|
||||
else {
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
}
|
||||
|
||||
if (iCurImage->Bpp == 1)
|
||||
iCurImage->Format = IL_LUMINANCE;
|
||||
else if (iCurImage->Bpp == 3)
|
||||
iCurImage->Format = IL_RGB;
|
||||
else // 4
|
||||
iCurImage->Format = IL_RGBA;
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Raw file
|
||||
ILboolean ilSaveRaw(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE RawFile;
|
||||
ILuint RawSize;
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
RawFile = iopenw(FileName);
|
||||
if (RawFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
RawSize = ilSaveRawF(RawFile);
|
||||
iclosew(RawFile);
|
||||
|
||||
if (RawSize == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes Raw to an already-opened file
|
||||
ILuint ilSaveRawF(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputFile(File);
|
||||
Pos = itellw();
|
||||
if (iSaveRawInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes Raw to a memory "lump"
|
||||
ILuint ilSaveRawL(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputLump(Lump, Size);
|
||||
Pos = itellw();
|
||||
if (iSaveRawInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the raw data.
|
||||
ILboolean iSaveRawInternal()
|
||||
{
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
SaveLittleUInt(iCurImage->Width);
|
||||
SaveLittleUInt(iCurImage->Height);
|
||||
SaveLittleUInt(iCurImage->Depth);
|
||||
iputc(iCurImage->Bpp);
|
||||
iputc(iCurImage->Bpc);
|
||||
iwrite(iCurImage->Data, 1, iCurImage->SizeOfData);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_RAW
|
||||
@@ -0,0 +1,121 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/rawdata.c
|
||||
//
|
||||
// Description: "Raw" file functions
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
//#ifndef IL_NO_DATA
|
||||
#include "il_manip.h"
|
||||
|
||||
|
||||
ILboolean iLoadDataInternal(ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp);
|
||||
|
||||
|
||||
//! Reads a raw data file
|
||||
ILboolean ILAPIENTRY ilLoadData(ILconst_string FileName, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp)
|
||||
{
|
||||
ILHANDLE RawFile;
|
||||
ILboolean bRaw = IL_FALSE;
|
||||
|
||||
// No need to check for raw data
|
||||
/*if (!iCheckExtension(FileName, "raw")) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bRaw;
|
||||
}*/
|
||||
|
||||
RawFile = iopenr(FileName);
|
||||
if (RawFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bRaw;
|
||||
}
|
||||
|
||||
bRaw = ilLoadDataF(RawFile, Width, Height, Depth, Bpp);
|
||||
icloser(RawFile);
|
||||
|
||||
return bRaw;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened raw data file
|
||||
ILboolean ILAPIENTRY ilLoadDataF(ILHANDLE File, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadDataInternal(Width, Height, Depth, Bpp);
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a raw data memory "lump"
|
||||
ILboolean ILAPIENTRY ilLoadDataL(void *Lump, ILuint Size, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadDataInternal(Width, Height, Depth, Bpp);
|
||||
}
|
||||
|
||||
|
||||
// Internal function to load a raw data image
|
||||
ILboolean iLoadDataInternal(ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp)
|
||||
{
|
||||
if (iCurImage == NULL || ((Bpp != 1) && (Bpp != 3) && (Bpp != 4))) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!ilTexImage(Width, Height, Depth, Bpp, 0, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
// Tries to read the correct amount of data
|
||||
if (iread(iCurImage->Data, Width * Height * Depth * Bpp, 1) != 1)
|
||||
return IL_FALSE;
|
||||
|
||||
if (iCurImage->Bpp == 1)
|
||||
iCurImage->Format = IL_LUMINANCE;
|
||||
else if (iCurImage->Bpp == 3)
|
||||
iCurImage->Format = IL_RGB;
|
||||
else // 4
|
||||
iCurImage->Format = IL_RGBA;
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
//! Save the current image to FileName as raw data
|
||||
ILboolean ILAPIENTRY ilSaveData(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE DataFile;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
DataFile = iopenr(FileName);
|
||||
if (DataFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iwrite(iCurImage->Data, 1, iCurImage->SizeOfData);
|
||||
icloser(DataFile);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//#endif//IL_NO_DATA
|
||||
@@ -0,0 +1,434 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2008 by Denton Woods
|
||||
// Last modified: 11/07/2008
|
||||
//
|
||||
// Filename: src-IL/src/il_register.c
|
||||
//
|
||||
// Description: Allows the caller to specify user-defined callback functions
|
||||
// to open files DevIL does not support, to parse files
|
||||
// differently, or anything else a person can think up.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#include "il_register.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// Linked lists of registered formats
|
||||
iFormatL *LoadProcs = NULL;
|
||||
iFormatS *SaveProcs = NULL;
|
||||
|
||||
|
||||
ILboolean ILAPIENTRY ilRegisterLoad(ILconst_string Ext, IL_LOADPROC Load) {
|
||||
iFormatL *TempNode, *NewNode;
|
||||
|
||||
TempNode = LoadProcs;
|
||||
if (TempNode != NULL) {
|
||||
while (TempNode->Next != NULL) {
|
||||
TempNode = TempNode->Next;
|
||||
if (!iStrCmp(TempNode->Ext, Ext)) { // already registered
|
||||
return IL_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NewNode = (iFormatL*)ialloc(sizeof(iFormatL));
|
||||
if (NewNode == NULL) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (LoadProcs == NULL) {
|
||||
LoadProcs = NewNode;
|
||||
}
|
||||
else {
|
||||
TempNode->Next = NewNode;
|
||||
}
|
||||
|
||||
NewNode->Ext = ilStrDup(Ext);
|
||||
NewNode->Load = Load;
|
||||
NewNode->Next = NULL;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ILAPIENTRY ilRegisterSave(ILconst_string Ext, IL_SAVEPROC Save)
|
||||
{
|
||||
iFormatS *TempNode, *NewNode;
|
||||
|
||||
TempNode = SaveProcs;
|
||||
if (TempNode != NULL) {
|
||||
while (TempNode->Next != NULL) {
|
||||
TempNode = TempNode->Next;
|
||||
if (!iStrCmp(TempNode->Ext, Ext)) { // already registered
|
||||
return IL_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NewNode = (iFormatS*)ialloc(sizeof(iFormatL));
|
||||
if (NewNode == NULL) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (SaveProcs == NULL) {
|
||||
SaveProcs = NewNode;
|
||||
}
|
||||
else {
|
||||
TempNode->Next = NewNode;
|
||||
}
|
||||
|
||||
NewNode->Ext = ilStrDup(Ext);
|
||||
NewNode->Save = Save;
|
||||
NewNode->Next = NULL;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Unregisters a load extension - doesn't have to be called.
|
||||
ILboolean ILAPIENTRY ilRemoveLoad(ILconst_string Ext)
|
||||
{
|
||||
iFormatL *TempNode = LoadProcs, *PrevNode = NULL;
|
||||
|
||||
while (TempNode != NULL) {
|
||||
if (!iStrCmp(Ext, TempNode->Ext)) {
|
||||
if (PrevNode == NULL) { // first node in the list
|
||||
LoadProcs = TempNode->Next;
|
||||
ifree((void*)TempNode->Ext);
|
||||
ifree(TempNode);
|
||||
}
|
||||
else {
|
||||
PrevNode->Next = TempNode->Next;
|
||||
ifree((void*)TempNode->Ext);
|
||||
ifree(TempNode);
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
PrevNode = TempNode;
|
||||
TempNode = TempNode->Next;
|
||||
}
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
//! Unregisters a save extension - doesn't have to be called.
|
||||
ILboolean ILAPIENTRY ilRemoveSave(ILconst_string Ext)
|
||||
{
|
||||
iFormatS *TempNode = SaveProcs, *PrevNode = NULL;
|
||||
|
||||
while (TempNode != NULL) {
|
||||
if (!iStrCmp(Ext, TempNode->Ext)) {
|
||||
if (PrevNode == NULL) { // first node in the list
|
||||
SaveProcs = TempNode->Next;
|
||||
ifree((void*)TempNode->Ext);
|
||||
ifree(TempNode);
|
||||
}
|
||||
else {
|
||||
PrevNode->Next = TempNode->Next;
|
||||
ifree((void*)TempNode->Ext);
|
||||
ifree(TempNode);
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
PrevNode = TempNode;
|
||||
TempNode = TempNode->Next;
|
||||
}
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// Automatically removes all registered formats.
|
||||
void ilRemoveRegistered()
|
||||
{
|
||||
iFormatL *TempNodeL = LoadProcs;
|
||||
iFormatS *TempNodeS = SaveProcs;
|
||||
|
||||
while (LoadProcs != NULL) {
|
||||
TempNodeL = LoadProcs->Next;
|
||||
ifree((void*)LoadProcs->Ext);
|
||||
ifree(LoadProcs);
|
||||
LoadProcs = TempNodeL;
|
||||
}
|
||||
|
||||
while (SaveProcs != NULL) {
|
||||
TempNodeS = SaveProcs->Next;
|
||||
ifree((void*)SaveProcs->Ext);
|
||||
ifree(SaveProcs);
|
||||
SaveProcs = TempNodeS;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILboolean iRegisterLoad(ILconst_string FileName)
|
||||
{
|
||||
iFormatL *TempNode = LoadProcs;
|
||||
ILstring Ext = iGetExtension(FileName);
|
||||
ILenum Error;
|
||||
|
||||
if (!Ext)
|
||||
return IL_FALSE;
|
||||
|
||||
while (TempNode != NULL) {
|
||||
if (!iStrCmp(Ext, TempNode->Ext)) {
|
||||
Error = TempNode->Load(FileName);
|
||||
if (Error == IL_NO_ERROR || Error == 0) { // 0 and IL_NO_ERROR are both valid.
|
||||
return IL_TRUE;
|
||||
}
|
||||
else {
|
||||
ilSetError(Error);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
TempNode = TempNode->Next;
|
||||
}
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean iRegisterSave(ILconst_string FileName)
|
||||
{
|
||||
iFormatS *TempNode = SaveProcs;
|
||||
ILstring Ext = iGetExtension(FileName);
|
||||
ILenum Error;
|
||||
|
||||
if (!Ext)
|
||||
return IL_FALSE;
|
||||
|
||||
while (TempNode != NULL) {
|
||||
if (!iStrCmp(Ext, TempNode->Ext)) {
|
||||
Error = TempNode->Save(FileName);
|
||||
if (Error == IL_NO_ERROR || Error == 0) { // 0 and IL_NO_ERROR are both valid.
|
||||
return IL_TRUE;
|
||||
}
|
||||
else {
|
||||
ilSetError(Error);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
TempNode = TempNode->Next;
|
||||
}
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// "Reporting" functions
|
||||
//
|
||||
|
||||
void ILAPIENTRY ilRegisterOrigin(ILenum Origin)
|
||||
{
|
||||
switch (Origin)
|
||||
{
|
||||
case IL_ORIGIN_LOWER_LEFT:
|
||||
case IL_ORIGIN_UPPER_LEFT:
|
||||
iCurImage->Origin = Origin;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INVALID_ENUM);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void ILAPIENTRY ilRegisterFormat(ILenum Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case IL_COLOUR_INDEX:
|
||||
case IL_RGB:
|
||||
case IL_RGBA:
|
||||
case IL_BGR:
|
||||
case IL_BGRA:
|
||||
case IL_LUMINANCE:
|
||||
case IL_LUMINANCE_ALPHA:
|
||||
iCurImage->Format = Format;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INVALID_ENUM);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ILAPIENTRY ilRegisterNumFaces(ILuint Num)
|
||||
{
|
||||
ILimage *Next, *Prev;
|
||||
|
||||
ilBindImage(ilGetCurName()); // Make sure the current image is actually bound.
|
||||
ilCloseImage(iCurImage->Faces); // Close any current mipmaps.
|
||||
|
||||
iCurImage->Faces = NULL;
|
||||
if (Num == 0) // Just gets rid of all the mipmaps.
|
||||
return IL_TRUE;
|
||||
|
||||
iCurImage->Faces = ilNewImage(1, 1, 1, 1, 1);
|
||||
if (iCurImage->Faces == NULL)
|
||||
return IL_FALSE;
|
||||
Next = iCurImage->Faces;
|
||||
Num--;
|
||||
|
||||
while (Num) {
|
||||
Next->Faces = ilNewImage(1, 1, 1, 1, 1);
|
||||
if (Next->Faces == NULL) {
|
||||
// Clean up before we error out.
|
||||
Prev = iCurImage->Faces;
|
||||
while (Prev) {
|
||||
Next = Prev->Faces;
|
||||
ilCloseImage(Prev);
|
||||
Prev = Next;
|
||||
}
|
||||
return IL_FALSE;
|
||||
}
|
||||
Next = Next->Faces;
|
||||
Num--;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ILAPIENTRY ilRegisterMipNum(ILuint Num)
|
||||
{
|
||||
ILimage *Next, *Prev;
|
||||
|
||||
ilBindImage(ilGetCurName()); // Make sure the current image is actually bound.
|
||||
ilCloseImage(iCurImage->Mipmaps); // Close any current mipmaps.
|
||||
|
||||
iCurImage->Mipmaps = NULL;
|
||||
if (Num == 0) // Just gets rid of all the mipmaps.
|
||||
return IL_TRUE;
|
||||
|
||||
iCurImage->Mipmaps = ilNewImage(1, 1, 1, 1, 1);
|
||||
if (iCurImage->Mipmaps == NULL)
|
||||
return IL_FALSE;
|
||||
Next = iCurImage->Mipmaps;
|
||||
Num--;
|
||||
|
||||
while (Num) {
|
||||
Next->Next = ilNewImage(1, 1, 1, 1, 1);
|
||||
if (Next->Next == NULL) {
|
||||
// Clean up before we error out.
|
||||
Prev = iCurImage->Mipmaps;
|
||||
while (Prev) {
|
||||
Next = Prev->Next;
|
||||
ilCloseImage(Prev);
|
||||
Prev = Next;
|
||||
}
|
||||
return IL_FALSE;
|
||||
}
|
||||
Next = Next->Next;
|
||||
Num--;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ILAPIENTRY ilRegisterNumImages(ILuint Num)
|
||||
{
|
||||
ILimage *Next, *Prev;
|
||||
|
||||
ilBindImage(ilGetCurName()); // Make sure the current image is actually bound.
|
||||
ilCloseImage(iCurImage->Next); // Close any current "next" images.
|
||||
|
||||
iCurImage->Next = NULL;
|
||||
if (Num == 0) // Just gets rid of all the "next" images.
|
||||
return IL_TRUE;
|
||||
|
||||
iCurImage->Next = ilNewImage(1, 1, 1, 1, 1);
|
||||
if (iCurImage->Next == NULL)
|
||||
return IL_FALSE;
|
||||
Next = iCurImage->Next;
|
||||
Num--;
|
||||
|
||||
while (Num) {
|
||||
Next->Next = ilNewImage(1, 1, 1, 1, 1);
|
||||
if (Next->Next == NULL) {
|
||||
// Clean up before we error out.
|
||||
Prev = iCurImage->Next;
|
||||
while (Prev) {
|
||||
Next = Prev->Next;
|
||||
ilCloseImage(Prev);
|
||||
Prev = Next;
|
||||
}
|
||||
return IL_FALSE;
|
||||
}
|
||||
Next = Next->Next;
|
||||
Num--;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
void ILAPIENTRY ilRegisterType(ILenum Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case IL_BYTE:
|
||||
case IL_UNSIGNED_BYTE:
|
||||
case IL_SHORT:
|
||||
case IL_UNSIGNED_SHORT:
|
||||
case IL_INT:
|
||||
case IL_UNSIGNED_INT:
|
||||
case IL_FLOAT:
|
||||
case IL_DOUBLE:
|
||||
iCurImage->Type = Type;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INVALID_ENUM);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void ILAPIENTRY ilRegisterPal(void *Pal, ILuint Size, ILenum Type)
|
||||
{
|
||||
if (!iCurImage->Pal.Palette || !iCurImage->Pal.PalSize || iCurImage->Pal.PalType != IL_PAL_NONE) {
|
||||
ifree(iCurImage->Pal.Palette);
|
||||
}
|
||||
|
||||
iCurImage->Pal.PalSize = Size;
|
||||
iCurImage->Pal.PalType = Type;
|
||||
iCurImage->Pal.Palette = (ILubyte*)ialloc(Size);
|
||||
if (iCurImage->Pal.Palette == NULL)
|
||||
return;
|
||||
|
||||
if (Pal != NULL) {
|
||||
memcpy(iCurImage->Pal.Palette, Pal, Size);
|
||||
}
|
||||
else {
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILboolean ILAPIENTRY ilSetDuration(ILuint Duration)
|
||||
{
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iCurImage->Duration = Duration;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Description: Functions for run-length encoding
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// RLE code from TrueVision's TGA sample code available as Tgautils.zip at
|
||||
// ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/PC.Version
|
||||
|
||||
#define IL_RLE_C
|
||||
|
||||
#include "il_internal.h"
|
||||
#include "il_rle.h"
|
||||
|
||||
ILboolean ilRleCompressLine(ILubyte *p, ILuint n, ILubyte bpp,
|
||||
ILubyte *q, ILuint *DestWidth, ILenum CompressMode) {
|
||||
|
||||
ILint DiffCount; // pixel count until two identical
|
||||
ILint SameCount; // number of identical adjacent pixels
|
||||
ILint RLEBufSize = 0; // count of number of bytes encoded
|
||||
ILint MaxRun;
|
||||
const ILint bmp_pad_to_even = 1 - ((ILint)q - *DestWidth) % 2;
|
||||
|
||||
switch( CompressMode ) {
|
||||
case IL_TGACOMP:
|
||||
MaxRun = TGA_MAX_RUN;
|
||||
break;
|
||||
case IL_SGICOMP:
|
||||
MaxRun = SGI_MAX_RUN;
|
||||
break;
|
||||
case IL_BMPCOMP:
|
||||
MaxRun = BMP_MAX_RUN;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
while( n > 0 ) {
|
||||
// Analyze pixels
|
||||
DiffCount = CountDiffPixels(p, bpp, (ILint)n > MaxRun ? MaxRun : n);
|
||||
SameCount = CountSamePixels(p, bpp, (ILint)n > MaxRun ? MaxRun : n);
|
||||
|
||||
if( CompressMode == IL_BMPCOMP ) {
|
||||
ILint remaining_data = n - DiffCount - SameCount;
|
||||
if( remaining_data < 3 ) { // check if the run has gone near the end
|
||||
// no absolute run can be done
|
||||
// complete the line adding 0x01 + pixel, for each pixel
|
||||
while( remaining_data > 0 ) {
|
||||
*q++ = 0x01;
|
||||
*q++ = *p++;
|
||||
remaining_data--;
|
||||
}
|
||||
DiffCount = 0;
|
||||
SameCount = 0;
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( DiffCount > 0 ) { // create a raw packet (bmp absolute run)
|
||||
switch(CompressMode) {
|
||||
case IL_TGACOMP:
|
||||
*q++ = (ILbyte)(DiffCount - 1);
|
||||
break;
|
||||
case IL_BMPCOMP:
|
||||
*q++ = 0x00; RLEBufSize++;
|
||||
*q++ = (ILbyte)DiffCount;
|
||||
break;
|
||||
case IL_SGICOMP:
|
||||
*q++ = (ILbyte)(DiffCount | 0x80);
|
||||
break;
|
||||
}
|
||||
n -= DiffCount;
|
||||
RLEBufSize += (DiffCount * bpp) + 1;
|
||||
|
||||
while( DiffCount > 0 ) {
|
||||
switch(bpp) {
|
||||
case 4: *q++ = *p++;
|
||||
case 3: *q++ = *p++;
|
||||
case 2: *q++ = *p++;
|
||||
case 1: *q++ = *p++;
|
||||
}
|
||||
DiffCount--;
|
||||
}
|
||||
|
||||
if( CompressMode == IL_BMPCOMP ) {
|
||||
if( (size_t)q % 2 == bmp_pad_to_even ) {
|
||||
*q++ = 0x00; // insert padding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( SameCount > 1 ) { // create a RLE packet
|
||||
switch(CompressMode) {
|
||||
case IL_TGACOMP:
|
||||
*q++ = (ILbyte)((SameCount - 1) | 0x80);
|
||||
break;
|
||||
case IL_SGICOMP:
|
||||
case IL_BMPCOMP:
|
||||
*q++ = (ILbyte)(SameCount);
|
||||
break;
|
||||
}
|
||||
n -= SameCount;
|
||||
RLEBufSize += bpp + 1;
|
||||
p += (SameCount - 1) * bpp;
|
||||
*q++ = *p++;
|
||||
switch(bpp) {
|
||||
case 4: *q++ = *p++;
|
||||
case 3: *q++ = *p++;
|
||||
case 2: *q++ = *p++;
|
||||
case 1: *q++ = *p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write line termination code
|
||||
switch(CompressMode) {
|
||||
case IL_SGICOMP:
|
||||
++RLEBufSize;
|
||||
*q++ = 0;
|
||||
break;
|
||||
case IL_BMPCOMP:
|
||||
*q++ = 0x00; RLEBufSize++;
|
||||
*q++ = 0x00; RLEBufSize++;
|
||||
break;
|
||||
}
|
||||
*DestWidth = RLEBufSize;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Compresses an entire image using run-length encoding
|
||||
ILuint ilRleCompress(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp,
|
||||
ILubyte *Dest, ILenum CompressMode, ILuint *ScanTable) {
|
||||
ILuint DestW = 0, i, j, LineLen, Bps = Width * Bpp, SizeOfPlane = Width * Height * Bpp;
|
||||
|
||||
if( ScanTable )
|
||||
imemclear(ScanTable,Depth*Height*sizeof(ILuint));
|
||||
for( j = 0; j < Depth; j++ ) {
|
||||
for( i = 0; i < Height; i++ ) {
|
||||
if( ScanTable )
|
||||
*ScanTable++ = DestW;
|
||||
ilRleCompressLine(Data + j * SizeOfPlane + i * Bps, Width, Bpp, Dest + DestW, &LineLen, CompressMode);
|
||||
DestW += LineLen;
|
||||
}
|
||||
}
|
||||
|
||||
if( CompressMode == IL_BMPCOMP ) { // add end of image
|
||||
*(Data+DestW) = 0x00; DestW++;
|
||||
*(Data+DestW) = 0x01; DestW++;
|
||||
}
|
||||
|
||||
return DestW;
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 02/15/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_rot.c
|
||||
//
|
||||
// Description: Reads from a Homeworld 2 - Relic Texture (.rot) file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// @TODO:
|
||||
// Note: I am not certain about which is DXT3 and which is DXT5. According to
|
||||
// http://forums.relicnews.com/showthread.php?t=20512, DXT3 is 1030, and DXT5
|
||||
// is 1029. However, neither way seems to work quite right for the alpha.
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_ROT
|
||||
#include "il_dds.h"
|
||||
|
||||
ILboolean iLoadRotInternal(void);
|
||||
|
||||
#define ROT_RGBA32 1024
|
||||
#define ROT_DXT1 1028
|
||||
#define ROT_DXT3 1029
|
||||
#define ROT_DXT5 1030
|
||||
|
||||
|
||||
//! Reads a ROT file
|
||||
ILboolean ilLoadRot(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE RotFile;
|
||||
ILboolean bRot = IL_FALSE;
|
||||
|
||||
RotFile = iopenr(FileName);
|
||||
if (RotFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bRot;
|
||||
}
|
||||
|
||||
bRot = ilLoadRotF(RotFile);
|
||||
icloser(RotFile);
|
||||
|
||||
return bRot;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened ROT file
|
||||
ILboolean ilLoadRotF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadRotInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a ROT
|
||||
ILboolean ilLoadRotL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadRotInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the ROT.
|
||||
ILboolean iLoadRotInternal(void)
|
||||
{
|
||||
ILubyte Form[4], FormName[4];
|
||||
ILuint FormLen, Width, Height, Format, Channels, CompSize;
|
||||
ILuint MipSize, MipLevel, MipWidth, MipHeight;
|
||||
ILenum FormatIL;
|
||||
ILimage *Image;
|
||||
ILboolean BaseCreated = IL_FALSE;
|
||||
ILubyte *CompData = NULL;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// The first entry in the file must be 'FORM', 0x20 in a big endian integer and then 'HEAD'.
|
||||
iread(Form, 1, 4);
|
||||
FormLen = GetBigUInt();
|
||||
iread(FormName, 1, 4);
|
||||
if (strncmp(Form, "FORM", 4) || FormLen != 0x14 || strncmp(FormName, "HEAD", 4)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Next follows the width, height and format in the header.
|
||||
Width = GetLittleUInt();
|
||||
Height = GetLittleUInt();
|
||||
Format = GetLittleUInt();
|
||||
|
||||
//@TODO: More formats.
|
||||
switch (Format)
|
||||
{
|
||||
case ROT_RGBA32: // 32-bit RGBA format
|
||||
Channels = 4;
|
||||
FormatIL = IL_RGBA;
|
||||
break;
|
||||
|
||||
case ROT_DXT1: // DXT1 (no alpha)
|
||||
Channels = 4;
|
||||
FormatIL = IL_RGBA;
|
||||
break;
|
||||
|
||||
case ROT_DXT3: // DXT3
|
||||
case ROT_DXT5: // DXT5
|
||||
Channels = 4;
|
||||
FormatIL = IL_RGBA;
|
||||
// Allocates the maximum needed (the first width/height given in the file).
|
||||
CompSize = ((Width + 3) / 4) * ((Height + 3) / 4) * 16;
|
||||
CompData = ialloc(CompSize);
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (Width == 0 || Height == 0) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
//@TODO: Find out what this is.
|
||||
GetLittleUInt(); // Skip this for the moment. This appears to be the number of channels.
|
||||
|
||||
// Next comes 'FORM', a length and 'MIPS'.
|
||||
iread(Form, 1, 4);
|
||||
FormLen = GetBigUInt();
|
||||
iread(FormName, 1, 4);
|
||||
//@TODO: Not sure if the FormLen has to be anything specific here.
|
||||
if (strncmp(Form, "FORM", 4) || strncmp(FormName, "MIPS", 4)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
//@TODO: Can these mipmap levels be in any order? Some things may be easier if the answer is no.
|
||||
Image = iCurImage;
|
||||
do {
|
||||
// Then we have 'FORM' again.
|
||||
iread(Form, 1, 4);
|
||||
// This is the size of the mipmap data.
|
||||
MipSize = GetBigUInt();
|
||||
iread(FormName, 1, 4);
|
||||
if (strncmp(Form, "FORM", 4)) {
|
||||
if (!BaseCreated) { // Our file is malformed.
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
// We have reached the end of the mipmap data.
|
||||
break;
|
||||
}
|
||||
if (strncmp(FormName, "MLVL", 4)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Next is the mipmap attributes (level number, width, height and length)
|
||||
MipLevel = GetLittleUInt();
|
||||
MipWidth = GetLittleUInt();
|
||||
MipHeight = GetLittleUInt();
|
||||
MipSize = GetLittleUInt(); // This is the same as the previous size listed -20 (for attributes).
|
||||
|
||||
// Lower level mipmaps cannot be larger than the main image.
|
||||
if (MipWidth > Width || MipHeight > Height || MipSize > CompSize) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Just create our images here.
|
||||
if (!BaseCreated) {
|
||||
if (!ilTexImage(MipWidth, MipHeight, 1, Channels, FormatIL, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
BaseCreated = IL_TRUE;
|
||||
}
|
||||
else {
|
||||
Image->Mipmaps = ilNewImageFull(MipWidth, MipHeight, 1, Channels, FormatIL, IL_UNSIGNED_BYTE, NULL);
|
||||
Image = Image->Mipmaps;
|
||||
}
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case ROT_RGBA32: // 32-bit RGBA format
|
||||
if (iread(Image->Data, Image->SizeOfData, 1) != 1)
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case ROT_DXT1:
|
||||
// Allocates the size of the compressed data.
|
||||
CompSize = ((MipWidth + 3) / 4) * ((MipHeight + 3) / 4) * 8;
|
||||
if (CompSize != MipSize) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
CompData = ialloc(CompSize);
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
// Read in the DXT1 data...
|
||||
if (iread(CompData, CompSize, 1) != 1)
|
||||
return IL_FALSE;
|
||||
// ...and decompress it.
|
||||
if (!DecompressDXT1(Image, CompData)) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
|
||||
Image->DxtcSize = CompSize;
|
||||
Image->DxtcData = CompData;
|
||||
Image->DxtcFormat = IL_DXT1;
|
||||
CompData = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ROT_DXT3:
|
||||
// Allocates the size of the compressed data.
|
||||
CompSize = ((MipWidth + 3) / 4) * ((MipHeight + 3) / 4) * 16;
|
||||
if (CompSize != MipSize) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
CompData = ialloc(CompSize);
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
// Read in the DXT3 data...
|
||||
if (iread(CompData, MipSize, 1) != 1)
|
||||
return IL_FALSE;
|
||||
// ...and decompress it.
|
||||
if (!DecompressDXT3(Image, CompData)) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
|
||||
Image->DxtcSize = CompSize;
|
||||
Image->DxtcData = CompData;
|
||||
Image->DxtcFormat = IL_DXT3;
|
||||
CompData = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ROT_DXT5:
|
||||
// Allocates the size of the compressed data.
|
||||
CompSize = ((MipWidth + 3) / 4) * ((MipHeight + 3) / 4) * 16;
|
||||
if (CompSize != MipSize) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
CompData = ialloc(CompSize);
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
// Read in the DXT5 data...
|
||||
if (iread(CompData, MipSize, 1) != 1)
|
||||
return IL_FALSE;
|
||||
// ...and decompress it.
|
||||
if (!DecompressDXT5(Image, CompData)) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
// Keeps a copy
|
||||
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
|
||||
Image->DxtcSize = CompSize;
|
||||
Image->DxtcData = CompData;
|
||||
Image->DxtcFormat = IL_DXT5;
|
||||
CompData = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ifree(CompData); // Free it if it was not saved.
|
||||
} while (!ieof()); //@TODO: Is there any other condition that should end this?
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
#endif//IL_NO_ROT
|
||||
|
||||
@@ -0,0 +1,763 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_sgi.c
|
||||
//
|
||||
// Description: Reads and writes Silicon Graphics Inc. (.sgi) files.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_SGI
|
||||
#include "il_sgi.h"
|
||||
#include "il_manip.h"
|
||||
#include <limits.h>
|
||||
|
||||
static char *FName = NULL;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*! Checks if the file specified in FileName is a valid .sgi file. */
|
||||
ILboolean ilIsValidSgi(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE SgiFile;
|
||||
ILboolean bSgi = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("sgi"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bSgi;
|
||||
}
|
||||
|
||||
FName = (char*)FileName;
|
||||
|
||||
SgiFile = iopenr(FileName);
|
||||
if (SgiFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bSgi;
|
||||
}
|
||||
|
||||
bSgi = ilIsValidSgiF(SgiFile);
|
||||
icloser(SgiFile);
|
||||
|
||||
return bSgi;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*! Checks if the ILHANDLE contains a valid .sgi file at the current position.*/
|
||||
ILboolean ilIsValidSgiF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidSgi();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
//! Checks if Lump is a valid .sgi lump.
|
||||
ILboolean ilIsValidSgiL(const void *Lump, ILuint Size)
|
||||
{
|
||||
FName = NULL;
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidSgi();
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// Internal function used to get the .sgi header from the current file.
|
||||
ILboolean iGetSgiHead(iSgiHeader *Header)
|
||||
{
|
||||
Header->MagicNum = GetBigUShort();
|
||||
Header->Storage = (ILbyte)igetc();
|
||||
Header->Bpc = (ILbyte)igetc();
|
||||
Header->Dim = GetBigUShort();
|
||||
Header->XSize = GetBigUShort();
|
||||
Header->YSize = GetBigUShort();
|
||||
Header->ZSize = GetBigUShort();
|
||||
Header->PixMin = GetBigInt();
|
||||
Header->PixMax = GetBigInt();
|
||||
Header->Dummy1 = GetBigInt();
|
||||
iread(Header->Name, 1, 80);
|
||||
Header->ColMap = GetBigInt();
|
||||
iread(Header->Dummy, 1, 404);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Internal function to get the header and check it. */
|
||||
ILboolean iIsValidSgi()
|
||||
{
|
||||
iSgiHeader Head;
|
||||
|
||||
if (!iGetSgiHead(&Head))
|
||||
return IL_FALSE;
|
||||
iseek(-(ILint)sizeof(iSgiHeader), IL_SEEK_CUR); // Go ahead and restore to previous state
|
||||
|
||||
return iCheckSgi(&Head);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Internal function used to check if the HEADER is a valid .sgi header. */
|
||||
ILboolean iCheckSgi(iSgiHeader *Header)
|
||||
{
|
||||
if (Header->MagicNum != SGI_MAGICNUM)
|
||||
return IL_FALSE;
|
||||
if (Header->Storage != SGI_RLE && Header->Storage != SGI_VERBATIM)
|
||||
return IL_FALSE;
|
||||
if (Header->Bpc == 0 || Header->Dim == 0)
|
||||
return IL_FALSE;
|
||||
if (Header->XSize == 0 || Header->YSize == 0 || Header->ZSize == 0)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*! Reads a SGI file */
|
||||
ILboolean ilLoadSgi(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE SgiFile;
|
||||
ILboolean bSgi = IL_FALSE;
|
||||
|
||||
SgiFile = iopenr(FileName);
|
||||
if (SgiFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bSgi;
|
||||
}
|
||||
|
||||
bSgi = ilLoadSgiF(SgiFile);
|
||||
icloser(SgiFile);
|
||||
|
||||
return bSgi;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*! Reads an already-opened SGI file */
|
||||
ILboolean ilLoadSgiF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadSgiInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/*! Reads from a memory "lump" that contains a SGI image */
|
||||
ILboolean ilLoadSgiL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadSgiInternal();
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Internal function used to load the SGI image */
|
||||
ILboolean iLoadSgiInternal()
|
||||
{
|
||||
iSgiHeader Header;
|
||||
ILboolean bSgi;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!iGetSgiHead(&Header))
|
||||
return IL_FALSE;
|
||||
if (!iCheckSgi(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Bugfix for #1060946.
|
||||
// The ZSize should never really be 2 by the specifications. Some
|
||||
// application is outputting these, and it looks like the ZSize
|
||||
// should really be 1.
|
||||
if (Header.ZSize == 2)
|
||||
Header.ZSize = 1;
|
||||
|
||||
if (Header.Storage == SGI_RLE) { // RLE
|
||||
bSgi = iReadRleSgi(&Header);
|
||||
}
|
||||
else { // Non-RLE //(Header.Storage == SGI_VERBATIM)
|
||||
bSgi = iReadNonRleSgi(&Header);
|
||||
}
|
||||
|
||||
if (!bSgi)
|
||||
return IL_FALSE;
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
ILboolean iReadRleSgi(iSgiHeader *Head)
|
||||
{
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
ILuint ixTable;
|
||||
#endif
|
||||
ILuint ChanInt = 0;
|
||||
ILuint ixPlane, ixHeight,ixPixel, RleOff, RleLen;
|
||||
ILuint *OffTable=NULL, *LenTable=NULL, TableSize, Cur;
|
||||
ILubyte **TempData=NULL;
|
||||
|
||||
if (!iNewSgi(Head))
|
||||
return IL_FALSE;
|
||||
|
||||
TableSize = Head->YSize * Head->ZSize;
|
||||
OffTable = (ILuint*)ialloc(TableSize * sizeof(ILuint));
|
||||
LenTable = (ILuint*)ialloc(TableSize * sizeof(ILuint));
|
||||
if (OffTable == NULL || LenTable == NULL)
|
||||
goto cleanup_error;
|
||||
if (iread(OffTable, TableSize * sizeof(ILuint), 1) != 1)
|
||||
goto cleanup_error;
|
||||
if (iread(LenTable, TableSize * sizeof(ILuint), 1) != 1)
|
||||
goto cleanup_error;
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
// Fix the offset/len table (it's big endian format)
|
||||
for (ixTable = 0; ixTable < TableSize; ixTable++) {
|
||||
iSwapUInt(OffTable + ixTable);
|
||||
iSwapUInt(LenTable + ixTable);
|
||||
}
|
||||
#endif //__LITTLE_ENDIAN__
|
||||
|
||||
// We have to create a temporary buffer for the image, because SGI
|
||||
// images are plane-separated.
|
||||
TempData = (ILubyte**)ialloc(Head->ZSize * sizeof(ILubyte*));
|
||||
if (TempData == NULL)
|
||||
goto cleanup_error;
|
||||
imemclear(TempData, Head->ZSize * sizeof(ILubyte*)); // Just in case ialloc fails then cleanup_error.
|
||||
for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
|
||||
TempData[ixPlane] = (ILubyte*)ialloc(Head->XSize * Head->YSize * Head->Bpc);
|
||||
if (TempData[ixPlane] == NULL)
|
||||
goto cleanup_error;
|
||||
}
|
||||
|
||||
// Read the Planes into the temporary memory
|
||||
for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
|
||||
for (ixHeight = 0, Cur = 0; ixHeight < Head->YSize;
|
||||
ixHeight++, Cur += Head->XSize * Head->Bpc) {
|
||||
|
||||
RleOff = OffTable[ixHeight + ixPlane * Head->YSize];
|
||||
RleLen = LenTable[ixHeight + ixPlane * Head->YSize];
|
||||
|
||||
// Seeks to the offset table position
|
||||
iseek(RleOff, IL_SEEK_SET);
|
||||
if (iGetScanLine((TempData[ixPlane]) + (ixHeight * Head->XSize * Head->Bpc),
|
||||
Head, RleLen) != Head->XSize * Head->Bpc) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
goto cleanup_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DW: Removed on 05/25/2002.
|
||||
/*// Check if an alphaplane exists and invert it
|
||||
if (Head->ZSize == 4) {
|
||||
for (ixPixel=0; (ILint)ixPixel<Head->XSize * Head->YSize; ixPixel++) {
|
||||
TempData[3][ixPixel] = TempData[3][ixPixel] ^ 255;
|
||||
}
|
||||
}*/
|
||||
|
||||
// Assemble the image from its planes
|
||||
for (ixPixel = 0; ixPixel < iCurImage->SizeOfData;
|
||||
ixPixel += Head->ZSize * Head->Bpc, ChanInt += Head->Bpc) {
|
||||
for (ixPlane = 0; (ILint)ixPlane < Head->ZSize * Head->Bpc; ixPlane += Head->Bpc) {
|
||||
iCurImage->Data[ixPixel + ixPlane] = TempData[ixPlane][ChanInt];
|
||||
if (Head->Bpc == 2)
|
||||
iCurImage->Data[ixPixel + ixPlane + 1] = TempData[ixPlane][ChanInt + 1];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
if (Head->Bpc == 2)
|
||||
sgiSwitchData(iCurImage->Data, iCurImage->SizeOfData);
|
||||
#endif
|
||||
|
||||
ifree(OffTable);
|
||||
ifree(LenTable);
|
||||
|
||||
for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
|
||||
ifree(TempData[ixPlane]);
|
||||
}
|
||||
ifree(TempData);
|
||||
|
||||
return IL_TRUE;
|
||||
|
||||
cleanup_error:
|
||||
ifree(OffTable);
|
||||
ifree(LenTable);
|
||||
if (TempData) {
|
||||
for (ixPlane = 0; ixPlane < Head->ZSize; ixPlane++) {
|
||||
ifree(TempData[ixPlane]);
|
||||
}
|
||||
ifree(TempData);
|
||||
}
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
ILint iGetScanLine(ILubyte *ScanLine, iSgiHeader *Head, ILuint Length)
|
||||
{
|
||||
ILushort Pixel, Count; // For current pixel
|
||||
ILuint BppRead = 0, CurPos = 0, Bps = Head->XSize * Head->Bpc;
|
||||
|
||||
while (BppRead < Length && CurPos < Bps)
|
||||
{
|
||||
Pixel = 0;
|
||||
if (iread(&Pixel, Head->Bpc, 1) != 1)
|
||||
return -1;
|
||||
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
iSwapUShort(&Pixel);
|
||||
#endif
|
||||
|
||||
if (!(Count = (Pixel & 0x7f))) // If 0, line ends
|
||||
return CurPos;
|
||||
if (Pixel & 0x80) { // If top bit set, then it is a "run"
|
||||
if (iread(ScanLine, Head->Bpc, Count) != Count)
|
||||
return -1;
|
||||
BppRead += Head->Bpc * Count + Head->Bpc;
|
||||
ScanLine += Head->Bpc * Count;
|
||||
CurPos += Head->Bpc * Count;
|
||||
}
|
||||
else {
|
||||
if (iread(&Pixel, Head->Bpc, 1) != 1)
|
||||
return -1;
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
iSwapUShort(&Pixel);
|
||||
#endif
|
||||
if (Head->Bpc == 1) {
|
||||
while (Count--) {
|
||||
*ScanLine = (ILubyte)Pixel;
|
||||
ScanLine++;
|
||||
CurPos++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (Count--) {
|
||||
*(ILushort*)ScanLine = Pixel;
|
||||
ScanLine += 2;
|
||||
CurPos += 2;
|
||||
}
|
||||
}
|
||||
BppRead += Head->Bpc + Head->Bpc;
|
||||
}
|
||||
}
|
||||
|
||||
return CurPos;
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// Much easier to read - just assemble from planes, no decompression
|
||||
ILboolean iReadNonRleSgi(iSgiHeader *Head)
|
||||
{
|
||||
ILuint i, c;
|
||||
// ILint ChanInt = 0; Unused
|
||||
ILint ChanSize;
|
||||
ILboolean Cache = IL_FALSE;
|
||||
|
||||
if (!iNewSgi(Head)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST) {
|
||||
Cache = IL_TRUE;
|
||||
ChanSize = Head->XSize * Head->YSize * Head->Bpc;
|
||||
iPreCache(ChanSize);
|
||||
}
|
||||
|
||||
for (c = 0; c < iCurImage->Bpp; c++) {
|
||||
for (i = c; i < iCurImage->SizeOfData; i += iCurImage->Bpp) {
|
||||
if (iread(iCurImage->Data + i, 1, 1) != 1) {
|
||||
if (Cache)
|
||||
iUnCache();
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Cache)
|
||||
iUnCache();
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void sgiSwitchData(ILubyte *Data, ILuint SizeOfData)
|
||||
{
|
||||
ILubyte Temp;
|
||||
ILuint i;
|
||||
#ifdef ALTIVEC_GCC
|
||||
i = 0;
|
||||
union {
|
||||
vector unsigned char vec;
|
||||
vector unsigned int load;
|
||||
}inversion_vector;
|
||||
|
||||
inversion_vector.load = (vector unsigned int)\
|
||||
{0x01000302,0x05040706,0x09080B0A,0x0D0C0F0E};
|
||||
while( i <= SizeOfData-16 ) {
|
||||
vector unsigned char data = vec_ld(i,Data);
|
||||
vec_perm(data,data,inversion_vector.vec);
|
||||
vec_st(data,i,Data);
|
||||
i+=16;
|
||||
}
|
||||
SizeOfData -= i;
|
||||
#endif
|
||||
for (i = 0; i < SizeOfData; i += 2) {
|
||||
Temp = Data[i];
|
||||
Data[i] = Data[i+1];
|
||||
Data[i+1] = Temp;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// Just an internal convenience function for reading SGI files
|
||||
ILboolean iNewSgi(iSgiHeader *Head)
|
||||
{
|
||||
if (!ilTexImage(Head->XSize, Head->YSize, Head->Bpc, (ILubyte)Head->ZSize, 0, IL_UNSIGNED_BYTE, NULL)) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
|
||||
switch (Head->ZSize)
|
||||
{
|
||||
case 1:
|
||||
iCurImage->Format = IL_LUMINANCE;
|
||||
break;
|
||||
/*case 2:
|
||||
iCurImage->Format = IL_LUMINANCE_ALPHA;
|
||||
break;*/
|
||||
case 3:
|
||||
iCurImage->Format = IL_RGB;
|
||||
break;
|
||||
case 4:
|
||||
iCurImage->Format = IL_RGBA;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
switch (Head->Bpc)
|
||||
{
|
||||
case 1:
|
||||
if (Head->PixMin < 0)
|
||||
iCurImage->Type = IL_BYTE;
|
||||
else
|
||||
iCurImage->Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case 2:
|
||||
if (Head->PixMin < 0)
|
||||
iCurImage->Type = IL_SHORT;
|
||||
else
|
||||
iCurImage->Type = IL_UNSIGNED_SHORT;
|
||||
break;
|
||||
default:
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
//! Writes a SGI file
|
||||
ILboolean ilSaveSgi(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE SgiFile;
|
||||
ILuint SgiSize;
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
SgiFile = iopenw(FileName);
|
||||
if (SgiFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
SgiSize = ilSaveSgiF(SgiFile);
|
||||
iclosew(SgiFile);
|
||||
|
||||
if (SgiSize == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Sgi to an already-opened file
|
||||
ILuint ilSaveSgiF(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputFile(File);
|
||||
Pos = itellw();
|
||||
if (iSaveSgiInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Sgi to a memory "lump"
|
||||
ILuint ilSaveSgiL(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputLump(Lump, Size);
|
||||
Pos = itellw();
|
||||
if (iSaveSgiInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
ILenum DetermineSgiType(ILenum Type)
|
||||
{
|
||||
if (Type > IL_UNSIGNED_SHORT) {
|
||||
if (iCurImage->Type == IL_INT)
|
||||
return IL_SHORT;
|
||||
return IL_UNSIGNED_SHORT;
|
||||
}
|
||||
return Type;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// Rle does NOT work yet.
|
||||
|
||||
// Internal function used to save the Sgi.
|
||||
ILboolean iSaveSgiInternal()
|
||||
{
|
||||
ILuint i, c;
|
||||
ILboolean Compress;
|
||||
ILimage *Temp = iCurImage;
|
||||
ILubyte *TempData;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (iCurImage->Format != IL_LUMINANCE
|
||||
//while the sgi spec doesn't directly forbid rgb files with 2
|
||||
//channels, they are quite uncommon and most apps don't support
|
||||
//them. so convert lum_a images to rgba before writing.
|
||||
//&& iCurImage->Format != IL_LUMINANCE_ALPHA
|
||||
&& iCurImage->Format != IL_RGB
|
||||
&& iCurImage->Format != IL_RGBA) {
|
||||
if (iCurImage->Format == IL_BGRA || iCurImage->Format == IL_LUMINANCE_ALPHA)
|
||||
Temp = iConvertImage(iCurImage, IL_RGBA, DetermineSgiType(iCurImage->Type));
|
||||
else
|
||||
Temp = iConvertImage(iCurImage, IL_RGB, DetermineSgiType(iCurImage->Type));
|
||||
}
|
||||
else if (iCurImage->Type > IL_UNSIGNED_SHORT) {
|
||||
Temp = iConvertImage(iCurImage, iCurImage->Format, DetermineSgiType(iCurImage->Type));
|
||||
}
|
||||
|
||||
//compression of images with 2 bytes per channel doesn't work yet
|
||||
Compress = iGetInt(IL_SGI_RLE) && Temp->Bpc == 1;
|
||||
|
||||
if (Temp == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
SaveBigUShort(SGI_MAGICNUM); // 'Magic' number
|
||||
if (Compress)
|
||||
iputc(1);
|
||||
else
|
||||
iputc(0);
|
||||
|
||||
if (Temp->Type == IL_UNSIGNED_BYTE)
|
||||
iputc(1);
|
||||
else if (Temp->Type == IL_UNSIGNED_SHORT)
|
||||
iputc(2);
|
||||
// Need to error here if not one of the two...
|
||||
|
||||
if (Temp->Format == IL_LUMINANCE || Temp->Format == IL_COLOUR_INDEX)
|
||||
SaveBigUShort(2);
|
||||
else
|
||||
SaveBigUShort(3);
|
||||
|
||||
SaveBigUShort((ILushort)Temp->Width);
|
||||
SaveBigUShort((ILushort)Temp->Height);
|
||||
SaveBigUShort((ILushort)Temp->Bpp);
|
||||
|
||||
switch (Temp->Type)
|
||||
{
|
||||
case IL_BYTE:
|
||||
SaveBigInt(SCHAR_MIN); // Minimum pixel value
|
||||
SaveBigInt(SCHAR_MAX); // Maximum pixel value
|
||||
break;
|
||||
case IL_UNSIGNED_BYTE:
|
||||
SaveBigInt(0); // Minimum pixel value
|
||||
SaveBigInt(UCHAR_MAX); // Maximum pixel value
|
||||
break;
|
||||
case IL_SHORT:
|
||||
SaveBigInt(SHRT_MIN); // Minimum pixel value
|
||||
SaveBigInt(SHRT_MAX); // Maximum pixel value
|
||||
break;
|
||||
case IL_UNSIGNED_SHORT:
|
||||
SaveBigInt(0); // Minimum pixel value
|
||||
SaveBigInt(USHRT_MAX); // Maximum pixel value
|
||||
break;
|
||||
}
|
||||
|
||||
SaveBigInt(0); // Dummy value
|
||||
|
||||
if (FName) {
|
||||
c = ilCharStrLen(FName);
|
||||
c = c < 79 ? 79 : c;
|
||||
iwrite(FName, 1, c);
|
||||
c = 80 - c;
|
||||
for (i = 0; i < c; i++) {
|
||||
iputc(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < 80; i++) {
|
||||
iputc(0);
|
||||
}
|
||||
}
|
||||
|
||||
SaveBigUInt(0); // Colormap
|
||||
|
||||
// Padding
|
||||
for (i = 0; i < 101; i++) {
|
||||
SaveLittleInt(0);
|
||||
}
|
||||
|
||||
|
||||
if (iCurImage->Origin == IL_ORIGIN_UPPER_LEFT) {
|
||||
TempData = iGetFlipped(Temp);
|
||||
if (TempData == NULL) {
|
||||
if (Temp!= iCurImage)
|
||||
ilCloseImage(Temp);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
TempData = Temp->Data;
|
||||
}
|
||||
|
||||
|
||||
if (!Compress) {
|
||||
for (c = 0; c < Temp->Bpp; c++) {
|
||||
for (i = c; i < Temp->SizeOfData; i += Temp->Bpp) {
|
||||
iputc(TempData[i]); // Have to save each colour plane separately.
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
iSaveRleSgi(TempData, Temp->Width, Temp->Height, Temp->Bpp, Temp->Bps);
|
||||
}
|
||||
|
||||
|
||||
if (TempData != Temp->Data)
|
||||
ifree(TempData);
|
||||
if (Temp != iCurImage)
|
||||
ilCloseImage(Temp);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
ILboolean iSaveRleSgi(ILubyte *Data, ILuint w, ILuint h, ILuint numChannels,
|
||||
ILuint bps)
|
||||
{
|
||||
//works only for sgi files with only 1 bpc
|
||||
|
||||
ILuint c, i, y, j;
|
||||
ILubyte *ScanLine = NULL, *CompLine = NULL;
|
||||
ILuint *StartTable = NULL, *LenTable = NULL;
|
||||
ILuint TableOff, DataOff = 0;
|
||||
|
||||
ScanLine = (ILubyte*)ialloc(w);
|
||||
CompLine = (ILubyte*)ialloc(w * 2 + 1); // Absolute worst case.
|
||||
StartTable = (ILuint*)ialloc(h * numChannels * sizeof(ILuint));
|
||||
LenTable = (ILuint*)icalloc(h * numChannels, sizeof(ILuint));
|
||||
if (!ScanLine || !CompLine || !StartTable || !LenTable) {
|
||||
ifree(ScanLine);
|
||||
ifree(CompLine);
|
||||
ifree(StartTable);
|
||||
ifree(LenTable);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// These just contain dummy values at this point.
|
||||
TableOff = itellw();
|
||||
iwrite(StartTable, sizeof(ILuint), h * numChannels);
|
||||
iwrite(LenTable, sizeof(ILuint), h * numChannels);
|
||||
|
||||
DataOff = itellw();
|
||||
for (c = 0; c < numChannels; c++) {
|
||||
for (y = 0; y < h; y++) {
|
||||
i = y * bps + c;
|
||||
for (j = 0; j < w; j++, i += numChannels) {
|
||||
ScanLine[j] = Data[i];
|
||||
}
|
||||
|
||||
ilRleCompressLine(ScanLine, w, 1, CompLine, LenTable + h * c + y, IL_SGICOMP);
|
||||
iwrite(CompLine, 1, *(LenTable + h * c + y));
|
||||
}
|
||||
}
|
||||
|
||||
iseekw(TableOff, IL_SEEK_SET);
|
||||
|
||||
j = h * numChannels;
|
||||
for (y = 0; y < j; y++) {
|
||||
StartTable[y] = DataOff;
|
||||
DataOff += LenTable[y];
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
iSwapUInt(&StartTable[y]);
|
||||
iSwapUInt(&LenTable[y]);
|
||||
#endif
|
||||
}
|
||||
|
||||
iwrite(StartTable, sizeof(ILuint), h * numChannels);
|
||||
iwrite(LenTable, sizeof(ILuint), h * numChannels);
|
||||
|
||||
ifree(ScanLine);
|
||||
ifree(CompLine);
|
||||
ifree(StartTable);
|
||||
ifree(LenTable);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#endif//IL_NO_SGI
|
||||
@@ -0,0 +1,185 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 01/30/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_size.c
|
||||
//
|
||||
// Description: Determines the size of output files for lump writing.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
|
||||
|
||||
ILuint iTargaSize(void);
|
||||
|
||||
|
||||
ILuint CurPos; // Fake "file" pointer.
|
||||
ILuint MaxPos;
|
||||
|
||||
|
||||
//! Fake seek function
|
||||
ILint ILAPIENTRY iSizeSeek(ILint Offset, ILuint Mode)
|
||||
{
|
||||
switch (Mode)
|
||||
{
|
||||
case IL_SEEK_SET:
|
||||
CurPos = Offset;
|
||||
if (CurPos > MaxPos)
|
||||
MaxPos = CurPos;
|
||||
break;
|
||||
|
||||
case IL_SEEK_CUR:
|
||||
CurPos = CurPos + Offset;
|
||||
break;
|
||||
|
||||
case IL_SEEK_END:
|
||||
CurPos = MaxPos + Offset; // Offset should be negative in this case.
|
||||
break;
|
||||
|
||||
default:
|
||||
ilSetError(IL_INTERNAL_ERROR); // Should never happen!
|
||||
return -1; // Error code
|
||||
}
|
||||
|
||||
if (CurPos > MaxPos)
|
||||
MaxPos = CurPos;
|
||||
|
||||
return 0; // Code for success
|
||||
}
|
||||
|
||||
ILuint ILAPIENTRY iSizeTell(void)
|
||||
{
|
||||
return CurPos;
|
||||
}
|
||||
|
||||
ILint ILAPIENTRY iSizePutc(ILubyte Char)
|
||||
{
|
||||
CurPos++;
|
||||
if (CurPos > MaxPos)
|
||||
MaxPos = CurPos;
|
||||
return Char;
|
||||
}
|
||||
|
||||
ILint ILAPIENTRY iSizeWrite(const void *Buffer, ILuint Size, ILuint Number)
|
||||
{
|
||||
CurPos += Size * Number;
|
||||
if (CurPos > MaxPos)
|
||||
MaxPos = CurPos;
|
||||
return Number;
|
||||
}
|
||||
|
||||
|
||||
//@TODO: Do computations for uncompressed formats without going through the
|
||||
// whole writing process.
|
||||
|
||||
//! Returns the size of the memory buffer needed to save the current image into this Type.
|
||||
// A return value of 0 is an error.
|
||||
ILuint ilDetermineSize(ILenum Type)
|
||||
{
|
||||
MaxPos = CurPos = 0;
|
||||
iSetOutputFake(); // Sets iputc, iwrite, etc. to functions above.
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
#ifndef IL_NO_BMP
|
||||
case IL_BMP:
|
||||
ilSaveBmpL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_BMP
|
||||
|
||||
#ifndef IL_NO_DDS
|
||||
case IL_DDS:
|
||||
ilSaveDdsL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_DDS
|
||||
|
||||
#ifndef IL_NO_EXR
|
||||
case IL_EXR:
|
||||
ilSaveExrL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_EXR
|
||||
|
||||
#ifndef IL_NO_HDR
|
||||
case IL_HDR:
|
||||
ilSaveHdrL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_HDR
|
||||
|
||||
#ifndef IL_NO_JP2
|
||||
case IL_JP2:
|
||||
ilSaveJp2L(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_JP2
|
||||
|
||||
#ifndef IL_NO_JPG
|
||||
case IL_JPG:
|
||||
ilSaveJpegL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_JPG
|
||||
|
||||
#ifndef IL_NO_PCX
|
||||
case IL_PCX:
|
||||
ilSavePcxL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_PCX
|
||||
|
||||
#ifndef IL_NO_PNG
|
||||
case IL_PNG:
|
||||
ilSavePngL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_PNG
|
||||
|
||||
#ifndef IL_NO_PNM
|
||||
case IL_PNM:
|
||||
ilSavePnmL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_PNM
|
||||
|
||||
#ifndef IL_NO_PSD
|
||||
case IL_PSD:
|
||||
ilSavePsdL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_PSD
|
||||
|
||||
#ifndef IL_NO_RAW
|
||||
case IL_RAW:
|
||||
ilSaveRawL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_RAW
|
||||
|
||||
#ifndef IL_NO_SGI
|
||||
case IL_SGI:
|
||||
ilSaveSgiL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_SGI
|
||||
|
||||
#ifndef IL_NO_TGA
|
||||
case IL_TGA:
|
||||
//ilSaveTargaL(NULL, 0);
|
||||
return iTargaSize();
|
||||
break;
|
||||
#endif//IL_NO_TGA
|
||||
|
||||
#ifndef IL_NO_TIF
|
||||
case IL_TIF:
|
||||
ilSaveTiffL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_TIF
|
||||
|
||||
#ifndef IL_NO_WBMP
|
||||
case IL_WBMP:
|
||||
ilSaveWbmpL(NULL, 0);
|
||||
break;
|
||||
#endif//IL_NO_WBMP
|
||||
|
||||
default:
|
||||
// 0 is an error for this.
|
||||
ilSetError(IL_INVALID_ENUM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return MaxPos;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 01/15/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_squish.cpp
|
||||
//
|
||||
// Description: Implements access to the Squish library.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
/*#include "il_dds.h"
|
||||
#include "il_manip.h"
|
||||
#include <limits.h>*/
|
||||
|
||||
|
||||
#ifdef IL_USE_DXTC_SQUISH
|
||||
#include <squish.h>
|
||||
|
||||
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#ifndef _DEBUG
|
||||
#pragma comment(lib, "squish.lib")
|
||||
#else
|
||||
#pragma comment(lib, "squish-d.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
//! Compresses data to a DXT format using libsquish.
|
||||
// The data must be in unsigned byte RGBA format. The alpha channel will be ignored if DxtType is IL_DXT1.
|
||||
// DxtSize is used to return the size in bytes of the DXTC data returned.
|
||||
ILAPI ILubyte* ILAPIENTRY ilSquishCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat, ILuint *DxtSize)
|
||||
{
|
||||
ILuint Size; //@TODO: Support larger than 32-bit data?
|
||||
ILint Flags;
|
||||
ILubyte *DxtcData;
|
||||
|
||||
if (Data == NULL) { // We cannot operate on a null pointer.
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The nVidia Texture Tools library does not support volume textures yet.
|
||||
if (Depth != 1) {
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (DxtFormat)
|
||||
{
|
||||
case IL_DXT1: // Should these two be
|
||||
case IL_DXT1A: // any different?
|
||||
Flags = squish::kDxt1;
|
||||
break;
|
||||
case IL_DXT3:
|
||||
Flags = squish::kDxt3;
|
||||
break;
|
||||
case IL_DXT5:
|
||||
Flags = squish::kDxt5;
|
||||
break;
|
||||
default: // Does not support DXT2 or DXT4.
|
||||
ilSetError(IL_INVALID_PARAM);
|
||||
break;
|
||||
}
|
||||
|
||||
Size = squish::GetStorageRequirements(Width, Height, Flags);
|
||||
DxtcData = (ILubyte*)ialloc(Size);
|
||||
if (DxtcData == NULL)
|
||||
return NULL;
|
||||
|
||||
squish::CompressImage(Data, Width, Height, DxtcData, Flags);
|
||||
|
||||
*DxtSize = Size;
|
||||
return DxtcData;
|
||||
}
|
||||
|
||||
#else
|
||||
// Let's have this so that the function is always created and exported, even if it does nothing.
|
||||
ILAPI ILubyte* ILAPIENTRY ilSquishCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat, ILuint *DxtSize)
|
||||
{
|
||||
//@TODO: Do we need to set an error message?
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif//IL_NO_DXTC_SQUISH
|
||||
@@ -0,0 +1,669 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2008 by Denton Woods
|
||||
// Last modified: 12/17/2008
|
||||
//
|
||||
// Filename: src-IL/src/il_stack.c
|
||||
//
|
||||
// Description: The main image stack
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Credit goes to John Villar (johnny@reliaschev.com) for making the suggestion
|
||||
// of not letting the user use ILimage structs but instead binding images
|
||||
// like OpenGL.
|
||||
|
||||
#include "il_internal.h"
|
||||
#include "il_stack.h"
|
||||
|
||||
//! Creates Num images and puts their index in Images - similar to glGenTextures().
|
||||
void ILAPIENTRY ilGenImages(ILsizei Num, ILuint *Images)
|
||||
{
|
||||
ILsizei Index = 0;
|
||||
iFree *TempFree = FreeNames;
|
||||
|
||||
if (Num < 1 || Images == NULL) {
|
||||
ilSetError(IL_INVALID_VALUE);
|
||||
return;
|
||||
}
|
||||
|
||||
// No images have been generated yet, so create the image stack.
|
||||
if (ImageStack == NULL)
|
||||
if (!iEnlargeStack())
|
||||
return;
|
||||
|
||||
do {
|
||||
if (FreeNames != NULL) { // If any have been deleted, then reuse their image names.
|
||||
TempFree = (iFree*)FreeNames->Next;
|
||||
Images[Index] = FreeNames->Name;
|
||||
ImageStack[FreeNames->Name] = ilNewImage(1, 1, 1, 1, 1);
|
||||
ifree(FreeNames);
|
||||
FreeNames = TempFree;
|
||||
} else {
|
||||
if (LastUsed >= StackSize)
|
||||
if (!iEnlargeStack())
|
||||
return;
|
||||
Images[Index] = LastUsed;
|
||||
// Must be all 1's instead of 0's, because some functions would divide by 0.
|
||||
ImageStack[LastUsed] = ilNewImage(1, 1, 1, 1, 1);
|
||||
LastUsed++;
|
||||
}
|
||||
} while (++Index < Num);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ILuint ILAPIENTRY ilGenImage()
|
||||
{
|
||||
ILuint i;
|
||||
ilGenImages(1,&i);
|
||||
return i;
|
||||
}
|
||||
|
||||
//! Makes Image the current active image - similar to glBindTexture().
|
||||
void ILAPIENTRY ilBindImage(ILuint Image)
|
||||
{
|
||||
if (ImageStack == NULL || StackSize == 0) {
|
||||
if (!iEnlargeStack()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the user requests a high image name.
|
||||
while (Image >= StackSize) {
|
||||
if (!iEnlargeStack()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImageStack[Image] == NULL) {
|
||||
ImageStack[Image] = ilNewImage(1, 1, 1, 1, 1);
|
||||
if (Image >= LastUsed) // >= ?
|
||||
LastUsed = Image + 1;
|
||||
}
|
||||
|
||||
iCurImage = ImageStack[Image];
|
||||
CurName = Image;
|
||||
|
||||
ParentImage = IL_TRUE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! Deletes Num images from the image stack - similar to glDeleteTextures().
|
||||
void ILAPIENTRY ilDeleteImages(ILsizei Num, const ILuint *Images)
|
||||
{
|
||||
iFree *Temp = FreeNames;
|
||||
ILuint Index = 0;
|
||||
|
||||
if (Num < 1) {
|
||||
//ilSetError(IL_INVALID_VALUE);
|
||||
return;
|
||||
}
|
||||
if (StackSize == 0)
|
||||
return;
|
||||
|
||||
do {
|
||||
if (Images[Index] > 0 && Images[Index] < LastUsed) { // <= ?
|
||||
/*if (FreeNames != NULL) { // Terribly inefficient
|
||||
Temp = FreeNames;
|
||||
do {
|
||||
if (Temp->Name == Images[Index]) {
|
||||
continue; // Sufficient?
|
||||
}
|
||||
} while ((Temp = Temp->Next));
|
||||
}*/
|
||||
|
||||
// Already has been deleted or was never used.
|
||||
if (ImageStack[Images[Index]] == NULL)
|
||||
continue;
|
||||
|
||||
// Find out if current image - if so, set to default image zero.
|
||||
if (Images[Index] == CurName || Images[Index] == 0) {
|
||||
iCurImage = ImageStack[0];
|
||||
CurName = 0;
|
||||
}
|
||||
|
||||
// Should *NOT* be NULL here!
|
||||
ilCloseImage(ImageStack[Images[Index]]);
|
||||
ImageStack[Images[Index]] = NULL;
|
||||
|
||||
// Add to head of list - works for empty and non-empty lists
|
||||
Temp = (iFree*)ialloc(sizeof(iFree));
|
||||
if (!Temp) {
|
||||
return;
|
||||
}
|
||||
Temp->Name = Images[Index];
|
||||
Temp->Next = FreeNames;
|
||||
FreeNames = Temp;
|
||||
}
|
||||
/*else { // Shouldn't set an error...just continue onward.
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
}*/
|
||||
} while (++Index < (ILuint)Num);
|
||||
}
|
||||
|
||||
|
||||
void ILAPIENTRY ilDeleteImage(const ILuint Num) {
|
||||
ilDeleteImages(1,&Num);
|
||||
}
|
||||
|
||||
//! Checks if Image is a valid ilGenImages-generated image (like glIsTexture()).
|
||||
ILboolean ILAPIENTRY ilIsImage(ILuint Image)
|
||||
{
|
||||
//iFree *Temp = FreeNames;
|
||||
|
||||
if (ImageStack == NULL)
|
||||
return IL_FALSE;
|
||||
if (Image >= LastUsed || Image == 0)
|
||||
return IL_FALSE;
|
||||
|
||||
/*do {
|
||||
if (Temp->Name == Image)
|
||||
return IL_FALSE;
|
||||
} while ((Temp = Temp->Next));*/
|
||||
|
||||
if (ImageStack[Image] == NULL) // Easier check.
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Closes Image and frees all memory associated with it.
|
||||
ILAPI void ILAPIENTRY ilCloseImage(ILimage *Image)
|
||||
{
|
||||
if (Image == NULL)
|
||||
return;
|
||||
|
||||
if (Image->Data != NULL) {
|
||||
ifree(Image->Data);
|
||||
Image->Data = NULL;
|
||||
}
|
||||
|
||||
if (Image->Pal.Palette != NULL && Image->Pal.PalSize > 0 && Image->Pal.PalType != IL_PAL_NONE) {
|
||||
ifree(Image->Pal.Palette);
|
||||
Image->Pal.Palette = NULL;
|
||||
}
|
||||
|
||||
if (Image->Next != NULL) {
|
||||
ilCloseImage(Image->Next);
|
||||
Image->Next = NULL;
|
||||
}
|
||||
|
||||
if (Image->Faces != NULL) {
|
||||
ilCloseImage(Image->Faces);
|
||||
Image->Mipmaps = NULL;
|
||||
}
|
||||
|
||||
if (Image->Mipmaps != NULL) {
|
||||
ilCloseImage(Image->Mipmaps);
|
||||
Image->Mipmaps = NULL;
|
||||
}
|
||||
|
||||
if (Image->Layers != NULL) {
|
||||
ilCloseImage(Image->Layers);
|
||||
Image->Layers = NULL;
|
||||
}
|
||||
|
||||
if (Image->AnimList != NULL && Image->AnimSize != 0) {
|
||||
ifree(Image->AnimList);
|
||||
Image->AnimList = NULL;
|
||||
}
|
||||
|
||||
if (Image->Profile != NULL && Image->ProfileSize != 0) {
|
||||
ifree(Image->Profile);
|
||||
Image->Profile = NULL;
|
||||
Image->ProfileSize = 0;
|
||||
}
|
||||
|
||||
if (Image->DxtcData != NULL && Image->DxtcFormat != IL_DXT_NO_COMP) {
|
||||
ifree(Image->DxtcData);
|
||||
Image->DxtcData = NULL;
|
||||
Image->DxtcFormat = IL_DXT_NO_COMP;
|
||||
Image->DxtcSize = 0;
|
||||
}
|
||||
|
||||
ifree(Image);
|
||||
Image = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILAPI ILboolean ILAPIENTRY ilIsValidPal(ILpal *Palette)
|
||||
{
|
||||
if (Palette == NULL)
|
||||
return IL_FALSE;
|
||||
if (Palette->PalSize == 0 || Palette->Palette == NULL)
|
||||
return IL_FALSE;
|
||||
switch (Palette->PalType)
|
||||
{
|
||||
case IL_PAL_RGB24:
|
||||
case IL_PAL_RGB32:
|
||||
case IL_PAL_RGBA32:
|
||||
case IL_PAL_BGR24:
|
||||
case IL_PAL_BGR32:
|
||||
case IL_PAL_BGRA32:
|
||||
return IL_TRUE;
|
||||
}
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
//! Closes Palette and frees all memory associated with it.
|
||||
ILAPI void ILAPIENTRY ilClosePal(ILpal *Palette)
|
||||
{
|
||||
if (Palette == NULL)
|
||||
return;
|
||||
if (!ilIsValidPal(Palette))
|
||||
return;
|
||||
ifree(Palette->Palette);
|
||||
ifree(Palette);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILimage *iGetBaseImage()
|
||||
{
|
||||
return ImageStack[ilGetCurName()];
|
||||
}
|
||||
|
||||
|
||||
//! Sets the current mipmap level
|
||||
ILboolean ILAPIENTRY ilActiveMipmap(ILuint Number)
|
||||
{
|
||||
ILuint Current;
|
||||
ILimage *iTempImage;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (Number == 0) {
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
iTempImage = iCurImage;
|
||||
iCurImage = iCurImage->Mipmaps;
|
||||
if (iCurImage == NULL) {
|
||||
iCurImage = iTempImage;
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
for (Current = 1; Current < Number; Current++) {
|
||||
iCurImage = iCurImage->Mipmaps;
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
iCurImage = iTempImage;
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
ParentImage = IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Used for setting the current image if it is an animation.
|
||||
ILboolean ILAPIENTRY ilActiveImage(ILuint Number)
|
||||
{
|
||||
ILuint Current;
|
||||
ILimage *iTempImage;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (Number == 0) {
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
iTempImage = iCurImage;
|
||||
iCurImage = iCurImage->Next;
|
||||
if (iCurImage == NULL) {
|
||||
iCurImage = iTempImage;
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Number--; // Skip 0 (parent image)
|
||||
for (Current = 0; Current < Number; Current++) {
|
||||
iCurImage = iCurImage->Next;
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
iCurImage = iTempImage;
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
ParentImage = IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Used for setting the current face if it is a cubemap.
|
||||
ILboolean ILAPIENTRY ilActiveFace(ILuint Number)
|
||||
{
|
||||
ILuint Current;
|
||||
ILimage *iTempImage;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (Number == 0) {
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
iTempImage = iCurImage;
|
||||
iCurImage = iCurImage->Faces;
|
||||
if (iCurImage == NULL) {
|
||||
iCurImage = iTempImage;
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
//Number--; // Skip 0 (parent image)
|
||||
for (Current = 1; Current < Number; Current++) {
|
||||
iCurImage = iCurImage->Faces;
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
iCurImage = iTempImage;
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
ParentImage = IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Used for setting the current layer if layers exist.
|
||||
ILboolean ILAPIENTRY ilActiveLayer(ILuint Number)
|
||||
{
|
||||
ILuint Current;
|
||||
ILimage *iTempImage;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (Number == 0) {
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
iTempImage = iCurImage;
|
||||
iCurImage = iCurImage->Layers;
|
||||
if (iCurImage == NULL) {
|
||||
iCurImage = iTempImage;
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
//Number--; // Skip 0 (parent image)
|
||||
for (Current = 1; Current < Number; Current++) {
|
||||
iCurImage = iCurImage->Layers;
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
iCurImage = iTempImage;
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
ParentImage = IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILuint ILAPIENTRY ilCreateSubImage(ILenum Type, ILuint Num)
|
||||
{
|
||||
ILimage *SubImage;
|
||||
ILuint Count ; // Create one before we go in the loop.
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return 0;
|
||||
}
|
||||
if (Num == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case IL_SUB_NEXT:
|
||||
if (iCurImage->Next)
|
||||
ilCloseImage(iCurImage->Next);
|
||||
iCurImage->Next = ilNewImage(1, 1, 1, 1, 1);
|
||||
SubImage = iCurImage->Next;
|
||||
break;
|
||||
|
||||
case IL_SUB_MIPMAP:
|
||||
if (iCurImage->Mipmaps)
|
||||
ilCloseImage(iCurImage->Mipmaps);
|
||||
iCurImage->Mipmaps = ilNewImage(1, 1, 1, 1, 1);
|
||||
SubImage = iCurImage->Mipmaps;
|
||||
break;
|
||||
|
||||
case IL_SUB_LAYER:
|
||||
if (iCurImage->Layers)
|
||||
ilCloseImage(iCurImage->Layers);
|
||||
iCurImage->Layers = ilNewImage(1, 1, 1, 1, 1);
|
||||
SubImage = iCurImage->Layers;
|
||||
break;
|
||||
|
||||
default:
|
||||
ilSetError(IL_INVALID_ENUM);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (SubImage == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (Count = 1; Count < Num; Count++) {
|
||||
SubImage->Next = ilNewImage(1, 1, 1, 1, 1);
|
||||
SubImage = SubImage->Next;
|
||||
if (SubImage == NULL)
|
||||
return Count;
|
||||
}
|
||||
|
||||
return Count;
|
||||
}
|
||||
|
||||
|
||||
// Returns the current index.
|
||||
ILAPI ILuint ILAPIENTRY ilGetCurName()
|
||||
{
|
||||
if (iCurImage == NULL || ImageStack == NULL || StackSize == 0)
|
||||
return 0;
|
||||
return CurName;
|
||||
}
|
||||
|
||||
|
||||
// Returns the current image.
|
||||
ILAPI ILimage* ILAPIENTRY ilGetCurImage()
|
||||
{
|
||||
return iCurImage;
|
||||
}
|
||||
|
||||
|
||||
// To be only used when the original image is going to be set back almost immediately.
|
||||
ILAPI void ILAPIENTRY ilSetCurImage(ILimage *Image)
|
||||
{
|
||||
iCurImage = Image;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Completely replaces the current image and the version in the image stack.
|
||||
ILAPI void ILAPIENTRY ilReplaceCurImage(ILimage *Image)
|
||||
{
|
||||
if (iCurImage) {
|
||||
ilActiveImage(0);
|
||||
ilCloseImage(iCurImage);
|
||||
}
|
||||
ImageStack[ilGetCurName()] = Image;
|
||||
iCurImage = Image;
|
||||
ParentImage = IL_TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Like realloc but sets new memory to 0.
|
||||
void* ILAPIENTRY ilRecalloc(void *Ptr, ILuint OldSize, ILuint NewSize)
|
||||
{
|
||||
void *Temp = ialloc(NewSize);
|
||||
ILuint CopySize = (OldSize < NewSize) ? OldSize : NewSize;
|
||||
|
||||
if (Temp != NULL) {
|
||||
if (Ptr != NULL) {
|
||||
memcpy(Temp, Ptr, CopySize);
|
||||
ifree(Ptr);
|
||||
}
|
||||
|
||||
Ptr = Temp;
|
||||
|
||||
if (OldSize < NewSize)
|
||||
imemclear((ILubyte*)Temp + OldSize, NewSize - OldSize);
|
||||
}
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to enlarge the image stack by I_STACK_INCREMENT members.
|
||||
ILboolean iEnlargeStack()
|
||||
{
|
||||
// 02-05-2001: Moved from ilGenImages().
|
||||
// Puts the cleanup function on the exit handler once.
|
||||
if (!OnExit) {
|
||||
#ifdef _MEM_DEBUG
|
||||
AddToAtexit(); // So iFreeMem doesn't get called after unfreed information.
|
||||
#endif//_MEM_DEBUG
|
||||
#if (!defined(_WIN32_WCE)) && (!defined(IL_STATIC_LIB))
|
||||
atexit((void*)ilShutDown);
|
||||
#endif
|
||||
OnExit = IL_TRUE;
|
||||
}
|
||||
|
||||
if (!(ImageStack = (ILimage**)ilRecalloc(ImageStack, StackSize * sizeof(ILimage*), (StackSize + I_STACK_INCREMENT) * sizeof(ILimage*)))) {
|
||||
return IL_FALSE;
|
||||
}
|
||||
StackSize += I_STACK_INCREMENT;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
static ILboolean IsInit = IL_FALSE;
|
||||
|
||||
// ONLY call at startup.
|
||||
void ILAPIENTRY ilInit()
|
||||
{
|
||||
// if it is already initialized skip initialization
|
||||
if (IsInit == IL_TRUE )
|
||||
return;
|
||||
|
||||
//ilSetMemory(NULL, NULL); Now useless 3/4/2006 (due to modification in il_alloc.c)
|
||||
ilSetError(IL_NO_ERROR);
|
||||
ilDefaultStates(); // Set states to their defaults.
|
||||
// Sets default file-reading callbacks.
|
||||
ilResetRead();
|
||||
ilResetWrite();
|
||||
#if (!defined(_WIN32_WCE)) && (!defined(IL_STATIC_LIB))
|
||||
atexit((void*)ilRemoveRegistered);
|
||||
#endif
|
||||
//_WIN32_WCE
|
||||
//ilShutDown();
|
||||
iSetImage0(); // Beware! Clears all existing textures!
|
||||
iBindImageTemp(); // Go ahead and create the temporary image.
|
||||
IsInit = IL_TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Frees any extra memory in the stack.
|
||||
// - Called on exit
|
||||
void ILAPIENTRY ilShutDown()
|
||||
{
|
||||
// if it is not initialized do not shutdown
|
||||
iFree* TempFree = (iFree*)FreeNames;
|
||||
ILuint i;
|
||||
|
||||
if (!IsInit)
|
||||
return;
|
||||
|
||||
if (!IsInit) { // Prevent from being called when not initialized.
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return;
|
||||
}
|
||||
|
||||
while (TempFree != NULL) {
|
||||
FreeNames = (iFree*)TempFree->Next;
|
||||
ifree(TempFree);
|
||||
TempFree = FreeNames;
|
||||
}
|
||||
|
||||
//for (i = 0; i < LastUsed; i++) {
|
||||
for (i = 0; i < StackSize; i++) {
|
||||
if (ImageStack[i] != NULL)
|
||||
ilCloseImage(ImageStack[i]);
|
||||
}
|
||||
|
||||
if (ImageStack)
|
||||
ifree(ImageStack);
|
||||
ImageStack = NULL;
|
||||
LastUsed = 0;
|
||||
StackSize = 0;
|
||||
IsInit = IL_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Initializes the image stack's first entry (default image) -- ONLY CALL ONCE!
|
||||
void iSetImage0()
|
||||
{
|
||||
if (ImageStack == NULL)
|
||||
if (!iEnlargeStack())
|
||||
return;
|
||||
|
||||
LastUsed = 1;
|
||||
CurName = 0;
|
||||
ParentImage = IL_TRUE;
|
||||
if (!ImageStack[0])
|
||||
ImageStack[0] = ilNewImage(1, 1, 1, 1, 1);
|
||||
iCurImage = ImageStack[0];
|
||||
ilDefaultImage();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ILAPI void ILAPIENTRY iBindImageTemp()
|
||||
{
|
||||
if (ImageStack == NULL || StackSize <= 1)
|
||||
if (!iEnlargeStack())
|
||||
return;
|
||||
|
||||
if (LastUsed < 2)
|
||||
LastUsed = 2;
|
||||
CurName = 1;
|
||||
ParentImage = IL_TRUE;
|
||||
if (!ImageStack[1])
|
||||
ImageStack[1] = ilNewImage(1, 1, 1, 1, 1);
|
||||
iCurImage = ImageStack[1];
|
||||
|
||||
return;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,398 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 01/06/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_sun.c
|
||||
//
|
||||
// Description: Reads from a Sun RAS file. Specifications available from
|
||||
// http://www.fileformat.info/format/sunraster/egff.htm.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_SUN
|
||||
#include "il_bits.h"
|
||||
|
||||
ILboolean iLoadSunInternal(void);
|
||||
ILboolean iIsValidSun(void);
|
||||
ILuint iSunGetRle(ILubyte *Data, ILuint Length);
|
||||
|
||||
typedef struct SUNHEAD
|
||||
{
|
||||
ILuint MagicNumber; // Magic (identification) number
|
||||
ILuint Width; // Width of image in pixels
|
||||
ILuint Height; // Height of image in pixels
|
||||
ILuint Depth; // Number of bits per pixel
|
||||
ILuint Length; // Size of image data in bytes
|
||||
ILuint Type; // Type of raster file
|
||||
ILuint ColorMapType; // Type of color map
|
||||
ILuint ColorMapLength; // Size of the color map in bytes
|
||||
} SUNHEAD;
|
||||
|
||||
// Data storage types
|
||||
#define IL_SUN_OLD 0x00
|
||||
#define IL_SUN_STANDARD 0x01
|
||||
#define IL_SUN_BYTE_ENC 0x02
|
||||
#define IL_SUN_RGB 0x03
|
||||
#define IL_SUN_TIFF 0x04
|
||||
#define IL_SUN_IFF 0x05
|
||||
#define IL_SUN_EXPER 0xFFFF // Experimental, not supported.
|
||||
|
||||
// Colormap types
|
||||
#define IL_SUN_NO_MAP 0x00
|
||||
#define IL_SUN_RGB_MAP 0x01
|
||||
#define IL_SUN_RAW_MAP 0x02
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid Sun file.
|
||||
ILboolean ilIsValidSun(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE SunFile;
|
||||
ILboolean bSun = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("sun")) && !iCheckExtension(FileName, IL_TEXT("ras")) &&
|
||||
!iCheckExtension(FileName, IL_TEXT("im1")) && !iCheckExtension(FileName, IL_TEXT("im8")) &&
|
||||
!iCheckExtension(FileName, IL_TEXT("im24")) && !iCheckExtension(FileName, IL_TEXT("im32")) &&
|
||||
!iCheckExtension(FileName, IL_TEXT("rs"))) { // Lots of names possible...
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bSun;
|
||||
}
|
||||
|
||||
SunFile = iopenr(FileName);
|
||||
if (SunFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bSun;
|
||||
}
|
||||
|
||||
bSun = ilIsValidSunF(SunFile);
|
||||
icloser(SunFile);
|
||||
|
||||
return bSun;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid Sun file at the current position.
|
||||
ILboolean ilIsValidSunF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidSun();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid Sun lump.
|
||||
ILboolean ilIsValidSunL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidSun();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the Sun header from the current file.
|
||||
ILboolean iGetSunHead(SUNHEAD *Header)
|
||||
{
|
||||
Header->MagicNumber = GetBigUInt();
|
||||
Header->Width = GetBigUInt();
|
||||
Header->Height = GetBigUInt();
|
||||
Header->Depth = GetBigUInt();
|
||||
Header->Length = GetBigUInt();
|
||||
Header->Type = GetBigUInt();
|
||||
Header->ColorMapType = GetBigUInt();
|
||||
Header->ColorMapLength = GetBigUInt();
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid SUN header.
|
||||
ILboolean iCheckSun(SUNHEAD *Header)
|
||||
{
|
||||
if (Header->MagicNumber != 0x59A66A95) // Magic number is always 0x59A66A95.
|
||||
return IL_FALSE;
|
||||
if (Header->Width == 0 || Header->Height == 0) // 0 dimensions are meaningless.
|
||||
return IL_FALSE;
|
||||
// These are the only valid depths that I know of.
|
||||
if (Header->Depth != 1 && Header->Depth != 8 && Header->Depth != 24 && Header->Depth != 32)
|
||||
return IL_FALSE;
|
||||
if (Header->Type > IL_SUN_RGB) //@TODO: Support further types.
|
||||
return IL_FALSE;
|
||||
if (Header->ColorMapType > IL_SUN_RGB_MAP) //@TODO: Find out more about raw map.
|
||||
return IL_FALSE;
|
||||
// Color map cannot be 0 if there is a map indicated.
|
||||
if (Header->ColorMapType > IL_SUN_NO_MAP && Header->ColorMapLength == 0)
|
||||
return IL_FALSE;
|
||||
//@TODO: These wouldn't make sense. Are they valid somehow? Find out...
|
||||
if ((Header->Depth == 1 || Header->Depth == 32) && Header->Type == IL_SUN_BYTE_ENC)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidSun()
|
||||
{
|
||||
SUNHEAD Head;
|
||||
|
||||
if (!iGetSunHead(&Head))
|
||||
return IL_FALSE;
|
||||
iseek(-(ILint)sizeof(SUNHEAD), IL_SEEK_CUR);
|
||||
|
||||
return iCheckSun(&Head);
|
||||
}
|
||||
|
||||
|
||||
// Reads a Sun file
|
||||
ILboolean ilLoadSun(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE SunFile;
|
||||
ILboolean bSun = IL_FALSE;
|
||||
|
||||
SunFile = iopenr(FileName);
|
||||
if (SunFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bSun;
|
||||
}
|
||||
|
||||
iSetInputFile(SunFile);
|
||||
|
||||
bSun = ilLoadSunF(SunFile);
|
||||
|
||||
icloser(SunFile);
|
||||
|
||||
return bSun;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened Sun file
|
||||
ILboolean ilLoadSunF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadSunInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a Sun
|
||||
ILboolean ilLoadSunL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadSunInternal();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadSunInternal(void)
|
||||
{
|
||||
SUNHEAD Header;
|
||||
BITFILE *File;
|
||||
ILuint i, j, Padding, Offset, BytesRead;
|
||||
ILubyte PaddingData[16];
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
//@TODO: Right now, iGetSunHead cannot fail.
|
||||
if (!iGetSunHead(&Header) || !iCheckSun(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
switch (Header.Depth)
|
||||
{
|
||||
case 1: //@TODO: Find a file to test this on.
|
||||
File = bfile(iGetFile());
|
||||
if (File == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
if (Header.ColorMapLength != 0) {
|
||||
// Data should be an index into the color map, but the color map should only be RGB (6 bytes, 2 entries).
|
||||
if (Header.ColorMapLength != 6) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
iCurImage->Pal.Palette = (ILubyte*)ialloc(6); // Just need 2 entries in the color map.
|
||||
if (Header.ColorMapLength == 0) { // Create the color map
|
||||
iCurImage->Pal.Palette[0] = 0x00; // Entry for black
|
||||
iCurImage->Pal.Palette[1] = 0x00;
|
||||
iCurImage->Pal.Palette[2] = 0x00;
|
||||
iCurImage->Pal.Palette[3] = 0xFF; // Entry for white
|
||||
iCurImage->Pal.Palette[4] = 0xFF;
|
||||
iCurImage->Pal.Palette[5] = 0xFF;
|
||||
}
|
||||
else {
|
||||
iread(iCurImage->Pal.Palette, 1, 6); // Read in the color map.
|
||||
}
|
||||
iCurImage->Pal.PalSize = 6;
|
||||
iCurImage->Pal.PalType = IL_PAL_RGB24;
|
||||
|
||||
Padding = (16 - (iCurImage->Width % 16)) % 16; // Has to be aligned on a 16-bit boundary. The rest is padding.
|
||||
|
||||
// Reads the bits
|
||||
for (i = 0; i < iCurImage->Height; i++) {
|
||||
bread(&iCurImage->Data[iCurImage->Width * i], 1, iCurImage->Width, File);
|
||||
//bseek(File, BitPadding, IL_SEEK_CUR); //@TODO: This function does not work correctly.
|
||||
bread(PaddingData, 1, Padding, File); // Skip padding bits.
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 8:
|
||||
if (Header.ColorMapType == IL_SUN_NO_MAP) { // Greyscale image
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
}
|
||||
else { // Colour-mapped image
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
iCurImage->Pal.Palette = (ILubyte*)ialloc(Header.ColorMapLength); // Allocate color map.
|
||||
if (iCurImage->Pal.Palette == NULL)
|
||||
return IL_FALSE;
|
||||
if (iread(iCurImage->Pal.Palette, 1, Header.ColorMapLength) != Header.ColorMapLength) { // Read color map.
|
||||
ilSetError(IL_FILE_READ_ERROR);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iCurImage->Pal.PalSize = Header.ColorMapLength;
|
||||
iCurImage->Pal.PalType = IL_PAL_RGB24;
|
||||
}
|
||||
|
||||
if (Header.Type != IL_SUN_BYTE_ENC) { // Regular uncompressed image data
|
||||
Padding = (2 - (iCurImage->Bps % 2)) % 2; // Must be padded on a 16-bit boundary (2 bytes)
|
||||
for (i = 0; i < Header.Height; i++) {
|
||||
iread(iCurImage->Data + i * Header.Width, 1, iCurImage->Bps);
|
||||
if (Padding) // Only possible for padding to be 0 or 1.
|
||||
igetc();
|
||||
}
|
||||
}
|
||||
else { // RLE image data
|
||||
for (i = 0; i < iCurImage->Height; i++) {
|
||||
BytesRead = iSunGetRle(iCurImage->Data + iCurImage->Bps * i, iCurImage->Bps);
|
||||
if (BytesRead % 2) // Each scanline must be aligned on a 2-byte boundary.
|
||||
igetc(); // Skip padding
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 24:
|
||||
if (Header.ColorMapLength > 0) // Ignore any possible colormaps.
|
||||
iseek(Header.ColorMapLength, IL_SEEK_CUR);
|
||||
|
||||
if (Header.Type == IL_SUN_RGB) {
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
}
|
||||
else {
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (Header.Type != IL_SUN_BYTE_ENC) { // Regular uncompressed image data
|
||||
Padding = (2 - (iCurImage->Bps % 2)) % 2; // Must be padded on a 16-bit boundary (2 bytes)
|
||||
for (i = 0; i < Header.Height; i++) {
|
||||
iread(iCurImage->Data + i * Header.Width * 3, 1, iCurImage->Bps);
|
||||
if (Padding) // Only possible for padding to be 0 or 1.
|
||||
igetc();
|
||||
}
|
||||
}
|
||||
else { // RLE image data
|
||||
for (i = 0; i < iCurImage->Height; i++) {
|
||||
BytesRead = iSunGetRle(iCurImage->Data + iCurImage->Bps * i, iCurImage->Bps);
|
||||
if (BytesRead % 2) // Each scanline must be aligned on a 2-byte boundary.
|
||||
igetc(); // Skip padding
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 32:
|
||||
if (Header.ColorMapLength > 0) // Ignore any possible colormaps.
|
||||
iseek(Header.ColorMapLength, IL_SEEK_CUR);
|
||||
|
||||
if (Header.Type == IL_SUN_RGB) {
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
}
|
||||
else {
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_BGR, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// There is no padding at the end of each scanline.
|
||||
Offset = 0;
|
||||
for (i = 0; i < Header.Height; i++) {
|
||||
for (j = 0; j < Header.Width; j++) {
|
||||
igetc(); // There is a pad byte before each pixel.
|
||||
iCurImage->Data[Offset] = igetc();
|
||||
iCurImage->Data[Offset+1] = igetc();
|
||||
iCurImage->Data[Offset+2] = igetc();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default: // Should have already been checked with iGetSunHead.
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
ILuint iSunGetRle(ILubyte *Data, ILuint Length)
|
||||
{
|
||||
ILuint i = 0, j;
|
||||
ILubyte Flag, Value;
|
||||
ILuint Count;
|
||||
|
||||
for (i = 0; i < Length; ) {
|
||||
Flag = igetc();
|
||||
if (Flag == 0x80) { // Run follows (or 1 byte of 0x80)
|
||||
Count = igetc();
|
||||
if (Count == 0) { // 1 pixel of value (0x80)
|
||||
*Data = 0x80;
|
||||
Data++;
|
||||
i++;
|
||||
}
|
||||
else { // Here we have a run.
|
||||
Value = igetc();
|
||||
Count++; // Should really be Count+1
|
||||
for (j = 0; j < Count && i + j < Length; j++, Data++) {
|
||||
*Data = Value;
|
||||
}
|
||||
i += Count;
|
||||
}
|
||||
}
|
||||
else { // 1 byte of this value (cannot be 0x80)
|
||||
*Data = Flag;
|
||||
Data++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_SUN
|
||||
|
||||
@@ -0,0 +1,955 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// 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 void *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 = (ILubyte)igetc();
|
||||
Header->ColMapPresent = (ILubyte)igetc();
|
||||
Header->ImageType = (ILubyte)igetc();
|
||||
Header->FirstEntry = GetLittleShort();
|
||||
Header->ColMapLen = GetLittleShort();
|
||||
Header->ColMapEntSize = (ILubyte)igetc();
|
||||
|
||||
Header->OriginX = GetLittleShort();
|
||||
Header->OriginY = GetLittleShort();
|
||||
Header->Width = GetLittleUShort();
|
||||
Header->Height = GetLittleUShort();
|
||||
Header->Bpp = (ILubyte)igetc();
|
||||
Header->ImageDesc = (ILubyte)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 void *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;
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
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, ToRead;
|
||||
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 = (ILubyte)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) {
|
||||
// Read the color in, but we check to make sure that we do not go past the end of the image.
|
||||
for (c = 0; c < Image->Bpp && BytesRead+i+c < Size; c++) {
|
||||
Image->Data[BytesRead+i+c] = Color[c];
|
||||
}
|
||||
}
|
||||
BytesRead += RunLen;
|
||||
}
|
||||
else {
|
||||
RunLen = (Header+1) * Image->Bpp;
|
||||
// We have to check that we do not go past the end of the image data.
|
||||
if (BytesRead + RunLen > Size)
|
||||
ToRead = Size - BytesRead;
|
||||
else
|
||||
ToRead = RunLen;
|
||||
if (iread(Image->Data + BytesRead, 1, ToRead) != ToRead) {
|
||||
iUnCache(); //@TODO: Error needed here?
|
||||
return IL_FALSE;
|
||||
}
|
||||
BytesRead += RunLen;
|
||||
|
||||
if (BytesRead + RunLen > Size)
|
||||
iseek(RunLen - ToRead, IL_SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
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(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE TargaFile;
|
||||
ILuint TargaSize;
|
||||
|
||||
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 IL_FALSE;
|
||||
}
|
||||
|
||||
TargaSize = ilSaveTargaF(TargaFile);
|
||||
iclosew(TargaFile);
|
||||
|
||||
if (TargaSize == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Targa to an already-opened file
|
||||
ILuint ilSaveTargaF(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputFile(File);
|
||||
Pos = itellw();
|
||||
if (iSaveTargaInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Targa to a memory "lump"
|
||||
ILuint ilSaveTargaL(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos = itellw();
|
||||
iSetOutputLump(Lump, Size);
|
||||
if (iSaveTargaInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to save the Targa.
|
||||
ILboolean iSaveTargaInternal()
|
||||
{
|
||||
const char *ID = iGetString(IL_TGA_ID_STRING);
|
||||
const char *AuthName = iGetString(IL_TGA_AUTHNAME_STRING);
|
||||
const 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)ilCharStrLen(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 = (ILshort)(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 = (ILshort)(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, ilCharStrLen(AuthName));
|
||||
ipad(41 - ilCharStrLen(AuthName));
|
||||
iwrite(AuthComment, 1, ilCharStrLen(AuthComment));
|
||||
ipad(324 - ilCharStrLen(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, ilCharStrLen(idString)); // Software ID
|
||||
for (i = 0; i < 41 - ilCharStrLen(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, ilCharStrLen(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;
|
||||
}
|
||||
|
||||
|
||||
// Only to be called by ilDetermineSize. Returns the buffer size needed to save the
|
||||
// current image as a Targa file.
|
||||
ILuint iTargaSize(void)
|
||||
{
|
||||
ILuint Size, Bpp;
|
||||
ILubyte IDLen = 0;
|
||||
const char *ID = iGetString(IL_TGA_ID_STRING);
|
||||
const char *AuthName = iGetString(IL_TGA_AUTHNAME_STRING);
|
||||
const char *AuthComment = iGetString(IL_TGA_AUTHCOMMENT_STRING);
|
||||
|
||||
//@TODO: Support color indexed images.
|
||||
if (iGetInt(IL_TGA_RLE) == IL_TRUE || iCurImage->Format == IL_COLOUR_INDEX) {
|
||||
// Use the slower method, since we are using compression. We do a "fake" write.
|
||||
ilSaveTargaL(NULL, 0);
|
||||
}
|
||||
|
||||
if (ID)
|
||||
IDLen = (ILubyte)ilCharStrLen(ID);
|
||||
|
||||
Size = 18 + IDLen; // Header + ID
|
||||
|
||||
// Bpp may not be iCurImage->Bpp.
|
||||
switch (iCurImage->Format)
|
||||
{
|
||||
case IL_BGR:
|
||||
case IL_RGB:
|
||||
Bpp = 3;
|
||||
break;
|
||||
case IL_BGRA:
|
||||
case IL_RGBA:
|
||||
Bpp = 4;
|
||||
break;
|
||||
case IL_LUMINANCE:
|
||||
Bpp = 1;
|
||||
break;
|
||||
default: //@TODO: Do not know what to do with the others yet.
|
||||
return 0;
|
||||
}
|
||||
|
||||
Size += iCurImage->Width * iCurImage->Height * Bpp;
|
||||
Size += 532; // Size of the extension area
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
/*// Makes a neat string to go into the id field of the .tga
|
||||
void 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 - ilCharStrLen(PSG), "%#c (%z)", CurTime);
|
||||
//strftime(TimeStr, 255 - ilCharStrLen(PSG), "%C (%Z)", CurTime);
|
||||
sprintf(Str, "%s%s", PSG, TimeStr);
|
||||
|
||||
return;
|
||||
}*/
|
||||
|
||||
|
||||
//changed name to iGetDateTime on 20031221 to fix bug 830196
|
||||
void 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
|
||||
@@ -0,0 +1,66 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 02/16/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_texture.c
|
||||
//
|
||||
// Description: Reads from a Medieval II: Total War (by Creative Assembly)
|
||||
// Texture (.texture) file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_TEXTURE
|
||||
|
||||
|
||||
//! Reads a TEXTURE file
|
||||
ILboolean ilLoadTexture(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE TextureFile;
|
||||
ILboolean bTexture = IL_FALSE;
|
||||
|
||||
TextureFile = iopenr(FileName);
|
||||
if (TextureFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bTexture;
|
||||
}
|
||||
|
||||
bTexture = ilLoadTextureF(TextureFile);
|
||||
icloser(TextureFile);
|
||||
|
||||
return bTexture;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened TEXTURE file
|
||||
ILboolean ilLoadTextureF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
// From http://forums.totalwar.org/vb/showthread.php?t=70886, all that needs to be done
|
||||
// is to strip out the first 48 bytes, and then it is DDS data.
|
||||
iseek(48, IL_SEEK_CUR);
|
||||
bRet = ilLoadDdsF(File);
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a TEXTURE
|
||||
ILboolean ilLoadTextureL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
// From http://forums.totalwar.org/vb/showthread.php?t=70886, all that needs to be done
|
||||
// is to strip out the first 48 bytes, and then it is DDS data.
|
||||
iseek(48, IL_SEEK_CUR);
|
||||
return ilLoadDdsL(Lump, Size);
|
||||
}
|
||||
|
||||
#endif//IL_NO_TEXTURE
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,782 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_tpl.c
|
||||
//
|
||||
// Description: Reads from a Gamecube Texture Palette (.tpl).
|
||||
// Specifications were found at
|
||||
// http://pabut.homeip.net:8000/yagcd/chap14.html.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_TPL
|
||||
#include "il_dds.h"
|
||||
|
||||
|
||||
typedef struct TPLHEAD
|
||||
{
|
||||
ILuint Magic;
|
||||
ILuint nTextures;
|
||||
ILuint HeaderSize;
|
||||
} TPLHEAD;
|
||||
|
||||
// Data formats
|
||||
#define TPL_I4 0
|
||||
#define TPL_I8 1
|
||||
#define TPL_IA4 2
|
||||
#define TPL_IA8 3
|
||||
#define TPL_RGB565 4
|
||||
#define TPL_RGB5A3 5
|
||||
#define TPL_RGBA8 6
|
||||
#define TPL_CI4 8
|
||||
#define TPL_CI8 9
|
||||
#define TPL_CI14X2 10
|
||||
#define TPL_CMP 14
|
||||
|
||||
// Wrapping
|
||||
#define TPL_CLAMP 0
|
||||
#define TPL_REPEAT 1
|
||||
#define TPL_MIRROR 2
|
||||
|
||||
// Palette entries
|
||||
#define TPL_PAL_IA8 0
|
||||
#define TPL_PAL_RGB565 1
|
||||
#define TPL_PAL_RGB5A3 2
|
||||
|
||||
|
||||
ILboolean iIsValidTpl(void);
|
||||
ILboolean iCheckTpl(TPLHEAD *Header);
|
||||
ILboolean iLoadTplInternal(void);
|
||||
ILboolean TplGetIndexImage(ILimage *Image, ILuint TexOff, ILuint DataFormat);
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid TPL file.
|
||||
ILboolean ilIsValidTpl(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE TplFile;
|
||||
ILboolean bTpl = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("tpl"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bTpl;
|
||||
}
|
||||
|
||||
TplFile = iopenr(FileName);
|
||||
if (TplFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bTpl;
|
||||
}
|
||||
|
||||
bTpl = ilIsValidTplF(TplFile);
|
||||
icloser(TplFile);
|
||||
|
||||
return bTpl;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid TPL file at the current position.
|
||||
ILboolean ilIsValidTplF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidTpl();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid TPL lump.
|
||||
ILboolean ilIsValidTplL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidTpl();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the TPL header from the current file.
|
||||
ILboolean iGetTplHead(TPLHEAD *Header)
|
||||
{
|
||||
Header->Magic = GetBigUInt();
|
||||
Header->nTextures = GetBigUInt();
|
||||
Header->HeaderSize = GetBigUInt();
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidTpl(void)
|
||||
{
|
||||
TPLHEAD Header;
|
||||
|
||||
if (!iGetTplHead(&Header))
|
||||
return IL_FALSE;
|
||||
iseek(-12, IL_SEEK_CUR);
|
||||
|
||||
return iCheckTpl(&Header);
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to check if the HEADER is a valid TPL header.
|
||||
ILboolean iCheckTpl(TPLHEAD *Header)
|
||||
{
|
||||
// The file signature is 0x0020AF30.
|
||||
if (Header->Magic != 0x0020AF30)
|
||||
return IL_FALSE;
|
||||
// Only valid header size is 0x0C.
|
||||
if (Header->HeaderSize != 0x0C)
|
||||
return IL_FALSE;
|
||||
// We have to have at least 1 texture.
|
||||
if (Header->nTextures == 0)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a TPL file
|
||||
ILboolean ilLoadTpl(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE TplFile;
|
||||
ILboolean bTpl = IL_FALSE;
|
||||
|
||||
TplFile = iopenr(FileName);
|
||||
if (TplFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bTpl;
|
||||
}
|
||||
|
||||
bTpl = ilLoadTplF(TplFile);
|
||||
icloser(TplFile);
|
||||
|
||||
return bTpl;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened TPL file
|
||||
ILboolean ilLoadTplF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadTplInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a TPL
|
||||
ILboolean ilLoadTplL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadTplInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the TPL.
|
||||
ILboolean iLoadTplInternal(void)
|
||||
{
|
||||
TPLHEAD Header;
|
||||
ILimage *Image/*, *BaseImage*/;
|
||||
ILuint Pos, TexOff, PalOff, DataFormat, Bpp, DataOff, WrapS, WrapT;
|
||||
ILuint x, y, xBlock, yBlock, i, j, k, n;
|
||||
ILenum Format;
|
||||
ILushort Width, Height, ShortPixel;
|
||||
ILubyte BytePixel, CompData[8];
|
||||
Color8888 colours[4], *col;
|
||||
ILushort color_0, color_1;
|
||||
ILuint bitmask, Select;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
Image = iCurImage; // Top-level image
|
||||
|
||||
if (!iGetTplHead(&Header))
|
||||
return IL_FALSE;
|
||||
if (!iCheckTpl(&Header)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Points to the beginning of the texture header directory.
|
||||
Pos = itell();
|
||||
|
||||
for (n = 0; n < Header.nTextures; n++) {
|
||||
// Go back to the texture header directory for texture number n+1.
|
||||
iseek(Pos + n * 8, IL_SEEK_SET);
|
||||
TexOff = GetBigUInt();
|
||||
PalOff = GetBigUInt();
|
||||
// Go to the texture header.
|
||||
if (iseek(TexOff, IL_SEEK_SET))
|
||||
return IL_FALSE;
|
||||
|
||||
Height = GetBigUShort();
|
||||
Width = GetBigUShort();
|
||||
// It looks like files actually have n-1 images, with the nth one having 0 height and width.
|
||||
if (Width == 0 || Height == 0) {
|
||||
// If this is our first image, however, we error out.
|
||||
if (Image == iCurImage) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
// Break out of our for loop and run ilFixImage on the images.
|
||||
break;
|
||||
}
|
||||
|
||||
DataFormat = GetBigUInt();
|
||||
TexOff = GetBigUInt();
|
||||
WrapS = GetBigUInt();
|
||||
WrapT = GetBigUInt();
|
||||
if (WrapS == TPL_REPEAT || WrapS == TPL_MIRROR) {
|
||||
// By the specs, repeated and mirrored textures must have dimensions of power of 2.
|
||||
if ((Width != ilNextPower2(Width)) || (Height != ilNextPower2(Height))) {
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Go to the actual texture data.
|
||||
if (iseek(TexOff, IL_SEEK_SET))
|
||||
return IL_FALSE;
|
||||
|
||||
switch (DataFormat)
|
||||
{
|
||||
case TPL_I4:
|
||||
case TPL_I8:
|
||||
Format = IL_LUMINANCE;
|
||||
Bpp = 1;
|
||||
break;
|
||||
case TPL_IA4:
|
||||
case TPL_IA8:
|
||||
Format = IL_LUMINANCE_ALPHA;
|
||||
Bpp = 1;
|
||||
break;
|
||||
case TPL_RGB565:
|
||||
Format = IL_RGB;
|
||||
Bpp = 3;
|
||||
break;
|
||||
case TPL_RGB5A3:
|
||||
Format = IL_RGBA;
|
||||
Bpp = 4;
|
||||
break;
|
||||
case TPL_RGBA8:
|
||||
Format = IL_RGBA;
|
||||
Bpp = 4;
|
||||
break;
|
||||
case TPL_CI4:
|
||||
case TPL_CI8:
|
||||
Format = IL_COLOR_INDEX;
|
||||
Bpp = 1;
|
||||
break;
|
||||
case TPL_CI14X2:
|
||||
Format = IL_RGBA;
|
||||
Bpp = 3;
|
||||
break;
|
||||
case TPL_CMP:
|
||||
Format = IL_RGBA;
|
||||
Bpp = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (Image == iCurImage) { // This is our first image.
|
||||
if (!ilTexImage(Width, Height, 1, Bpp, Format, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
}
|
||||
else {
|
||||
Image->Next = ilNewImageFull(Width, Height, 1, Bpp, Format, IL_UNSIGNED_BYTE, NULL);
|
||||
if (Image->Next == NULL)
|
||||
return IL_FALSE;
|
||||
Image = Image->Next;
|
||||
}
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT; // Origins are always fixed here.
|
||||
|
||||
switch (DataFormat)
|
||||
{
|
||||
case TPL_I4:
|
||||
// 8x8 tiles of 4-bit intensity values
|
||||
for (y = 0; y < Image->Height; y += 8) {
|
||||
for (x = 0; x < Image->Width; x += 8) {
|
||||
for (yBlock = 0; yBlock < 8; yBlock++) {
|
||||
if ((y + yBlock) >= Image->Height) {
|
||||
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
|
||||
continue;
|
||||
}
|
||||
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
|
||||
for (xBlock = 0; xBlock < 8; xBlock += 2) {
|
||||
BytePixel = igetc();
|
||||
if ((x + xBlock) >= Image->Width)
|
||||
continue; // Already read the pad byte.
|
||||
Image->Data[DataOff] = (BytePixel & 0xF0) | (BytePixel & 0xF0) >> 4;
|
||||
DataOff++;
|
||||
// We have to do this check again, so we do not go past the last pixel in the image (ex. 1 pixel wide image).
|
||||
if ((x + xBlock) >= Image->Width)
|
||||
continue; // Already read the pad byte.
|
||||
Image->Data[DataOff+1] = (BytePixel & 0x0F) << 4 | (BytePixel & 0x0F);
|
||||
DataOff++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TPL_I8:
|
||||
// 8x4 tiles of 8-bit intensity values
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 8) {
|
||||
for (yBlock = 0; yBlock < 4; yBlock++) {
|
||||
if ((y + yBlock) >= Image->Height) {
|
||||
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
|
||||
continue;
|
||||
}
|
||||
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
|
||||
for (xBlock = 0; xBlock < 8; xBlock++) {
|
||||
if ((x + xBlock) >= Image->Width) {
|
||||
igetc(); // Skip the pad byte.
|
||||
continue;
|
||||
}
|
||||
Image->Data[DataOff] = igetc(); // Luminance value
|
||||
DataOff++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TPL_IA4:
|
||||
// 8x4 tiles of 4-bit intensity and 4-bit alpha values
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 8) {
|
||||
for (yBlock = 0; yBlock < 4; yBlock++) {
|
||||
if ((y + yBlock) >= Image->Height) {
|
||||
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
|
||||
continue;
|
||||
}
|
||||
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
|
||||
for (xBlock = 0; xBlock < 8; xBlock += 2) {
|
||||
BytePixel = igetc();
|
||||
if ((x + xBlock) >= Image->Width)
|
||||
continue; // Already read the pad byte.
|
||||
Image->Data[DataOff] = (BytePixel & 0xF0) | (BytePixel & 0xF0) >> 4;
|
||||
Image->Data[DataOff+1] = (BytePixel & 0x0F) << 4 | (BytePixel & 0x0F);
|
||||
DataOff += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TPL_IA8:
|
||||
// 4x4 tiles of 8-bit intensity and 8-bit alpha values
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 4) {
|
||||
for (yBlock = 0; yBlock < 4; yBlock++) {
|
||||
if ((y + yBlock) >= Image->Height) {
|
||||
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
|
||||
continue;
|
||||
}
|
||||
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
|
||||
for (xBlock = 0; xBlock < 4; xBlock += 2) {
|
||||
if ((x + xBlock) >= Image->Width) {
|
||||
iseek(2, IL_SEEK_CUR); // Skip the pad bytes.
|
||||
continue;
|
||||
}
|
||||
Image->Data[DataOff] = igetc();
|
||||
Image->Data[DataOff+1] = igetc();
|
||||
DataOff += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TPL_RGB565:
|
||||
// 4x4 tiles of RGB565 data
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 4) {
|
||||
for (yBlock = 0; yBlock < 4; yBlock++) {
|
||||
if ((y + yBlock) >= Image->Height) {
|
||||
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
|
||||
continue;
|
||||
}
|
||||
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
|
||||
for (xBlock = 0; xBlock < 4; xBlock++) {
|
||||
ShortPixel = GetBigUShort();
|
||||
if ((x + xBlock) >= Image->Width)
|
||||
continue; // Already read the pad byte.
|
||||
Image->Data[DataOff] = ((ShortPixel & 0xF800) >> 8) | ((ShortPixel & 0xE000) >> 13); // Red
|
||||
Image->Data[DataOff+1] = ((ShortPixel & 0x7E0) >> 3) | ((ShortPixel & 0x600) >> 9); // Green
|
||||
Image->Data[DataOff+2] = ((ShortPixel & 0x1f) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
|
||||
DataOff += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TPL_RGB5A3:
|
||||
// 4x4 tiles of either RGB5 or RGB4A3 depending on the MSB. 0x80
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 4) {
|
||||
for (yBlock = 0; yBlock < 4; yBlock++) {
|
||||
if ((y + yBlock) >= Image->Height) {
|
||||
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
|
||||
continue;
|
||||
}
|
||||
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
|
||||
for (xBlock = 0; xBlock < 4; xBlock++) {
|
||||
ShortPixel = GetBigUShort();
|
||||
if ((x + xBlock) >= Image->Width)
|
||||
continue; // Already read the pad byte.
|
||||
|
||||
if (ShortPixel & 0x8000) { // Check MSB.
|
||||
// We have RGB5.
|
||||
Image->Data[DataOff] = ((ShortPixel & 0x7C00) >> 7) | ((ShortPixel & 0x7000) >> 12); // Red
|
||||
Image->Data[DataOff+1] = ((ShortPixel & 0x3E0) >> 2) | ((ShortPixel & 0x380) >> 7); // Green
|
||||
Image->Data[DataOff+2] = ((ShortPixel & 0x1F) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
|
||||
Image->Data[DataOff+3] = 0xFF; // I am just assuming that it is opaque.
|
||||
}
|
||||
else {
|
||||
// We have RGB4A3.
|
||||
Image->Data[DataOff] = ((ShortPixel & 0x7800) >> 7) | ((ShortPixel & 0x7800) >> 11); // Red
|
||||
Image->Data[DataOff+1] = ((ShortPixel & 0x0780) >> 3) | ((ShortPixel & 0x0780) >> 7); // Green
|
||||
Image->Data[DataOff+2] = ((ShortPixel & 0x0078) << 1) | ((ShortPixel & 0x0078) >> 3); // Blue
|
||||
Image->Data[DataOff+3] = ((ShortPixel & 0x07) << 5) | ((ShortPixel & 0x07) << 2) | (ShortPixel >> 1); // Alpha
|
||||
}
|
||||
DataOff += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TPL_RGBA8:
|
||||
// 4x4 tiles of RGBA data
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 4) {
|
||||
for (yBlock = 0; yBlock < 4; yBlock++) {
|
||||
// Skip pad bytes at the bottom of the tile if any.
|
||||
if ((y + yBlock) >= Image->Height) {
|
||||
iseek(16, IL_SEEK_CUR); // Entire row of pad bytes skipped
|
||||
continue;
|
||||
}
|
||||
|
||||
// First it has the AR data.
|
||||
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
|
||||
for (xBlock = 0; xBlock < 4; xBlock++) {
|
||||
if ((x + xBlock) >= Image->Width) {
|
||||
iseek(2, IL_SEEK_CUR); // Skip pad bytes.
|
||||
continue;
|
||||
}
|
||||
Image->Data[DataOff+3] = igetc(); // Alpha
|
||||
Image->Data[DataOff] = igetc(); // Red
|
||||
DataOff += 3;
|
||||
}
|
||||
|
||||
// Then it has the GB data.
|
||||
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
|
||||
for (xBlock = 0; xBlock < 4 && x + xBlock < Image->Width; xBlock++) {
|
||||
if ((x + xBlock) >= Image->Width) {
|
||||
iseek(2, IL_SEEK_CUR); // Skip pad bytes.
|
||||
continue;
|
||||
}
|
||||
Image->Data[DataOff+1] = igetc(); // Green
|
||||
Image->Data[DataOff+2] = igetc(); // Blue
|
||||
DataOff += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TPL_CI4:
|
||||
case TPL_CI8:
|
||||
case TPL_CI14X2:
|
||||
// Seek to the palette header.
|
||||
if (iseek(PalOff, IL_SEEK_SET))
|
||||
return IL_FALSE;
|
||||
if (!TplGetIndexImage(Image, TexOff, DataFormat))
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case TPL_CMP:
|
||||
// S3TC 2x2 blocks of 4x4 tiles. I am assuming that this is DXT1, since it is not specified in the specs.
|
||||
// Most of this ended up being copied from il_dds.c, from the DecompressDXT1 function.
|
||||
//@TODO: Make this/that code a bit more modular.
|
||||
for (y = 0; y < Image->Height; y += 8) {
|
||||
for (x = 0; x < Image->Width; x += 8) {
|
||||
for (yBlock = 0; yBlock < 8 && (y + yBlock) < Image->Height; yBlock += 4) {
|
||||
for (xBlock = 0; xBlock < 8 && (x + xBlock) < Image->Width; xBlock += 4) {
|
||||
if (iread(CompData, 1, 8) != 8)
|
||||
return IL_FALSE; //@TODO: Need to do any cleanup here?
|
||||
color_0 = *((ILushort*)CompData);
|
||||
UShort(&color_0);
|
||||
color_1 = *((ILushort*)(CompData + 2));
|
||||
UShort(&color_1);
|
||||
DxtcReadColor(color_0, colours);
|
||||
DxtcReadColor(color_1, colours + 1);
|
||||
bitmask = ((ILuint*)CompData)[1];
|
||||
UInt(&bitmask);
|
||||
|
||||
if (color_0 > color_1) {
|
||||
// Four-color block: derive the other two colors.
|
||||
// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
|
||||
// These 2-bit codes correspond to the 2-bit fields
|
||||
// stored in the 64-bit block.
|
||||
colours[2].b = (2 * colours[0].b + colours[1].b + 1) / 3;
|
||||
colours[2].g = (2 * colours[0].g + colours[1].g + 1) / 3;
|
||||
colours[2].r = (2 * colours[0].r + colours[1].r + 1) / 3;
|
||||
//colours[2].a = 0xFF;
|
||||
|
||||
colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
|
||||
colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
|
||||
colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
|
||||
colours[3].a = 0xFF;
|
||||
}
|
||||
else {
|
||||
// Three-color block: derive the other color.
|
||||
// 00 = color_0, 01 = color_1, 10 = color_2,
|
||||
// 11 = transparent.
|
||||
// These 2-bit codes correspond to the 2-bit fields
|
||||
// stored in the 64-bit block.
|
||||
colours[2].b = (colours[0].b + colours[1].b) / 2;
|
||||
colours[2].g = (colours[0].g + colours[1].g) / 2;
|
||||
colours[2].r = (colours[0].r + colours[1].r) / 2;
|
||||
//colours[2].a = 0xFF;
|
||||
|
||||
colours[3].b = (colours[0].b + 2 * colours[1].b + 1) / 3;
|
||||
colours[3].g = (colours[0].g + 2 * colours[1].g + 1) / 3;
|
||||
colours[3].r = (colours[0].r + 2 * colours[1].r + 1) / 3;
|
||||
colours[3].a = 0x00;
|
||||
}
|
||||
|
||||
for (j = 0, k = 0; j < 4; j++) {
|
||||
for (i = 0; i < 4; i++, k++) {
|
||||
Select = (bitmask & (0x03 << k*2)) >> k*2;
|
||||
col = &colours[Select];
|
||||
|
||||
if (((x + xBlock + i) < Image->Width) && ((y + yBlock + j) < Image->Height)) {
|
||||
DataOff = (y + yBlock + j) * Image->Bps + (x + xBlock + i) * Image->Bpp;
|
||||
Image->Data[DataOff + 0] = col->r;
|
||||
Image->Data[DataOff + 1] = col->g;
|
||||
Image->Data[DataOff + 2] = col->b;
|
||||
Image->Data[DataOff + 3] = col->a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
ILboolean TplGetIndexImage(ILimage *Image, ILuint TexOff, ILuint DataFormat)
|
||||
{
|
||||
ILushort NumPal, ShortPixel;
|
||||
ILubyte LumVal, BytePixel;
|
||||
ILuint PalFormat, PalOff, PalBpp, DataOff;
|
||||
ILuint x, y, xBlock, yBlock, i;
|
||||
|
||||
NumPal = GetBigUShort();
|
||||
iseek(2, IL_SEEK_CUR); // Do we need to do anything with the 'unpacked' entry? I see nothing in the specs about it.
|
||||
PalFormat = GetBigUInt();
|
||||
|
||||
// Now we have to find out where the actual palette data is stored.
|
||||
//@TODO: Do we need to set any errors here?
|
||||
PalOff = GetBigUInt();
|
||||
if (iseek(PalOff, IL_SEEK_SET))
|
||||
return IL_FALSE;
|
||||
|
||||
switch (PalFormat)
|
||||
{
|
||||
case TPL_PAL_IA8:
|
||||
Image->Pal.Palette = (ILubyte*)ialloc(NumPal * 4);
|
||||
if (Image->Pal.Palette == NULL)
|
||||
return IL_FALSE;
|
||||
Image->Pal.PalType = IL_PAL_RGBA32; //@TODO: Use this format natively.
|
||||
Image->Pal.PalSize = NumPal * 4;
|
||||
PalBpp = 4;
|
||||
|
||||
for (i = 0; i < NumPal; i++) {
|
||||
LumVal = igetc();
|
||||
//@TODO: Do proper conversion of luminance, or support this format natively.
|
||||
Image->Pal.Palette[i * 4] = LumVal; // Assign the luminance value.
|
||||
Image->Pal.Palette[i * 4 + 1] = LumVal;
|
||||
Image->Pal.Palette[i * 4 + 2] = LumVal;
|
||||
Image->Pal.Palette[i * 4 + 3] = igetc(); // Get alpha value.
|
||||
}
|
||||
break;
|
||||
|
||||
case TPL_PAL_RGB565:
|
||||
Image->Pal.Palette = (ILubyte*)ialloc(NumPal * 3);
|
||||
if (Image->Pal.Palette == NULL)
|
||||
return IL_FALSE;
|
||||
Image->Pal.PalType = IL_PAL_RGB24;
|
||||
Image->Pal.PalSize = NumPal * 3;
|
||||
PalBpp = 3;
|
||||
|
||||
for (i = 0; i < NumPal; i++) {
|
||||
ShortPixel = GetBigUShort();
|
||||
// This is mostly the same code as in the TPL_RGB565 case.
|
||||
Image->Pal.Palette[i*3] = ((ShortPixel & 0xF800) >> 8) | ((ShortPixel & 0xE000) >> 13); // Red
|
||||
Image->Pal.Palette[i*3+1] = ((ShortPixel & 0x7E0) >> 3) | ((ShortPixel & 0x600) >> 9); // Green
|
||||
Image->Pal.Palette[i*3+2] = ((ShortPixel & 0x1f) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
|
||||
}
|
||||
break;
|
||||
|
||||
case TPL_PAL_RGB5A3:
|
||||
Image->Pal.Palette = (ILubyte*)ialloc(NumPal * 4);
|
||||
if (Image->Pal.Palette == NULL)
|
||||
return IL_FALSE;
|
||||
Image->Pal.PalType = IL_PAL_RGBA32;
|
||||
Image->Pal.PalSize = NumPal * 4;
|
||||
PalBpp = 4;
|
||||
|
||||
for (i = 0; i < NumPal; i++) {
|
||||
ShortPixel = GetBigUShort();
|
||||
// This is mostly the same code as in the TPL_RGB565 case.
|
||||
if (ShortPixel & 0x8000) { // Check MSB.
|
||||
// We have RGB5.
|
||||
Image->Pal.Palette[i*4] = ((ShortPixel & 0x7C00) >> 7) | ((ShortPixel & 0x7000) >> 12); // Red
|
||||
Image->Pal.Palette[i*4+1] = ((ShortPixel & 0x3E0) >> 2) | ((ShortPixel & 0x380) >> 7); // Green
|
||||
Image->Pal.Palette[i*4+2] = ((ShortPixel & 0x1F) << 3) | ((ShortPixel & 0x1C) >> 2); // Blue
|
||||
Image->Pal.Palette[i*4+3] = 0xFF; // I am just assuming that it is opaque.
|
||||
}
|
||||
else {
|
||||
// We have RGB4A3.
|
||||
Image->Pal.Palette[i*4] = ((ShortPixel & 0x7800) >> 7) | ((ShortPixel & 0x7800) >> 11); // Red
|
||||
Image->Pal.Palette[i*4+1] = ((ShortPixel & 0x0780) >> 3) | ((ShortPixel & 0x0780) >> 7); // Green
|
||||
Image->Pal.Palette[i*4+2] = ((ShortPixel & 0x0078) << 1) | ((ShortPixel & 0x0078) >> 3); // Blue
|
||||
Image->Pal.Palette[i*4+3] = ((ShortPixel & 0x07) << 5) | ((ShortPixel & 0x07) << 2) | (ShortPixel >> 1); // Alpha
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// Go back to the texture data.
|
||||
if (iseek(TexOff, IL_SEEK_SET))
|
||||
return IL_FALSE;
|
||||
|
||||
switch (DataFormat)
|
||||
{
|
||||
case TPL_CI4:
|
||||
// 8x8 tiles of 4-bit color indices
|
||||
// This is the exact same code as the TPL_I4 case.
|
||||
for (y = 0; y < Image->Height; y += 8) {
|
||||
for (x = 0; x < Image->Width; x += 8) {
|
||||
for (yBlock = 0; yBlock < 8; yBlock++) {
|
||||
if ((y + yBlock) >= Image->Height) {
|
||||
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
|
||||
continue;
|
||||
}
|
||||
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
|
||||
for (xBlock = 0; xBlock < 8; xBlock += 2) {
|
||||
BytePixel = igetc();
|
||||
if ((x + xBlock) >= Image->Width)
|
||||
continue; // Already read the pad byte.
|
||||
Image->Data[DataOff] = (BytePixel & 0xF0) | (BytePixel & 0xF0) >> 4;
|
||||
DataOff++;
|
||||
// We have to do this check again, so we do not go past the last pixel in the image (ex. 1 pixel wide image).
|
||||
if ((x + xBlock) >= Image->Width)
|
||||
continue; // Already read the pad byte.
|
||||
Image->Data[DataOff+1] = (BytePixel & 0x0F) << 4 | (BytePixel & 0x0F);
|
||||
DataOff++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TPL_CI8:
|
||||
// 8x4 tiles of 8-bit intensity values
|
||||
// This is the exact same code as the TPL_I8 case.
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 8) {
|
||||
for (yBlock = 0; yBlock < 4; yBlock++) {
|
||||
if ((y + yBlock) >= Image->Height) {
|
||||
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
|
||||
continue;
|
||||
}
|
||||
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
|
||||
for (xBlock = 0; xBlock < 8; xBlock++) {
|
||||
if ((x + xBlock) >= Image->Width) {
|
||||
igetc(); // Skip the pad byte.
|
||||
continue;
|
||||
}
|
||||
Image->Data[DataOff] = igetc(); // Color index
|
||||
DataOff++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
//@TODO: Convert to more formats than just RGBA.
|
||||
case TPL_CI14X2:
|
||||
// 4x4 tiles of 14-bit indices into a palette. Not supported at all in DevIL, since
|
||||
// it has a huge palette (> 256 colors). Convert to RGBA.
|
||||
for (y = 0; y < Image->Height; y += 4) {
|
||||
for (x = 0; x < Image->Width; x += 4) {
|
||||
for (yBlock = 0; yBlock < 4; yBlock++) {
|
||||
if ((y + yBlock) >= Image->Height) {
|
||||
iseek(8, IL_SEEK_CUR); // Entire row of pad bytes skipped.
|
||||
continue;
|
||||
}
|
||||
DataOff = Image->Bps * (y + yBlock) + Image->Bpp * x;
|
||||
for (xBlock = 0; xBlock < 4; xBlock++) {
|
||||
if ((x + xBlock) >= Image->Width) {
|
||||
GetBigUShort(); // Skip the pad short.
|
||||
continue;
|
||||
}
|
||||
ShortPixel = GetBigUShort();
|
||||
ShortPixel >>= 2; // Lower 2 bits are padding bits.
|
||||
Image->Data[DataOff] = Image->Pal.Palette[ShortPixel * PalBpp];
|
||||
Image->Data[DataOff+1] = Image->Pal.Palette[ShortPixel * PalBpp + 1];
|
||||
Image->Data[DataOff+2] = Image->Pal.Palette[ShortPixel * PalBpp + 2];
|
||||
if (PalFormat == TPL_PAL_RGB565)
|
||||
Image->Data[DataOff+3] = 0xFF;
|
||||
else
|
||||
Image->Data[DataOff+3] = Image->Pal.Palette[ShortPixel * PalBpp + 3];
|
||||
DataOff++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get rid of the palette, since we no longer need it.
|
||||
ifree(Image->Pal.Palette);
|
||||
Image->Pal.PalType = IL_PAL_NONE;
|
||||
Image->Pal.PalSize = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
#endif//IL_NO_TPL
|
||||
@@ -0,0 +1,171 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 02/04/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_utility.c
|
||||
//
|
||||
// Description: Utility functions
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
|
||||
|
||||
// Returns the bpp of any Format
|
||||
ILAPI ILubyte ILAPIENTRY ilGetBppFormat(ILenum Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case IL_COLOUR_INDEX:
|
||||
case IL_LUMINANCE:
|
||||
case IL_ALPHA:
|
||||
return 1;
|
||||
case IL_LUMINANCE_ALPHA:
|
||||
return 2;
|
||||
case IL_RGB:
|
||||
case IL_BGR:
|
||||
return 3;
|
||||
case IL_RGBA:
|
||||
case IL_BGRA:
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns the format of any bpp
|
||||
ILAPI ILenum ILAPIENTRY ilGetFormatBpp(ILubyte Bpp)
|
||||
{
|
||||
switch (Bpp)
|
||||
{
|
||||
case 1:
|
||||
return IL_LUMINANCE;
|
||||
case 2:
|
||||
return IL_LUMINANCE_ALPHA;
|
||||
case 3:
|
||||
return IL_RGB;
|
||||
case 4:
|
||||
return IL_RGBA;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns the bpc of any Type
|
||||
ILAPI ILubyte ILAPIENTRY ilGetBpcType(ILenum Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case IL_BYTE:
|
||||
case IL_UNSIGNED_BYTE:
|
||||
return 1;
|
||||
case IL_SHORT:
|
||||
case IL_UNSIGNED_SHORT:
|
||||
case IL_HALF:
|
||||
return 2;
|
||||
case IL_INT:
|
||||
case IL_UNSIGNED_INT:
|
||||
case IL_FLOAT:
|
||||
return 4;
|
||||
case IL_DOUBLE:
|
||||
return 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns the type matching a bpc
|
||||
ILAPI ILenum ILAPIENTRY ilGetTypeBpc(ILubyte Bpc)
|
||||
{
|
||||
switch (Bpc)
|
||||
{
|
||||
case 1:
|
||||
return IL_UNSIGNED_BYTE;
|
||||
case 2:
|
||||
return IL_UNSIGNED_SHORT;
|
||||
case 4:
|
||||
return IL_UNSIGNED_INT;
|
||||
case 8:
|
||||
return IL_DOUBLE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns the bpp of any palette type (PalType)
|
||||
ILAPI ILubyte ILAPIENTRY ilGetBppPal(ILenum PalType)
|
||||
{
|
||||
switch (PalType)
|
||||
{
|
||||
case IL_PAL_RGB24:
|
||||
case IL_PAL_BGR24:
|
||||
return 3;
|
||||
case IL_PAL_RGB32:
|
||||
case IL_PAL_RGBA32:
|
||||
case IL_PAL_BGR32:
|
||||
case IL_PAL_BGRA32:
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns the base format of a palette type (PalType)
|
||||
ILAPI ILenum ILAPIENTRY ilGetPalBaseType(ILenum PalType)
|
||||
{
|
||||
switch (PalType)
|
||||
{
|
||||
case IL_PAL_RGB24:
|
||||
return IL_RGB;
|
||||
case IL_PAL_RGB32:
|
||||
return IL_RGBA; // Not sure
|
||||
case IL_PAL_RGBA32:
|
||||
return IL_RGBA;
|
||||
case IL_PAL_BGR24:
|
||||
return IL_BGR;
|
||||
case IL_PAL_BGR32:
|
||||
return IL_BGRA; // Not sure
|
||||
case IL_PAL_BGRA32:
|
||||
return IL_BGRA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns the next power of 2 if Num isn't 2^n or returns Num if Num is 2^n
|
||||
ILAPI ILuint ILAPIENTRY ilNextPower2(ILuint n)
|
||||
{
|
||||
ILuint power = 1;
|
||||
while( power < n ) {
|
||||
power <<= 1;
|
||||
}
|
||||
return power;
|
||||
}
|
||||
|
||||
ILAPI void ILAPIENTRY iMemSwap(ILubyte *s1, ILubyte *s2, const ILuint size)
|
||||
{
|
||||
const ILuint block_size = 4096;
|
||||
const ILuint blocks = size/block_size;
|
||||
ILuint i;
|
||||
|
||||
ILubyte *block = (ILubyte*)ialloc(block_size);
|
||||
if(block == NULL) return;
|
||||
for( i = 0; i < blocks; i++ ) {
|
||||
memcpy(block,s1,block_size);
|
||||
memcpy(s1,s2,block_size);
|
||||
memcpy(s2,block,block_size);
|
||||
s2 += block_size;
|
||||
s1 += block_size;
|
||||
}
|
||||
i = size - i*block_size;
|
||||
if( i > 0 ) {
|
||||
memcpy(block,s1,i);
|
||||
memcpy(s1,s2,i);
|
||||
memcpy(s2,block,i);
|
||||
}
|
||||
ifree(block);
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,545 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_utx.cpp
|
||||
//
|
||||
// Description: Reads from an Unreal and Unreal Tournament Texture (.utx) file.
|
||||
// Specifications can be found at
|
||||
// http://wiki.beyondunreal.com/Legacy:Package_File_Format.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_UTX
|
||||
#include "il_utx.h"
|
||||
|
||||
|
||||
//! Reads a UTX file
|
||||
ILboolean ilLoadUtx(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE UtxFile;
|
||||
ILboolean bUtx = IL_FALSE;
|
||||
|
||||
UtxFile = iopenr(FileName);
|
||||
if (UtxFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bUtx;
|
||||
}
|
||||
|
||||
bUtx = ilLoadUtxF(UtxFile);
|
||||
icloser(UtxFile);
|
||||
|
||||
return bUtx;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened UTX file
|
||||
ILboolean ilLoadUtxF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
try {
|
||||
bRet = iLoadUtxInternal();
|
||||
}
|
||||
catch (bad_alloc &e) {
|
||||
e;
|
||||
ilSetError(IL_OUT_OF_MEMORY);
|
||||
return IL_FALSE;
|
||||
}
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a UTX
|
||||
ILboolean ilLoadUtxL(const void *Lump, ILuint Size)
|
||||
{
|
||||
try {
|
||||
iSetInputLump(Lump, Size);
|
||||
}
|
||||
catch (bad_alloc &e) {
|
||||
e;
|
||||
ilSetError(IL_OUT_OF_MEMORY);
|
||||
return IL_FALSE;
|
||||
}
|
||||
return iLoadUtxInternal();
|
||||
}
|
||||
|
||||
|
||||
ILboolean GetUtxHead(UTXHEADER &Header)
|
||||
{
|
||||
Header.Signature = GetLittleUInt();
|
||||
Header.Version = GetLittleUShort();
|
||||
Header.LicenseMode = GetLittleUShort();
|
||||
Header.Flags = GetLittleUInt();
|
||||
Header.NameCount = GetLittleUInt();
|
||||
Header.NameOffset = GetLittleUInt();
|
||||
Header.ExportCount = GetLittleUInt();
|
||||
Header.ExportOffset = GetLittleUInt();
|
||||
Header.ImportCount = GetLittleUInt();
|
||||
Header.ImportOffset = GetLittleUInt();
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean CheckUtxHead(UTXHEADER &Header)
|
||||
{
|
||||
// This signature signifies a UTX file.
|
||||
if (Header.Signature != 0x9E2A83C1)
|
||||
return IL_FALSE;
|
||||
// Unreal uses 61-63, and Unreal Tournament uses 67-69.
|
||||
if ((Header.Version < 61 || Header.Version > 69))
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Gets a name variable from the file. Keep in mind that the return value must be freed.
|
||||
string GetUtxName(UTXHEADER &Header)
|
||||
{
|
||||
#define NAME_MAX_LEN 256 //@TODO: Figure out if these can possibly be longer.
|
||||
char Name[NAME_MAX_LEN];
|
||||
ILubyte Length = 0;
|
||||
|
||||
// New style (Unreal Tournament) name. This has a byte at the beginning telling
|
||||
// how long the string is (plus terminating 0), followed by the terminating 0.
|
||||
if (Header.Version >= 64) {
|
||||
Length = igetc();
|
||||
if (iread(Name, Length, 1) != 1)
|
||||
return "";
|
||||
if (Name[Length-1] != 0)
|
||||
return "";
|
||||
return string(Name);
|
||||
}
|
||||
|
||||
// Old style (Unreal) name. This string length is unknown, but it is terminated
|
||||
// by a 0.
|
||||
do {
|
||||
Name[Length++] = igetc();
|
||||
} while (!ieof() && Name[Length-1] != 0 && Length < NAME_MAX_LEN);
|
||||
|
||||
// Never reached the terminating 0.
|
||||
if (Length == NAME_MAX_LEN && Name[Length-1] != 0)
|
||||
return "";
|
||||
|
||||
return string(Name);
|
||||
#undef NAME_MAX_LEN
|
||||
}
|
||||
|
||||
|
||||
bool GetUtxNameTable(vector <UTXENTRYNAME> &NameEntries, UTXHEADER &Header)
|
||||
{
|
||||
ILuint NumRead;
|
||||
|
||||
// Go to the name table.
|
||||
iseek(Header.NameOffset, IL_SEEK_SET);
|
||||
|
||||
NameEntries.resize(Header.NameCount);
|
||||
|
||||
// Read in the name table.
|
||||
for (NumRead = 0; NumRead < Header.NameCount; NumRead++) {
|
||||
NameEntries[NumRead].Name = GetUtxName(Header);
|
||||
if (NameEntries[NumRead].Name == "")
|
||||
break;
|
||||
NameEntries[NumRead].Flags = GetLittleUInt();
|
||||
}
|
||||
|
||||
// Did not read all of the entries (most likely GetUtxName failed).
|
||||
if (NumRead < Header.NameCount) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// This following code is from http://wiki.beyondunreal.com/Legacy:Package_File_Format/Data_Details.
|
||||
/// <summary>Reads a compact integer from the FileReader.
|
||||
/// Bytes read differs, so do not make assumptions about
|
||||
/// physical data being read from the stream. (If you have
|
||||
/// to, get the difference of FileReader.BaseStream.Position
|
||||
/// before and after this is executed.)</summary>
|
||||
/// <returns>An "uncompacted" signed integer.</returns>
|
||||
/// <remarks>FileReader is a System.IO.BinaryReader mapped
|
||||
/// to a file. Also, there may be better ways to implement
|
||||
/// this, but this is fast, and it works.</remarks>
|
||||
ILint UtxReadCompactInteger()
|
||||
{
|
||||
int output = 0;
|
||||
ILboolean sign = IL_FALSE;
|
||||
int i;
|
||||
ILubyte x;
|
||||
for(i = 0; i < 5; i++)
|
||||
{
|
||||
x = igetc();
|
||||
// First byte
|
||||
if(i == 0)
|
||||
{
|
||||
// Bit: X0000000
|
||||
if((x & 0x80) > 0)
|
||||
sign = IL_TRUE;
|
||||
// Bits: 00XXXXXX
|
||||
output |= (x & 0x3F);
|
||||
// Bit: 0X000000
|
||||
if((x & 0x40) == 0)
|
||||
break;
|
||||
}
|
||||
// Last byte
|
||||
else if(i == 4)
|
||||
{
|
||||
// Bits: 000XXXXX -- the 0 bits are ignored
|
||||
// (hits the 32 bit boundary)
|
||||
output |= (x & 0x1F) << (6 + (3 * 7));
|
||||
}
|
||||
// Middle bytes
|
||||
else
|
||||
{
|
||||
// Bits: 0XXXXXXX
|
||||
output |= (x & 0x7F) << (6 + ((i - 1) * 7));
|
||||
// Bit: X0000000
|
||||
if((x & 0x80) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// multiply by negative one here, since the first 6+ bits could be 0
|
||||
if (sign)
|
||||
output *= -1;
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
void ChangeObjectReference(ILint *ObjRef, ILboolean *IsImported)
|
||||
{
|
||||
if (*ObjRef < 0) {
|
||||
*IsImported = IL_TRUE;
|
||||
*ObjRef = -*ObjRef - 1;
|
||||
}
|
||||
else if (*ObjRef > 0) {
|
||||
*IsImported = IL_FALSE;
|
||||
*ObjRef = *ObjRef - 1; // This is an object reference, so we have to do this conversion.
|
||||
}
|
||||
else {
|
||||
*ObjRef = -1; // "NULL" pointer
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool GetUtxExportTable(vector <UTXEXPORTTABLE> &ExportTable, UTXHEADER &Header)
|
||||
{
|
||||
ILuint i;
|
||||
|
||||
// Go to the name table.
|
||||
iseek(Header.ExportOffset, IL_SEEK_SET);
|
||||
|
||||
// Create ExportCount elements in our array.
|
||||
ExportTable.resize(Header.ExportCount);
|
||||
|
||||
for (i = 0; i < Header.ExportCount; i++) {
|
||||
ExportTable[i].Class = UtxReadCompactInteger();
|
||||
ExportTable[i].Super = UtxReadCompactInteger();
|
||||
ExportTable[i].Group = GetLittleUInt();
|
||||
ExportTable[i].ObjectName = UtxReadCompactInteger();
|
||||
ExportTable[i].ObjectFlags = GetLittleUInt();
|
||||
ExportTable[i].SerialSize = UtxReadCompactInteger();
|
||||
ExportTable[i].SerialOffset = UtxReadCompactInteger();
|
||||
|
||||
ChangeObjectReference(&ExportTable[i].Class, &ExportTable[i].ClassImported);
|
||||
ChangeObjectReference(&ExportTable[i].Super, &ExportTable[i].SuperImported);
|
||||
ChangeObjectReference(&ExportTable[i].Group, &ExportTable[i].GroupImported);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GetUtxImportTable(vector <UTXIMPORTTABLE> &ImportTable, UTXHEADER &Header)
|
||||
{
|
||||
ILuint i;
|
||||
|
||||
// Go to the name table.
|
||||
iseek(Header.ImportOffset, IL_SEEK_SET);
|
||||
|
||||
// Allocate the name table.
|
||||
ImportTable.resize(Header.ImportCount);
|
||||
|
||||
for (i = 0; i < Header.ImportCount; i++) {
|
||||
ImportTable[i].ClassPackage = UtxReadCompactInteger();
|
||||
ImportTable[i].ClassName = UtxReadCompactInteger();
|
||||
ImportTable[i].Package = GetLittleUInt();
|
||||
ImportTable[i].ObjectName = UtxReadCompactInteger();
|
||||
|
||||
ChangeObjectReference(&ImportTable[i].Package, &ImportTable[i].PackageImported);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*void UtxDestroyPalettes(UTXPALETTE *Palettes, ILuint NumPal)
|
||||
{
|
||||
ILuint i;
|
||||
for (i = 0; i < NumPal; i++) {
|
||||
//ifree(Palettes[i].Name);
|
||||
ifree(Palettes[i].Pal);
|
||||
}
|
||||
ifree(Palettes);
|
||||
}*/
|
||||
|
||||
|
||||
ILenum UtxFormatToDevIL(ILuint Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case UTX_P8:
|
||||
return IL_COLOR_INDEX;
|
||||
case UTX_DXT1:
|
||||
return IL_RGBA;
|
||||
}
|
||||
return IL_BGRA; // Should never reach here.
|
||||
}
|
||||
|
||||
|
||||
ILuint UtxFormatToBpp(ILuint Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case UTX_P8:
|
||||
return 1;
|
||||
case UTX_DXT1:
|
||||
return 4;
|
||||
}
|
||||
return 4; // Should never reach here.
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the UTX.
|
||||
ILboolean iLoadUtxInternal(void)
|
||||
{
|
||||
UTXHEADER Header;
|
||||
vector <UTXENTRYNAME> NameEntries;
|
||||
vector <UTXEXPORTTABLE> ExportTable;
|
||||
vector <UTXIMPORTTABLE> ImportTable;
|
||||
vector <UTXPALETTE> Palettes;
|
||||
ILimage *Image;
|
||||
ILuint NumPal = 0, i, j = 0;
|
||||
ILint Name;
|
||||
ILubyte Type;
|
||||
ILint Val;
|
||||
ILint Size;
|
||||
ILint Width, Height, PalEntry;
|
||||
ILboolean BaseCreated = IL_FALSE, HasPal;
|
||||
ILint Format;
|
||||
ILubyte *CompData = NULL;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!GetUtxHead(Header))
|
||||
return IL_FALSE;
|
||||
if (!CheckUtxHead(Header))
|
||||
return IL_FALSE;
|
||||
|
||||
// We grab the name table.
|
||||
if (!GetUtxNameTable(NameEntries, Header))
|
||||
return IL_FALSE;
|
||||
// Then we get the export table.
|
||||
if (!GetUtxExportTable(ExportTable, Header))
|
||||
return IL_FALSE;
|
||||
// Then the last table is the import table.
|
||||
if (!GetUtxImportTable(ImportTable, Header))
|
||||
return IL_FALSE;
|
||||
|
||||
// Find the number of palettes in the export table.
|
||||
for (i = 0; i < Header.ExportCount; i++) {
|
||||
if (NameEntries[ImportTable[ExportTable[i].Class].ObjectName].Name == "Palette")
|
||||
NumPal++;
|
||||
}
|
||||
Palettes.resize(NumPal);
|
||||
|
||||
// Read in all of the palettes.
|
||||
NumPal = 0;
|
||||
for (i = 0; i < Header.ExportCount; i++) {
|
||||
if (NameEntries[ImportTable[ExportTable[i].Class].ObjectName].Name == "Palette") {
|
||||
Palettes[NumPal].Name = i;
|
||||
iseek(ExportTable[NumPal].SerialOffset, IL_SEEK_SET);
|
||||
Name = igetc(); // Skip the 2. @TODO: Can there be more in front of the palettes?
|
||||
Palettes[NumPal].Count = UtxReadCompactInteger();
|
||||
Palettes[NumPal].Pal = new ILubyte[Palettes[NumPal].Count * 4];
|
||||
if (iread(Palettes[NumPal].Pal, Palettes[NumPal].Count * 4, 1) != 1)
|
||||
return IL_FALSE;
|
||||
NumPal++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < Header.ExportCount; i++) {
|
||||
// Find textures in the file.
|
||||
if (NameEntries[ImportTable[ExportTable[i].Class].ObjectName].Name == "Texture") {
|
||||
iseek(ExportTable[i].SerialOffset, IL_SEEK_SET);
|
||||
Width = -1; Height = -1; PalEntry = NumPal; HasPal = IL_FALSE; Format = -1;
|
||||
|
||||
do {
|
||||
// Always starts with a comptact integer that gives us an entry into the name table.
|
||||
Name = UtxReadCompactInteger();
|
||||
if (NameEntries[Name].Name == "None")
|
||||
break;
|
||||
Type = igetc();
|
||||
Size = (Type & 0x70) >> 4;
|
||||
|
||||
if (Type == 0xA2)
|
||||
igetc(); // Byte is 1 here...
|
||||
|
||||
switch (Type & 0x0F)
|
||||
{
|
||||
case 1: // Get a single byte.
|
||||
Val = igetc();
|
||||
break;
|
||||
|
||||
case 2: // Get unsigned integer.
|
||||
Val = GetLittleUInt();
|
||||
break;
|
||||
|
||||
case 3: // Boolean value is in the info byte.
|
||||
igetc();
|
||||
break;
|
||||
|
||||
case 4: // Skip flaots for right now.
|
||||
GetLittleFloat();
|
||||
break;
|
||||
|
||||
case 5:
|
||||
case 6: // Get a compact integer - an object reference.
|
||||
Val = UtxReadCompactInteger();
|
||||
Val--;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
Val = igetc();
|
||||
switch (Size)
|
||||
{
|
||||
case 0:
|
||||
iseek(1, IL_SEEK_CUR);
|
||||
break;
|
||||
case 1:
|
||||
iseek(2, IL_SEEK_CUR);
|
||||
break;
|
||||
case 2:
|
||||
iseek(4, IL_SEEK_CUR);
|
||||
break;
|
||||
case 3:
|
||||
iseek(12, IL_SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: // Uhm...
|
||||
break;
|
||||
}
|
||||
|
||||
//@TODO: What should we do if Name >= Header.NameCount?
|
||||
if ((ILuint)Name < Header.NameCount) { // Don't want to go past the end of our array.
|
||||
if (NameEntries[Name].Name == "Palette") {
|
||||
// If it has references to more than one palette, just use the first one.
|
||||
if (HasPal == IL_FALSE) {
|
||||
// We go through the palette list here to match names.
|
||||
for (PalEntry = 0; (ILuint)PalEntry < NumPal; PalEntry++) {
|
||||
if (Val == Palettes[PalEntry].Name) {
|
||||
HasPal = IL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NameEntries[Name].Name == "Format") // Not required for P8 images but can be present.
|
||||
if (Format == -1)
|
||||
Format = Val;
|
||||
if (NameEntries[Name].Name == "USize") // Width of the image
|
||||
if (Width == -1)
|
||||
Width = Val;
|
||||
if (NameEntries[Name].Name == "VSize") // Height of the image
|
||||
if (Height == -1)
|
||||
Height = Val;
|
||||
}
|
||||
} while (!ieof());
|
||||
|
||||
// If the format property is not present, it is a paletted (P8) image.
|
||||
if (Format == -1)
|
||||
Format = UTX_P8;
|
||||
// Just checks for everything being proper. If the format is P8, we check to make sure that a palette was found.
|
||||
if (Width == -1 || Height == -1 || (PalEntry == NumPal && Format != UTX_DXT1) || (Format != UTX_P8 && Format != UTX_DXT1))
|
||||
return IL_FALSE;
|
||||
if (BaseCreated == IL_FALSE) {
|
||||
BaseCreated = IL_TRUE;
|
||||
ilTexImage(Width, Height, 1, UtxFormatToBpp(Format), UtxFormatToDevIL(Format), IL_UNSIGNED_BYTE, NULL);
|
||||
Image = iCurImage;
|
||||
}
|
||||
else {
|
||||
Image->Next = ilNewImageFull(Width, Height, 1, UtxFormatToBpp(Format), UtxFormatToDevIL(Format), IL_UNSIGNED_BYTE, NULL);
|
||||
if (Image->Next == NULL)
|
||||
return IL_FALSE;
|
||||
Image = Image->Next;
|
||||
}
|
||||
|
||||
// Skip the mipmap count, width offset and mipmap size entries.
|
||||
//@TODO: Implement mipmaps.
|
||||
iseek(5, IL_SEEK_CUR);
|
||||
UtxReadCompactInteger();
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case UTX_P8:
|
||||
Image->Pal.PalSize = Palettes[PalEntry].Count * 4;
|
||||
Image->Pal.Palette = (ILubyte*)ialloc(Image->Pal.PalSize);
|
||||
if (Image->Pal.Palette == NULL)
|
||||
return IL_FALSE;
|
||||
memcpy(Image->Pal.Palette, Palettes[PalEntry].Pal, Image->Pal.PalSize);
|
||||
Image->Pal.PalType = IL_PAL_RGBA32;
|
||||
|
||||
if (iread(Image->Data, Image->SizeOfData, 1) != 1)
|
||||
return IL_FALSE;
|
||||
break;
|
||||
|
||||
case UTX_DXT1:
|
||||
Image->DxtcSize = IL_MAX(Image->Width * Image->Height / 2, 8);
|
||||
CompData = (ILubyte*)ialloc(Image->DxtcSize);
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
if (iread(CompData, Image->DxtcSize, 1) != 1) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
// Keep a copy of the DXTC data if the user wants it.
|
||||
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
|
||||
Image->DxtcData = CompData;
|
||||
Image->DxtcFormat = IL_DXT1;
|
||||
CompData = NULL;
|
||||
}
|
||||
if (DecompressDXT1(Image, CompData) == IL_FALSE) {
|
||||
ifree(CompData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
ifree(CompData);
|
||||
break;
|
||||
}
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
}
|
||||
}
|
||||
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
#endif//IL_NO_UTX
|
||||
|
||||
@@ -0,0 +1,953 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_vtf.c
|
||||
//
|
||||
// Description: Reads from and writes to a Valve Texture Format (.vtf) file.
|
||||
// These are used in Valve's Source games. VTF specs available
|
||||
// from http://developer.valvesoftware.com/wiki/VTF.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_VTF
|
||||
#include "il_vtf.h"
|
||||
#include "il_dds.h"
|
||||
|
||||
|
||||
//@TODO: Get rid of these globals.
|
||||
//static VTFHEAD Head;
|
||||
|
||||
|
||||
//! Checks if the file specified in FileName is a valid VTF file.
|
||||
ILboolean ilIsValidVtf(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE VtfFile;
|
||||
ILboolean bVtf = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("vtf"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bVtf;
|
||||
}
|
||||
|
||||
VtfFile = iopenr(FileName);
|
||||
if (VtfFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bVtf;
|
||||
}
|
||||
|
||||
bVtf = ilIsValidVtfF(VtfFile);
|
||||
icloser(VtfFile);
|
||||
|
||||
return bVtf;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid VTF file at the current position.
|
||||
ILboolean ilIsValidVtfF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidVtf();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid VTF lump.
|
||||
ILboolean ilIsValidVtfL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidVtf();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to get the VTF header from the current file.
|
||||
ILboolean iGetVtfHead(VTFHEAD *Header)
|
||||
{
|
||||
iread(Header->Signature, 1, 4);
|
||||
Header->Version[0] = GetLittleUInt();
|
||||
Header->Version[1] = GetLittleUInt();
|
||||
Header->HeaderSize = GetLittleUInt();
|
||||
Header->Width = GetLittleUShort();
|
||||
Header->Height = GetLittleUShort();
|
||||
Header->Flags = GetLittleUInt();
|
||||
Header->Frames = GetLittleUShort();
|
||||
Header->FirstFrame = GetLittleUShort();
|
||||
iseek(4, IL_SEEK_CUR); // Padding
|
||||
Header->Reflectivity[0] = GetLittleFloat();
|
||||
Header->Reflectivity[1] = GetLittleFloat();
|
||||
Header->Reflectivity[2] = GetLittleFloat();
|
||||
iseek(4, IL_SEEK_CUR); // Padding
|
||||
Header->BumpmapScale = GetLittleFloat();
|
||||
Header->HighResImageFormat = GetLittleUInt();
|
||||
Header->MipmapCount = (ILubyte)igetc();
|
||||
Header->LowResImageFormat = GetLittleInt();
|
||||
Header->LowResImageWidth = (ILubyte)igetc();
|
||||
Header->LowResImageHeight = (ILubyte)igetc();
|
||||
//@TODO: This is a hack for the moment.
|
||||
if (Header->HeaderSize == 64) {
|
||||
Header->Depth = igetc();
|
||||
if (Header->Depth == 0)
|
||||
Header->Depth = 1;
|
||||
}
|
||||
else {
|
||||
Header->Depth = GetLittleUShort();
|
||||
iseek(Header->HeaderSize - sizeof(VTFHEAD), IL_SEEK_CUR);
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidVtf(void)
|
||||
{
|
||||
VTFHEAD Header;
|
||||
|
||||
if (!iGetVtfHead(&Header))
|
||||
return IL_FALSE;
|
||||
iseek(-(ILint)sizeof(VTFHEAD), IL_SEEK_CUR);
|
||||
|
||||
return iCheckVtf(&Header);
|
||||
}
|
||||
|
||||
|
||||
//@TODO: Add more checks.
|
||||
// Should we check for Frames, MipmapCount and Depth != 0?
|
||||
|
||||
// Internal function used to check if the HEADER is a valid VTF header.
|
||||
ILboolean iCheckVtf(VTFHEAD *Header)
|
||||
{
|
||||
// The file signature is "VTF\0".
|
||||
if ((Header->Signature[0] != 'V') || (Header->Signature[1] != 'T') || (Header->Signature[2] != 'F')
|
||||
|| (Header->Signature[3] != 0))
|
||||
return IL_FALSE;
|
||||
// Are there other versions available yet?
|
||||
if (Header->Version[0] != 7)
|
||||
return IL_FALSE;
|
||||
// We have 7.0 through 7.4 as of 12/27/2008.
|
||||
if (Header->Version[1] > 4)
|
||||
return IL_FALSE;
|
||||
// May change in future version of the specifications.
|
||||
// 80 is through version 7.2, and 96/104 are through 7.4.
|
||||
// This must be 16-byte aligned, but something is outputting headers with 104.
|
||||
if ((Header->HeaderSize != 80) && (Header->HeaderSize != 96) && (Header->HeaderSize != 104)
|
||||
&& (Header->HeaderSize != 64))
|
||||
return IL_FALSE;
|
||||
|
||||
// 0 is an invalid dimension
|
||||
if (Header->Width == 0 || Header->Height == 0)
|
||||
return IL_FALSE;
|
||||
// Width and Height must be powers of 2.
|
||||
if ((ilNextPower2(Header->Width) != Header->Width) || (ilNextPower2(Header->Height) != Header->Height))
|
||||
return IL_FALSE;
|
||||
// It looks like width and height of zero are valid - i.e. no low res image.
|
||||
if (Header->LowResImageWidth != 0 && Header->LowResImageHeight != 0) {
|
||||
if ((ilNextPower2(Header->LowResImageWidth) != Header->LowResImageWidth)
|
||||
|| (ilNextPower2(Header->LowResImageHeight) != Header->LowResImageHeight))
|
||||
return IL_FALSE;
|
||||
}
|
||||
// In addition, the LowResImage has to have dimensions no greater than 16.
|
||||
if ((Header->LowResImageWidth > 16) || (Header->LowResImageHeight > 16))
|
||||
//|| (Header->LowResImageWidth == 0) || (Header->LowResImageHeight == 0))
|
||||
// It looks like width and height of zero are valid.
|
||||
return IL_FALSE;
|
||||
// And the LowResImage has to have dimensions less than or equal to the main image.
|
||||
if ((Header->LowResImageWidth > Header->Width) || (Header->LowResImageHeight > Header->Height))
|
||||
return IL_FALSE;
|
||||
// The LowResImage must be in DXT1 format, or if it does not exist, it is denoted by all bits set.
|
||||
if (Header->LowResImageFormat != IMAGE_FORMAT_DXT1 && Header->LowResImageFormat != 0xFFFFFFFF)
|
||||
return IL_FALSE;
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Reads a VTF file
|
||||
ILboolean ilLoadVtf(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE VtfFile;
|
||||
ILboolean bVtf = IL_FALSE;
|
||||
|
||||
VtfFile = iopenr(FileName);
|
||||
if (VtfFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bVtf;
|
||||
}
|
||||
|
||||
bVtf = ilLoadVtfF(VtfFile);
|
||||
icloser(VtfFile);
|
||||
|
||||
return bVtf;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened VTF file
|
||||
ILboolean ilLoadVtfF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadVtfInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a VTF
|
||||
ILboolean ilLoadVtfL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadVtfInternal();
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to load the VTF.
|
||||
ILboolean iLoadVtfInternal(void)
|
||||
{
|
||||
ILboolean bVtf = IL_TRUE;
|
||||
ILimage *Image, *BaseImage;
|
||||
ILenum Format, Type;
|
||||
ILint Frame, Face, Mipmap;
|
||||
ILuint SizeOfData, Channels, k;
|
||||
ILubyte *CompData = NULL, SwapVal, *Data16Bit, *Temp, NumFaces;
|
||||
VTFHEAD Head;
|
||||
ILuint CurName;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
CurName = ilGetCurName();
|
||||
|
||||
if (!iGetVtfHead(&Head))
|
||||
return IL_FALSE;
|
||||
if (!iCheckVtf(&Head)) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (Head.Flags & TEXTUREFLAGS_ENVMAP) {
|
||||
// If we have a spherical map in addition to the 6 sides of the cubemap, FirstFrame's bits
|
||||
// are all set. The only place I found out about this was VTFLib.
|
||||
NumFaces = Head.FirstFrame == 0xFFFF ? 6 : 7;
|
||||
}
|
||||
else
|
||||
NumFaces = 1; // This is not an environmental map.
|
||||
|
||||
// Skip the low resolution image. This is just a thumbnail.
|
||||
// The block size is 8, and the compression ratio is 6:1.
|
||||
SizeOfData = IL_MAX(Head.LowResImageWidth * Head.LowResImageHeight / 2, 8);
|
||||
if (Head.LowResImageWidth == 0 && Head.LowResImageHeight == 0)
|
||||
SizeOfData = 0; // No low resolution image present.
|
||||
iseek(SizeOfData, IL_SEEK_CUR);
|
||||
|
||||
//@TODO: Make this a helper function that set channels, bpc and format.
|
||||
switch (Head.HighResImageFormat)
|
||||
{
|
||||
case IMAGE_FORMAT_DXT1: //@TODO: Should we make DXT1 channels = 3?
|
||||
case IMAGE_FORMAT_DXT1_ONEBITALPHA:
|
||||
case IMAGE_FORMAT_DXT3:
|
||||
case IMAGE_FORMAT_DXT5:
|
||||
Channels = 4;
|
||||
Format = IL_RGBA;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_BGR888:
|
||||
case IMAGE_FORMAT_BGR888_BLUESCREEN:
|
||||
Channels = 3;
|
||||
Format = IL_BGR;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_BGRA8888:
|
||||
Channels = 4;
|
||||
Format = IL_BGRA;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_BGRX8888:
|
||||
Channels = 3;
|
||||
Format = IL_BGR;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_RGB888:
|
||||
case IMAGE_FORMAT_RGB888_BLUESCREEN:
|
||||
Channels = 3;
|
||||
Format = IL_RGB;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_RGBA8888:
|
||||
Channels = 4;
|
||||
Format = IL_RGBA;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_RGBA16161616: // 16-bit shorts
|
||||
Channels = 4;
|
||||
Format = IL_RGBA;
|
||||
Type = IL_UNSIGNED_SHORT;
|
||||
break;
|
||||
case IMAGE_FORMAT_RGBA16161616F: // 16-bit floats
|
||||
Channels = 4;
|
||||
Format = IL_RGBA;
|
||||
Type = IL_FLOAT;
|
||||
break;
|
||||
case IMAGE_FORMAT_I8: // 8-bit luminance data
|
||||
Channels = 1;
|
||||
Format = IL_LUMINANCE;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_IA88: // 8-bit luminance and alpha data
|
||||
Channels = 2;
|
||||
Format = IL_LUMINANCE_ALPHA;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_A8: // 8-bit alpha data
|
||||
Channels = 1;
|
||||
Format = IL_ALPHA;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_ARGB8888:
|
||||
Channels = 4;
|
||||
Format = IL_BGRA;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_ABGR8888:
|
||||
Channels = 4;
|
||||
Format = IL_RGBA;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_RGB565:
|
||||
Channels = 3;
|
||||
Format = IL_RGB;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_BGR565:
|
||||
Channels = 3;
|
||||
Format = IL_BGR;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_BGRA5551:
|
||||
Channels = 4;
|
||||
Format = IL_BGRA;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_BGRX5551: // Unused alpha channel
|
||||
Channels = 3;
|
||||
Format = IL_BGR;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case IMAGE_FORMAT_BGRA4444:
|
||||
Channels = 4;
|
||||
Format = IL_BGRA;
|
||||
Type = IL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
default:
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!ilTexImage(Head.Width, Head.Height, Head.Depth, Channels, Format, Type, NULL))
|
||||
return IL_FALSE;
|
||||
// The origin should be in the upper left.
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
// Create any mipmaps.
|
||||
VtfInitFacesMipmaps(iCurImage, NumFaces, &Head);
|
||||
|
||||
// Create our animation chain
|
||||
BaseImage = Image = iCurImage; // Top-level image
|
||||
for (Frame = 1; Frame < Head.Frames; Frame++) {
|
||||
Image->Next = ilNewImageFull(Head.Width, Head.Height, Head.Depth, Channels, Format, Type, NULL);
|
||||
if (Image->Next == NULL)
|
||||
return IL_FALSE;
|
||||
Image = Image->Next;
|
||||
// The origin should be in the upper left.
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
// Create our faces and mipmaps for each frame.
|
||||
VtfInitFacesMipmaps(Image, NumFaces, &Head);
|
||||
}
|
||||
|
||||
// We want to put the smallest mipmap at the end, but it is first in the file, so we count backwards.
|
||||
for (Mipmap = Head.MipmapCount - 1; Mipmap >= 0; Mipmap--) {
|
||||
// Frames are in the normal order.
|
||||
for (Frame = 0; Frame < Head.Frames; Frame++) {
|
||||
// @TODO: Cubemap faces are always in the same order?
|
||||
for (Face = 0; Face < NumFaces; Face++) {
|
||||
//@TODO: Would probably be quicker to do the linked list traversal manually here.
|
||||
ilBindImage(CurName);
|
||||
ilActiveImage(Frame);
|
||||
ilActiveFace(Face);
|
||||
ilActiveMipmap(Mipmap);
|
||||
Image = iCurImage;
|
||||
|
||||
switch (Head.HighResImageFormat)
|
||||
{
|
||||
// DXT1 compression
|
||||
case IMAGE_FORMAT_DXT1:
|
||||
case IMAGE_FORMAT_DXT1_ONEBITALPHA:
|
||||
// The block size is 8.
|
||||
SizeOfData = IL_MAX(Image->Width * Image->Height * Image->Depth / 2, 8);
|
||||
CompData = ialloc(SizeOfData); // Gives a 6:1 compression ratio (or 8:1 for DXT1 with alpha)
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
iread(CompData, 1, SizeOfData);
|
||||
// Keep a copy of the DXTC data if the user wants it.
|
||||
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
|
||||
Image->DxtcSize = SizeOfData;
|
||||
Image->DxtcData = CompData;
|
||||
Image->DxtcFormat = IL_DXT5;
|
||||
CompData = NULL;
|
||||
}
|
||||
bVtf = DecompressDXT1(Image, CompData);
|
||||
break;
|
||||
|
||||
// DXT3 compression
|
||||
case IMAGE_FORMAT_DXT3:
|
||||
// The block size is 16.
|
||||
SizeOfData = IL_MAX(Image->Width * Image->Height * Image->Depth, 16);
|
||||
CompData = ialloc(SizeOfData); // Gives a 4:1 compression ratio
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
iread(CompData, 1, SizeOfData);
|
||||
// Keep a copy of the DXTC data if the user wants it.
|
||||
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
|
||||
Image->DxtcSize = SizeOfData;
|
||||
Image->DxtcData = CompData;
|
||||
Image->DxtcFormat = IL_DXT3;
|
||||
CompData = NULL;
|
||||
}
|
||||
bVtf = DecompressDXT3(Image, CompData);
|
||||
break;
|
||||
|
||||
// DXT5 compression
|
||||
case IMAGE_FORMAT_DXT5:
|
||||
// The block size is 16.
|
||||
SizeOfData = IL_MAX(Image->Width * Image->Height * Image->Depth, 16);
|
||||
CompData = ialloc(SizeOfData); // Gives a 4:1 compression ratio
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
iread(CompData, 1, SizeOfData);
|
||||
// Keep a copy of the DXTC data if the user wants it.
|
||||
if (ilGetInteger(IL_KEEP_DXTC_DATA) == IL_TRUE) {
|
||||
Image->DxtcSize = SizeOfData;
|
||||
Image->DxtcData = CompData;
|
||||
Image->DxtcFormat = IL_DXT5;
|
||||
CompData = NULL;
|
||||
}
|
||||
bVtf = DecompressDXT5(Image, CompData);
|
||||
break;
|
||||
|
||||
// Uncompressed BGR(A) data (24-bit and 32-bit)
|
||||
case IMAGE_FORMAT_BGR888:
|
||||
case IMAGE_FORMAT_BGRA8888:
|
||||
// Uncompressed RGB(A) data (24-bit and 32-bit)
|
||||
case IMAGE_FORMAT_RGB888:
|
||||
case IMAGE_FORMAT_RGBA8888:
|
||||
// Uncompressed 16-bit shorts
|
||||
case IMAGE_FORMAT_RGBA16161616:
|
||||
// Luminance data only
|
||||
case IMAGE_FORMAT_I8:
|
||||
// Luminance and alpha data
|
||||
case IMAGE_FORMAT_IA88:
|
||||
// Alpha data only
|
||||
case IMAGE_FORMAT_A8:
|
||||
// We will ignore the part about the bluescreen right now.
|
||||
// I could not find any information about it.
|
||||
case IMAGE_FORMAT_RGB888_BLUESCREEN:
|
||||
case IMAGE_FORMAT_BGR888_BLUESCREEN:
|
||||
// Just copy the data over - no compression.
|
||||
if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData)
|
||||
bVtf = IL_FALSE;
|
||||
else
|
||||
bVtf = IL_TRUE;
|
||||
break;
|
||||
|
||||
// Uncompressed 24-bit data with an unused alpha channel (we discard it)
|
||||
case IMAGE_FORMAT_BGRX8888:
|
||||
SizeOfData = Image->Width * Image->Height * Image->Depth * 3;
|
||||
Temp = CompData = ialloc(SizeOfData / 3 * 4); // Not compressed data
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
if (iread(CompData, 1, SizeOfData / 3 * 4) != SizeOfData / 3 * 4) {
|
||||
bVtf = IL_FALSE;
|
||||
break;
|
||||
}
|
||||
for (k = 0; k < SizeOfData; k += 3) {
|
||||
Image->Data[k] = Temp[0];
|
||||
Image->Data[k+1] = Temp[1];
|
||||
Image->Data[k+2] = Temp[2];
|
||||
Temp += 4;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Uncompressed 16-bit floats (must be converted to 32-bit)
|
||||
case IMAGE_FORMAT_RGBA16161616F:
|
||||
SizeOfData = Image->Width * Image->Height * Image->Depth * Image->Bpp * 2;
|
||||
CompData = ialloc(SizeOfData); // Not compressed data
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
|
||||
bVtf = IL_FALSE;
|
||||
break;
|
||||
}
|
||||
bVtf = iConvFloat16ToFloat32((ILuint*)Image->Data, (ILushort*)CompData, SizeOfData / 2);
|
||||
break;
|
||||
|
||||
// Uncompressed 32-bit ARGB and ABGR data. DevIL does not handle this
|
||||
// internally, so we have to swap values.
|
||||
case IMAGE_FORMAT_ARGB8888:
|
||||
case IMAGE_FORMAT_ABGR8888:
|
||||
if (iread(Image->Data, 1, Image->SizeOfData) != Image->SizeOfData) {
|
||||
bVtf = IL_FALSE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
bVtf = IL_TRUE;
|
||||
}
|
||||
// Swap the data
|
||||
for (k = 0; k < Image->SizeOfData; k += 4) {
|
||||
SwapVal = Image->Data[k];
|
||||
Image->Data[k] = Image->Data[k+3];
|
||||
Image->Data[k+3] = SwapVal;
|
||||
SwapVal = Image->Data[k+1];
|
||||
Image->Data[k+1] = Image->Data[k+2];
|
||||
Image->Data[k+2] = SwapVal;
|
||||
}
|
||||
break;
|
||||
|
||||
// Uncompressed 16-bit RGB and BGR data. We have to expand this to 24-bit, since
|
||||
// DevIL does not handle this internally.
|
||||
// The data is in the file as: gggbbbbb rrrrrrggg
|
||||
case IMAGE_FORMAT_RGB565:
|
||||
case IMAGE_FORMAT_BGR565:
|
||||
SizeOfData = Image->Width * Image->Height * Image->Depth * 2;
|
||||
Data16Bit = CompData = ialloc(SizeOfData); // Not compressed data
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
|
||||
bVtf = IL_FALSE;
|
||||
break;
|
||||
}
|
||||
for (k = 0; k < Image->SizeOfData; k += 3) {
|
||||
Image->Data[k] = (Data16Bit[0] & 0x1F) << 3;
|
||||
Image->Data[k+1] = ((Data16Bit[1] & 0x07) << 5) | ((Data16Bit[0] & 0xE0) >> 3);
|
||||
Image->Data[k+2] = Data16Bit[1] & 0xF8;
|
||||
Data16Bit += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
// Uncompressed 16-bit BGRA data (1-bit alpha). We have to expand this to 32-bit,
|
||||
// since DevIL does not handle this internally.
|
||||
// Something seems strange with this one, but this is how VTFEdit outputs.
|
||||
// The data is in the file as: gggbbbbb arrrrrgg
|
||||
case IMAGE_FORMAT_BGRA5551:
|
||||
SizeOfData = Image->Width * Image->Height * Image->Depth * 2;
|
||||
Data16Bit = CompData = ialloc(SizeOfData); // Not compressed data
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
|
||||
bVtf = IL_FALSE;
|
||||
break;
|
||||
}
|
||||
for (k = 0; k < Image->SizeOfData; k += 4) {
|
||||
Image->Data[k] = (Data16Bit[0] & 0x1F) << 3;
|
||||
Image->Data[k+1] = ((Data16Bit[0] & 0xE0) >> 2) | ((Data16Bit[1] & 0x03) << 6);
|
||||
Image->Data[k+2] = (Data16Bit[1] & 0x7C) << 1;
|
||||
// 1-bit alpha is either off or on.
|
||||
Image->Data[k+3] = ((Data16Bit[0] & 0x80) == 0x80) ? 0xFF : 0x00;
|
||||
Data16Bit += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
// Same as above, but the alpha channel is unused.
|
||||
case IMAGE_FORMAT_BGRX5551:
|
||||
SizeOfData = Image->Width * Image->Height * Image->Depth * 2;
|
||||
Data16Bit = CompData = ialloc(SizeOfData); // Not compressed data
|
||||
if (iread(CompData, 1, SizeOfData) != SizeOfData) {
|
||||
bVtf = IL_FALSE;
|
||||
break;
|
||||
}
|
||||
for (k = 0; k < Image->SizeOfData; k += 3) {
|
||||
Image->Data[k] = (Data16Bit[0] & 0x1F) << 3;
|
||||
Image->Data[k+1] = ((Data16Bit[0] & 0xE0) >> 2) | ((Data16Bit[1] & 0x03) << 6);
|
||||
Image->Data[k+2] = (Data16Bit[1] & 0x7C) << 1;
|
||||
Data16Bit += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
// Data is reduced to a 4-bits per channel format.
|
||||
case IMAGE_FORMAT_BGRA4444:
|
||||
SizeOfData = Image->Width * Image->Height * Image->Depth * 4;
|
||||
Temp = CompData = ialloc(SizeOfData / 2); // Not compressed data
|
||||
if (CompData == NULL)
|
||||
return IL_FALSE;
|
||||
if (iread(CompData, 1, SizeOfData / 2) != SizeOfData / 2) {
|
||||
bVtf = IL_FALSE;
|
||||
break;
|
||||
}
|
||||
for (k = 0; k < SizeOfData; k += 4) {
|
||||
// We double the data here.
|
||||
Image->Data[k] = (Temp[0] & 0x0F) << 4 | (Temp[0] & 0x0F);
|
||||
Image->Data[k+1] = (Temp[0] & 0xF0) >> 4 | (Temp[0] & 0xF0);
|
||||
Image->Data[k+2] = (Temp[1] & 0x0F) << 4 | (Temp[1] & 0x0F);
|
||||
Image->Data[k+3] = (Temp[1] & 0xF0) >> 4 | (Temp[1] & 0xF0);
|
||||
Temp += 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ifree(CompData);
|
||||
CompData = NULL;
|
||||
if (bVtf == IL_FALSE) //@TODO: Do we need to do any cleanup here?
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ilBindImage(CurName); // Set to parent image first.
|
||||
return ilFixImage();
|
||||
}
|
||||
|
||||
|
||||
ILuint GetFaceFlag(ILuint FaceNum)
|
||||
{
|
||||
switch (FaceNum)
|
||||
{
|
||||
case 0:
|
||||
return IL_CUBEMAP_POSITIVEX;
|
||||
case 1:
|
||||
return IL_CUBEMAP_NEGATIVEX;
|
||||
case 2:
|
||||
return IL_CUBEMAP_POSITIVEY;
|
||||
case 3:
|
||||
return IL_CUBEMAP_NEGATIVEY;
|
||||
case 4:
|
||||
return IL_CUBEMAP_POSITIVEZ;
|
||||
case 5:
|
||||
return IL_CUBEMAP_NEGATIVEZ;
|
||||
case 6:
|
||||
return IL_SPHEREMAP;
|
||||
}
|
||||
|
||||
return IL_SPHEREMAP; // Should never reach here!
|
||||
}
|
||||
|
||||
|
||||
ILboolean VtfInitFacesMipmaps(ILimage *BaseImage, ILuint NumFaces, VTFHEAD *Header)
|
||||
{
|
||||
ILimage *Image;
|
||||
ILuint Face;
|
||||
|
||||
// Initialize mipmaps under the base image.
|
||||
VtfInitMipmaps(BaseImage, Header);
|
||||
Image = BaseImage;
|
||||
|
||||
// We have an environment map.
|
||||
if (NumFaces != 1) {
|
||||
Image->CubeFlags = IL_CUBEMAP_POSITIVEX;
|
||||
}
|
||||
|
||||
for (Face = 1; Face < NumFaces; Face++) {
|
||||
Image->Faces = ilNewImageFull(Image->Width, Image->Height, Image->Depth, Image->Bpp, Image->Format, Image->Type, NULL);
|
||||
if (Image->Faces == NULL)
|
||||
return IL_FALSE;
|
||||
Image = Image->Faces;
|
||||
|
||||
// The origin should be in the upper left.
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
// Set the flags that tell which face this is.
|
||||
Image->CubeFlags = GetFaceFlag(Face);
|
||||
|
||||
// Now we can initialize the mipmaps under each face.
|
||||
VtfInitMipmaps(Image, Header);
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean VtfInitMipmaps(ILimage *BaseImage, VTFHEAD *Header)
|
||||
{
|
||||
ILimage *Image;
|
||||
ILuint Width, Height, Depth, Mipmap;
|
||||
|
||||
Image = BaseImage;
|
||||
Width = BaseImage->Width; Height = BaseImage->Height; Depth = BaseImage->Depth;
|
||||
|
||||
for (Mipmap = 1; Mipmap < Header->MipmapCount; Mipmap++) {
|
||||
// 1 is the smallest dimension possible.
|
||||
Width = (Width >> 1) == 0 ? 1 : (Width >> 1);
|
||||
Height = (Height >> 1) == 0 ? 1 : (Height >> 1);
|
||||
Depth = (Depth >> 1) == 0 ? 1 : (Depth >> 1);
|
||||
|
||||
Image->Mipmaps = ilNewImageFull(Width, Height, Depth, BaseImage->Bpp, BaseImage->Format, BaseImage->Type, NULL);
|
||||
if (Image->Mipmaps == NULL)
|
||||
return IL_FALSE;
|
||||
Image = Image->Mipmaps;
|
||||
|
||||
// ilNewImage does not set these.
|
||||
Image->Format = BaseImage->Format;
|
||||
Image->Type = BaseImage->Type;
|
||||
// The origin should be in the upper left.
|
||||
Image->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ILboolean CheckDimensions()
|
||||
{
|
||||
if ((ilNextPower2(iCurImage->Width) != iCurImage->Width) || (ilNextPower2(iCurImage->Height) != iCurImage->Height)) {
|
||||
ilSetError(IL_BAD_DIMENSIONS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
//! Writes a Vtf file
|
||||
ILboolean ilSaveVtf(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE VtfFile;
|
||||
ILuint VtfSize;
|
||||
|
||||
if (!CheckDimensions())
|
||||
return IL_FALSE;
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
VtfFile = iopenw(FileName);
|
||||
if (VtfFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
VtfSize = ilSaveVtfF(VtfFile);
|
||||
iclosew(VtfFile);
|
||||
|
||||
if (VtfSize == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a .vtf to an already-opened file
|
||||
ILuint ilSaveVtfF(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos;
|
||||
if (!CheckDimensions())
|
||||
return 0;
|
||||
iSetOutputFile(File);
|
||||
Pos = itellw();
|
||||
if (iSaveVtfInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes a .vtf to a memory "lump"
|
||||
ILuint ilSaveVtfL(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos;
|
||||
if (!CheckDimensions())
|
||||
return 0;
|
||||
iSetOutputLump(Lump, Size);
|
||||
Pos = itellw();
|
||||
if (iSaveVtfInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
// Internal function used to save the Vtf.
|
||||
ILboolean iSaveVtfInternal()
|
||||
{
|
||||
ILimage *TempImage = iCurImage;
|
||||
ILubyte *TempData, *CompData;
|
||||
ILuint Format, i, CompSize;
|
||||
ILenum Compression;
|
||||
|
||||
// Find out if the user has specified to use DXT compression.
|
||||
Compression = ilGetInteger(IL_VTF_COMP);
|
||||
|
||||
//@TODO: Other formats
|
||||
if (Compression == IL_DXT_NO_COMP) {
|
||||
switch (TempImage->Format)
|
||||
{
|
||||
case IL_RGB:
|
||||
Format = IMAGE_FORMAT_RGB888;
|
||||
break;
|
||||
case IL_RGBA:
|
||||
Format = IMAGE_FORMAT_RGBA8888;
|
||||
break;
|
||||
case IL_BGR:
|
||||
Format = IMAGE_FORMAT_BGR888;
|
||||
break;
|
||||
case IL_BGRA:
|
||||
Format = IMAGE_FORMAT_BGRA8888;
|
||||
break;
|
||||
case IL_LUMINANCE:
|
||||
Format = IMAGE_FORMAT_I8;
|
||||
break;
|
||||
case IL_ALPHA:
|
||||
Format = IMAGE_FORMAT_A8;
|
||||
break;
|
||||
case IL_LUMINANCE_ALPHA:
|
||||
Format = IMAGE_FORMAT_IA88;
|
||||
break;
|
||||
//case IL_COLOUR_INDEX:
|
||||
default:
|
||||
Format = IMAGE_FORMAT_BGRA8888;
|
||||
TempImage = iConvertImage(iCurImage, IL_BGRA, IL_UNSIGNED_BYTE);
|
||||
if (TempImage == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
//@TODO: When we have the half format available internally, also use IMAGE_FORMAT_RGBA16161616F.
|
||||
if (TempImage->Format == IL_RGBA && TempImage->Type == IL_UNSIGNED_SHORT) {
|
||||
Format = IMAGE_FORMAT_RGBA16161616;
|
||||
}
|
||||
else if (TempImage->Type != IL_UNSIGNED_BYTE) { //@TODO: Any possibility for shorts, etc. to be used?
|
||||
TempImage = iConvertImage(iCurImage, Format, IL_UNSIGNED_BYTE);
|
||||
if (TempImage == NULL)
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
else { // We are using DXT compression.
|
||||
switch (Compression)
|
||||
{
|
||||
case IL_DXT1:
|
||||
Format = IMAGE_FORMAT_DXT1_ONEBITALPHA;//IMAGE_FORMAT_DXT1;
|
||||
break;
|
||||
case IL_DXT3:
|
||||
Format = IMAGE_FORMAT_DXT3;
|
||||
break;
|
||||
case IL_DXT5:
|
||||
Format = IMAGE_FORMAT_DXT5;
|
||||
break;
|
||||
default: // Should never reach this point.
|
||||
ilSetError(IL_INTERNAL_ERROR);
|
||||
Format = IMAGE_FORMAT_DXT5;
|
||||
}
|
||||
}
|
||||
|
||||
if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
|
||||
TempData = iGetFlipped(TempImage);
|
||||
if (TempData == NULL) {
|
||||
ilCloseImage(TempImage);
|
||||
return IL_FALSE;
|
||||
}
|
||||
} else {
|
||||
TempData = TempImage->Data;
|
||||
}
|
||||
|
||||
// Write the file signature.
|
||||
iwrite("VTF", 1, 4);
|
||||
// Write the file version - currently using 7.2 specs.
|
||||
SaveLittleUInt(7);
|
||||
SaveLittleUInt(2);
|
||||
// Write the header size.
|
||||
SaveLittleUInt(80);
|
||||
// Now we write the width and height of the image.
|
||||
SaveLittleUShort(TempImage->Width);
|
||||
SaveLittleUShort(TempImage->Height);
|
||||
//@TODO: This is supposed to be the flags used. What should we use here? Let users specify?
|
||||
SaveLittleUInt(0);
|
||||
// Number of frames in the animation. - @TODO: Change to use animations.
|
||||
SaveLittleUShort(1);
|
||||
// First frame in the animation
|
||||
SaveLittleUShort(0);
|
||||
// Padding
|
||||
SaveLittleUInt(0);
|
||||
// Reflectivity (3 floats) - @TODO: Use what values? User specified?
|
||||
SaveLittleFloat(0.0f);
|
||||
SaveLittleFloat(0.0f);
|
||||
SaveLittleFloat(0.0f);
|
||||
// Padding
|
||||
SaveLittleUInt(0);
|
||||
// Bumpmap scale
|
||||
SaveLittleFloat(0.0f);
|
||||
// Image format
|
||||
SaveLittleUInt(Format);
|
||||
// Mipmap count - @TODO: Use mipmaps
|
||||
iputc(1);
|
||||
// Low resolution image format - @TODO: Create low resolution image.
|
||||
SaveLittleUInt(0xFFFFFFFF);
|
||||
// Low resolution image width and height
|
||||
iputc(0);
|
||||
iputc(0);
|
||||
// Depth of the image - @TODO: Support for volumetric images.
|
||||
SaveLittleUShort(1);
|
||||
|
||||
// Write final padding for the header (out to 80 bytes).
|
||||
for (i = 0; i < 15; i++) {
|
||||
iputc(0);
|
||||
}
|
||||
|
||||
if (Compression == IL_DXT_NO_COMP) {
|
||||
// We just write the image data directly.
|
||||
if (iwrite(TempImage->Data, TempImage->SizeOfData, 1) != 1)
|
||||
return IL_FALSE;
|
||||
}
|
||||
else { // Do DXT compression here and write.
|
||||
// We have to find out how much we are writing first.
|
||||
CompSize = ilGetDXTCData(NULL, 0, Compression);
|
||||
if (CompSize == 0) {
|
||||
ilSetError(IL_INTERNAL_ERROR);
|
||||
if (TempData != TempImage->Data)
|
||||
ifree(TempData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
CompData = (ILubyte*)ialloc(CompSize);
|
||||
if (CompData == NULL) {
|
||||
if (TempData != TempImage->Data)
|
||||
ifree(TempData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
// DXT compress the data.
|
||||
CompSize = ilGetDXTCData(CompData, CompSize, Compression);
|
||||
if (CompSize == 0) {
|
||||
ilSetError(IL_INTERNAL_ERROR);
|
||||
if (TempData != TempImage->Data)
|
||||
ifree(TempData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
// Finally write the data.
|
||||
if (iwrite(CompData, CompSize, 1) != 1) {
|
||||
ifree(CompData);
|
||||
if (TempData != TempImage->Data)
|
||||
ifree(TempData);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (TempData != TempImage->Data)
|
||||
ifree(TempData);
|
||||
if (TempImage != iCurImage)
|
||||
ilCloseImage(TempImage);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_VTF
|
||||
@@ -0,0 +1,169 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_wal.c
|
||||
//
|
||||
// Description: Loads a Quake .wal texture.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_WAL
|
||||
#include "il_manip.h"
|
||||
#include "il_q2pal.h"
|
||||
|
||||
|
||||
typedef struct WALHEAD
|
||||
{
|
||||
ILbyte FileName[32]; // Image name
|
||||
ILuint Width; // Width of first image
|
||||
ILuint Height; // Height of first image
|
||||
ILuint Offsets[4]; // Offsets to image data
|
||||
ILbyte AnimName[32]; // Name of next frame
|
||||
ILuint Flags; // ??
|
||||
ILuint Contents; // ??
|
||||
ILuint Value; // ??
|
||||
} WALHEAD;
|
||||
|
||||
ILboolean iLoadWalInternal(void);
|
||||
|
||||
|
||||
//! Reads a .wal file
|
||||
ILboolean ilLoadWal(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE WalFile;
|
||||
ILboolean bWal = IL_FALSE;
|
||||
|
||||
WalFile = iopenr(FileName);
|
||||
if (WalFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bWal;
|
||||
}
|
||||
|
||||
bWal = ilLoadWalF(WalFile);
|
||||
icloser(WalFile);
|
||||
|
||||
return bWal;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .wal file
|
||||
ILboolean ilLoadWalF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadWalInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a .wal file
|
||||
ILboolean ilLoadWalL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadWalInternal();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadWalInternal()
|
||||
{
|
||||
WALHEAD Header;
|
||||
ILimage *Mipmaps[3], *CurImage;
|
||||
ILuint i, NewW, NewH;
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
CurImage = iCurImage;
|
||||
|
||||
|
||||
// Read header
|
||||
iread(&Header.FileName, 1, 32);
|
||||
Header.Width = GetLittleUInt();
|
||||
Header.Height = GetLittleUInt();
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
Header.Offsets[i] = GetLittleUInt();
|
||||
|
||||
iread(Header.AnimName, 1, 32);
|
||||
Header.Flags = GetLittleUInt();
|
||||
Header.Contents = GetLittleUInt();
|
||||
Header.Value = GetLittleUInt();
|
||||
|
||||
if (!ilTexImage(Header.Width, Header.Height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
Mipmaps[i] = (ILimage*)icalloc(sizeof(ILimage), 1);
|
||||
if (Mipmaps[i] == NULL)
|
||||
goto cleanup_error;
|
||||
Mipmaps[i]->Pal.Palette = (ILubyte*)ialloc(768);
|
||||
if (Mipmaps[i]->Pal.Palette == NULL)
|
||||
goto cleanup_error;
|
||||
memcpy(Mipmaps[i]->Pal.Palette, ilDefaultQ2Pal, 768);
|
||||
Mipmaps[i]->Pal.PalType = IL_PAL_RGB24;
|
||||
}
|
||||
|
||||
NewW = Header.Width;
|
||||
NewH = Header.Height;
|
||||
for (i = 0; i < 3; i++) {
|
||||
NewW /= 2;
|
||||
NewH /= 2;
|
||||
iCurImage = Mipmaps[i];
|
||||
if (!ilTexImage(NewW, NewH, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL))
|
||||
goto cleanup_error;
|
||||
// Don't set until now so ilTexImage won't get rid of the palette.
|
||||
Mipmaps[i]->Pal.PalSize = 768;
|
||||
Mipmaps[i]->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
}
|
||||
|
||||
iCurImage = CurImage;
|
||||
ilCloseImage(iCurImage->Mipmaps);
|
||||
iCurImage->Mipmaps = Mipmaps[0];
|
||||
Mipmaps[0]->Mipmaps = Mipmaps[1];
|
||||
Mipmaps[1]->Mipmaps = Mipmaps[2];
|
||||
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
if (iCurImage->Pal.Palette && iCurImage->Pal.PalSize && iCurImage->Pal.PalType != IL_PAL_NONE)
|
||||
ifree(iCurImage->Pal.Palette);
|
||||
iCurImage->Pal.Palette = (ILubyte*)ialloc(768);
|
||||
if (iCurImage->Pal.Palette == NULL)
|
||||
goto cleanup_error;
|
||||
|
||||
iCurImage->Pal.PalSize = 768;
|
||||
iCurImage->Pal.PalType = IL_PAL_RGB24;
|
||||
memcpy(iCurImage->Pal.Palette, ilDefaultQ2Pal, 768);
|
||||
|
||||
iseek(Header.Offsets[0], IL_SEEK_SET);
|
||||
if (iread(iCurImage->Data, Header.Width * Header.Height, 1) != 1)
|
||||
goto cleanup_error;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
iseek(Header.Offsets[i+1], IL_SEEK_SET);
|
||||
if (iread(Mipmaps[i]->Data, Mipmaps[i]->Width * Mipmaps[i]->Height, 1) != 1)
|
||||
goto cleanup_error;
|
||||
}
|
||||
|
||||
// Fixes all images, even mipmaps.
|
||||
return ilFixImage();
|
||||
|
||||
cleanup_error:
|
||||
for (i = 0; i < 3; i++) {
|
||||
ilCloseImage(Mipmaps[i]);
|
||||
}
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
#endif//IL_NO_WAL
|
||||
@@ -0,0 +1,274 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 03/07/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_wbmp.c
|
||||
//
|
||||
// Description: Reads from a Wireless Bitmap (.wbmp) file. Specs available from
|
||||
// http://www.ibm.com/developerworks/wireless/library/wi-wbmp/
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_WBMP
|
||||
#include "il_bits.h"
|
||||
|
||||
|
||||
ILboolean iLoadWbmpInternal(void);
|
||||
ILuint WbmpGetMultibyte(void);
|
||||
ILboolean iSaveWbmpInternal(void);
|
||||
|
||||
// Reads a .wbmp file
|
||||
ILboolean ilLoadWbmp(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE WbmpFile;
|
||||
ILboolean bWbmp = IL_FALSE;
|
||||
|
||||
WbmpFile = iopenr(FileName);
|
||||
if (WbmpFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bWbmp;
|
||||
}
|
||||
|
||||
iSetInputFile(WbmpFile);
|
||||
|
||||
bWbmp = ilLoadWbmpF(WbmpFile);
|
||||
|
||||
icloser(WbmpFile);
|
||||
|
||||
return bWbmp;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .wbmp file
|
||||
ILboolean ilLoadWbmpF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadWbmpInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a .wbmp
|
||||
ILboolean ilLoadWbmpL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadWbmpInternal();
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadWbmpInternal(void)
|
||||
{
|
||||
ILuint Width, Height, BitPadding, i;
|
||||
BITFILE *File;
|
||||
ILubyte Padding[8];
|
||||
|
||||
if (iCurImage == NULL) {
|
||||
ilSetError(IL_ILLEGAL_OPERATION);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (igetc() != 0 || igetc() != 0) { // The first two bytes have to be 0 (the "header")
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Width = WbmpGetMultibyte(); // Next follows the width and height.
|
||||
Height = WbmpGetMultibyte();
|
||||
|
||||
if (Width == 0 || Height == 0) { // Must have at least some height and width.
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
if (!ilTexImage(Width, Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))
|
||||
return IL_FALSE;
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT; // Always has origin in the upper left.
|
||||
|
||||
BitPadding = (8 - (Width % 8)) % 8; // Has to be aligned on a byte boundary. The rest is padding.
|
||||
File = bfile(iGetFile());
|
||||
if (File == NULL)
|
||||
return IL_FALSE; //@TODO: Error?
|
||||
|
||||
//@TODO: Do this without bread? Would be faster, since we would not have to do
|
||||
// the second loop.
|
||||
|
||||
// Reads the bits
|
||||
for (i = 0; i < iCurImage->Height; i++) {
|
||||
bread(&iCurImage->Data[iCurImage->Width * i], 1, iCurImage->Width, File);
|
||||
//bseek(File, BitPadding, IL_SEEK_CUR); //@TODO: This function does not work correctly.
|
||||
bread(Padding, 1, BitPadding, File); // Skip padding bits.
|
||||
}
|
||||
// Converts bit value of 1 to white and leaves 0 at 0 (2-colour images only).
|
||||
for (i = 0; i < iCurImage->SizeOfData; i++) {
|
||||
if (iCurImage->Data[i] == 1)
|
||||
iCurImage->Data[i] = 0xFF; // White
|
||||
}
|
||||
|
||||
bclose(File);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILuint WbmpGetMultibyte()
|
||||
{
|
||||
ILuint Val = 0, i;
|
||||
ILubyte Cur;
|
||||
|
||||
for (i = 0; i < 5; i++) { // Should not be more than 5 bytes.
|
||||
Cur = igetc();
|
||||
Val = (Val << 7) | (Cur & 0x7F); // Drop the MSB of Cur.
|
||||
if (!(Cur & 0x80)) { // Check the MSB and break if 0.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Val;
|
||||
}
|
||||
|
||||
|
||||
ILboolean WbmpPutMultibyte(ILuint Val)
|
||||
{
|
||||
ILint i, NumBytes = 0;
|
||||
ILuint MultiVal = Val;
|
||||
|
||||
do {
|
||||
MultiVal >>= 7;
|
||||
NumBytes++;
|
||||
} while (MultiVal != 0);
|
||||
|
||||
for (i = NumBytes - 1; i >= 0; i--) {
|
||||
MultiVal = (Val >> (i * 7)) & 0x7F;
|
||||
if (i != 0)
|
||||
MultiVal |= 0x80;
|
||||
iputc(MultiVal);
|
||||
}
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a Wbmp file
|
||||
ILboolean ilSaveWbmp(const ILstring FileName)
|
||||
{
|
||||
ILHANDLE WbmpFile;
|
||||
ILuint WbmpSize;
|
||||
|
||||
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
||||
if (iFileExists(FileName)) {
|
||||
ilSetError(IL_FILE_ALREADY_EXISTS);
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
WbmpFile = iopenw(FileName);
|
||||
if (WbmpFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
WbmpSize = ilSaveWbmpF(WbmpFile);
|
||||
iclosew(WbmpFile);
|
||||
|
||||
if (WbmpSize == 0)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//! Writes a .wbmp to an already-opened file
|
||||
ILuint ilSaveWbmpF(ILHANDLE File)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputFile(File);
|
||||
Pos = itellw();
|
||||
if (iSaveWbmpInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
//! Writes a .wbmp to a memory "lump"
|
||||
ILuint ilSaveWbmpL(void *Lump, ILuint Size)
|
||||
{
|
||||
ILuint Pos;
|
||||
iSetOutputLump(Lump, Size);
|
||||
Pos = itellw();
|
||||
if (iSaveWbmpInternal() == IL_FALSE)
|
||||
return 0; // Error occurred
|
||||
return itellw() - Pos; // Return the number of bytes written.
|
||||
}
|
||||
|
||||
|
||||
// In il_quantizer.c
|
||||
ILimage *iQuantizeImage(ILimage *Image, ILuint NumCols);
|
||||
// In il_neuquant.c
|
||||
ILimage *iNeuQuant(ILimage *Image, ILuint NumCols);
|
||||
|
||||
|
||||
// Internal function used to save the Wbmp.
|
||||
ILboolean iSaveWbmpInternal()
|
||||
{
|
||||
ILimage *TempImage = NULL;
|
||||
ILuint i, j;
|
||||
ILint k;
|
||||
ILubyte Val;
|
||||
ILubyte *TempData;
|
||||
|
||||
iputc(0); // First two header values
|
||||
iputc(0); // must be 0.
|
||||
|
||||
WbmpPutMultibyte(iCurImage->Width); // Write the width
|
||||
WbmpPutMultibyte(iCurImage->Height); // and the height.
|
||||
|
||||
//TempImage = iConvertImage(iCurImage, IL_LUMINANCE, IL_UNSIGNED_BYTE);
|
||||
if (iGetInt(IL_QUANTIZATION_MODE) == IL_NEU_QUANT)
|
||||
TempImage = iNeuQuant(iCurImage, 2);
|
||||
else // Assume IL_WU_QUANT otherwise.
|
||||
TempImage = iQuantizeImage(iCurImage, 2);
|
||||
|
||||
if (TempImage == NULL)
|
||||
return IL_FALSE;
|
||||
|
||||
if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
|
||||
TempData = iGetFlipped(TempImage);
|
||||
if (TempData == NULL) {
|
||||
ilCloseImage(TempImage);
|
||||
return IL_FALSE;
|
||||
}
|
||||
} else {
|
||||
TempData = TempImage->Data;
|
||||
}
|
||||
|
||||
for (i = 0; i < TempImage->Height; i++) {
|
||||
for (j = 0; j < TempImage->Width; j += 8) {
|
||||
Val = 0;
|
||||
for (k = 0; k < 8; k++) {
|
||||
if (j + k < TempImage->Width) {
|
||||
//Val |= ((TempData[TempImage->Width * i + j + k] > 0x7F) ? (0x80 >> k) : 0x00);
|
||||
Val |= ((TempData[TempImage->Width * i + j + k] == 1) ? (0x80 >> k) : 0x00);
|
||||
}
|
||||
}
|
||||
iputc(Val);
|
||||
}
|
||||
}
|
||||
|
||||
if (TempData != TempImage->Data)
|
||||
ifree(TempData);
|
||||
ilCloseImage(TempImage);
|
||||
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
#endif//IL_NO_WBMP
|
||||
|
||||
@@ -0,0 +1,429 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Last modified: 02/09/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_wdp.c
|
||||
//
|
||||
// Description: Reads a Microsoft HD Photo (.wdp or .hdp)
|
||||
// Based very much on the Microsoft HD Photo Device Porting Kit 1.0
|
||||
// available at
|
||||
// http://www.microsoft.com/downloads/details.aspx?FamilyID=285eeffd-d86c-48c3-ab93-3abd5ee7f1ce&displaylang=en.
|
||||
//
|
||||
// Note: The license that the Device Porting Kit is under is not very clear.
|
||||
// Commentary on the license can be found at http://en.wikipedia.org/wiki/HD_Photo.
|
||||
// Lots of this code is taken from the examples in the DPK and from code
|
||||
// within the DPK itself. For this reason, this file is not under the LGPL
|
||||
// license, unlike the rest of DevIL.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_WDP
|
||||
#include <WMPGlue.h>
|
||||
#include "il_wdp.h"
|
||||
|
||||
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#ifndef _DEBUG
|
||||
#pragma comment(lib, "wmplib.lib")
|
||||
#else
|
||||
#pragma comment(lib, "wmplib-d.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
//! Reads a WDP file
|
||||
ILboolean ilLoadWdp(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE WdpFile;
|
||||
ILboolean bWdp = IL_FALSE;
|
||||
|
||||
WdpFile = iopenr(FileName);
|
||||
if (WdpFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bWdp;
|
||||
}
|
||||
|
||||
bWdp = ilLoadWdpF(WdpFile);
|
||||
icloser(WdpFile);
|
||||
|
||||
return bWdp;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened WDP file
|
||||
ILboolean ilLoadWdpF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadWdpInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains a WDP
|
||||
ILboolean ilLoadWdpL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadWdpInternal();
|
||||
}
|
||||
|
||||
//@TODO: Put in ilPKImageEncode_WritePixels_DevIL?
|
||||
ERR WriteDevILHeader(PKImageEncode* pIE)
|
||||
{
|
||||
struct WMPStream* pS = pIE->pStream;
|
||||
|
||||
if (IsEqualGUID(&GUID_PKPixelFormat24bppRGB, &pIE->guidPixFormat) || IsEqualGUID(&GUID_PKPixelFormat24bppBGR, &pIE->guidPixFormat))
|
||||
{
|
||||
pIE->cbPixel = 3;
|
||||
}
|
||||
else if (IsEqualGUID(&GUID_PKPixelFormat32bppBGRA, &pIE->guidPixFormat)
|
||||
|| IsEqualGUID(&GUID_PKPixelFormat32bppBGR, &pIE->guidPixFormat)
|
||||
|| IsEqualGUID(&GUID_PKPixelFormat32bppPBGRA, &pIE->guidPixFormat))
|
||||
{
|
||||
pIE->cbPixel = 4;
|
||||
}
|
||||
else if (IsEqualGUID(&GUID_PKPixelFormat8bppGray, &pIE->guidPixFormat))
|
||||
{
|
||||
pIE->cbPixel = 1;
|
||||
}
|
||||
else if (IsEqualGUID(&GUID_PKPixelFormat16bppGray, &pIE->guidPixFormat))
|
||||
{
|
||||
pIE->cbPixel = 2;
|
||||
}
|
||||
else if (IsEqualGUID(&GUID_PKPixelFormat128bppRGBAFloat, &pIE->guidPixFormat))
|
||||
{
|
||||
pIE->cbPixel = 16;//4;
|
||||
}
|
||||
|
||||
|
||||
pIE->offPixel = pIE->offStart;
|
||||
pIE->fHeaderDone = !IL_FALSE;
|
||||
|
||||
return WMP_errSuccess;
|
||||
}
|
||||
|
||||
ERR ilPKImageEncode_WritePixels_DevIL(PKImageEncode* pIE, U32 cLine, U8* pbPixel, U32 cbStride)
|
||||
{
|
||||
ERR err = WMP_errSuccess;
|
||||
|
||||
struct WMPStream* pS = pIE->pStream;
|
||||
size_t cbLineM = 0, cbLineS = 0;
|
||||
I32 i = 0;
|
||||
static U8 pPadding[4] = {0};
|
||||
|
||||
// header
|
||||
if (!pIE->fHeaderDone)
|
||||
{
|
||||
// WriteBMPHeader() also inits this object
|
||||
Call(WriteDevILHeader(pIE));
|
||||
}
|
||||
|
||||
// body
|
||||
// calculate line size in memory and in stream
|
||||
cbLineM = pIE->cbPixel * pIE->uWidth;
|
||||
cbLineS = (cbLineM + 3) / 4 * 4;
|
||||
|
||||
//FailIf(pRect->X < 0 || pID->uWidth <= pRect->X, WMP_errInvalidParameter);
|
||||
//FailIf(pRect->Y < 0 || pID->uHeight <= pRect->Y, WMP_errInvalidParameter);
|
||||
//FailIf(pRect->Width < 0 || pID->uWidth < pRect->X + pRect->Width, WMP_errInvalidParameter);
|
||||
//FailIf(pRect->Height < 0 || pID->uHeight < pRect->Y + pRect->Height, WMP_errInvalidParameter);
|
||||
FailIf(cbStride < cbLineM, WMP_errInvalidParameter);
|
||||
|
||||
for (i = cLine - 1; 0 <= i; --i)
|
||||
{
|
||||
size_t offM = cbStride * i;
|
||||
size_t offS = cbLineS * (pIE->uHeight - (pIE->idxCurrentLine + i + 1));
|
||||
|
||||
Call(pS->SetPos(pS, pIE->offPixel + offS));
|
||||
Call(pS->Write(pS, pbPixel + offM, cbLineM));
|
||||
}
|
||||
Call(pS->Write(pS, pPadding, (cbLineS - cbLineM)));
|
||||
pIE->idxCurrentLine += cLine;
|
||||
|
||||
Cleanup:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
ERR PKImageEncode_Create_DevIL(
|
||||
PKImageEncode** ppIE)
|
||||
{
|
||||
ERR err = WMP_errSuccess;
|
||||
PKImageEncode* pIE = NULL;
|
||||
|
||||
Call(PKImageEncode_Create(ppIE));
|
||||
|
||||
pIE = *ppIE;
|
||||
pIE->WritePixels = ilPKImageEncode_WritePixels_DevIL;
|
||||
|
||||
Cleanup:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
ERR iWmpDecAppCreateEncoderFromExt(
|
||||
PKCodecFactory* pCFactory,
|
||||
const char* szExt,
|
||||
PKImageEncode** ppIE)
|
||||
{
|
||||
ERR err = WMP_errSuccess;
|
||||
const PKIID* pIID = NULL;
|
||||
|
||||
// get encod PKIID
|
||||
Call(GetImageEncodeIID(szExt, &pIID));
|
||||
|
||||
// Create encoder
|
||||
//Call(PKCodecFactory_CreateCodec(pIID, ppIE));
|
||||
|
||||
Call(PKImageEncode_Create_DevIL(ppIE));
|
||||
|
||||
Cleanup:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
ERR iCloseWS_File(struct WMPStream** ppWS)
|
||||
{
|
||||
ERR err = WMP_errSuccess;
|
||||
/*struct WMPStream* pWS = *ppWS;
|
||||
|
||||
fclose(pWS->state.file.pFile);
|
||||
Call(WMPFree((void**)ppWS));
|
||||
|
||||
Cleanup:*/
|
||||
return err;
|
||||
}
|
||||
|
||||
Bool iEOSWS_File(struct WMPStream* pWS)
|
||||
{
|
||||
//return feof(pWS->state.file.pFile);
|
||||
return ieof();
|
||||
}
|
||||
|
||||
ERR iReadWS_File(struct WMPStream* pWS, void* pv, size_t cb)
|
||||
{
|
||||
// For some reason, the WDP images load just fine, but it tries to read too much,
|
||||
// so IL_FILE_READ_ERROR is set. So we get rid of the error.
|
||||
if (iread(pv, 1, (ILuint)cb) != cb)
|
||||
ilGetError();
|
||||
return WMP_errSuccess;
|
||||
}
|
||||
|
||||
ERR iWriteWS_File(struct WMPStream* pWS, const void* pv, size_t cb)
|
||||
{
|
||||
ERR err = WMP_errSuccess;
|
||||
|
||||
if (0 != cb) {
|
||||
FailIf(1 != iwrite(pv, (ILuint)cb, 1), WMP_errFileIO);
|
||||
}
|
||||
|
||||
Cleanup:
|
||||
return err;
|
||||
}
|
||||
|
||||
ERR iSetPosWS_File(struct WMPStream* pWS, size_t offPos)
|
||||
{
|
||||
ERR err = WMP_errSuccess;
|
||||
|
||||
//FailIf(0 != fseek(pWS->state.file.pFile, (long)offPos, SEEK_SET), WMP_errFileIO);
|
||||
FailIf(0 != iseek((ILuint)offPos, IL_SEEK_SET), WMP_errFileIO);
|
||||
|
||||
Cleanup:
|
||||
return err;
|
||||
}
|
||||
|
||||
ERR iGetPosWS_File(struct WMPStream* pWS, size_t* poffPos)
|
||||
{
|
||||
ERR err = WMP_errSuccess;
|
||||
long lOff = 0;
|
||||
|
||||
//FailIf(-1 == (lOff = ftell(pWS->state.file.pFile)), WMP_errFileIO);
|
||||
lOff = itell();
|
||||
*poffPos = (size_t)lOff;
|
||||
|
||||
Cleanup:
|
||||
return err;
|
||||
}
|
||||
|
||||
ERR ilCreateWS_File(struct WMPStream** ppWS, const char* szFilename, const char* szMode)
|
||||
{
|
||||
ERR err = WMP_errSuccess;
|
||||
struct WMPStream* pWS = NULL;
|
||||
|
||||
*ppWS = icalloc(1, sizeof(**ppWS));
|
||||
if (*ppWS == NULL)
|
||||
return WMP_errOutOfMemory;
|
||||
pWS = *ppWS;
|
||||
|
||||
pWS->Close = iCloseWS_File;
|
||||
pWS->EOS = iEOSWS_File;
|
||||
|
||||
pWS->Read = iReadWS_File;
|
||||
pWS->Write = iWriteWS_File;
|
||||
//pWS->GetLine = GetLineWS_File;
|
||||
|
||||
pWS->SetPos = iSetPosWS_File;
|
||||
pWS->GetPos = iGetPosWS_File;
|
||||
|
||||
//pWS->state.file.pFile = fopen(szFilename, szMode);
|
||||
pWS->state.file.pFile = NULL;
|
||||
//FailIf(NULL == pWS->state.file.pFile, WMP_errFileIO);
|
||||
|
||||
Cleanup:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
ERR ilPKCodecFactory_CreateDecoderFromFile(PKImageDecode** ppDecoder)
|
||||
{
|
||||
ERR err = WMP_errSuccess;
|
||||
|
||||
char *pExt = ".wdp"; // We are loading a WDP file, so we have to tell the library that with this extension.
|
||||
PKIID* pIID = NULL;
|
||||
|
||||
struct WMPStream* pStream = NULL;
|
||||
PKImageDecode* pDecoder = NULL;
|
||||
|
||||
// get decode PKIID
|
||||
Call(GetImageDecodeIID(pExt, &pIID));
|
||||
|
||||
// create stream
|
||||
Call(ilCreateWS_File(&pStream, NULL, "rb"));
|
||||
|
||||
// Create decoder
|
||||
Call(PKCodecFactory_CreateCodec(pIID, ppDecoder));
|
||||
pDecoder = *ppDecoder;
|
||||
|
||||
// attach stream to decoder
|
||||
Call(pDecoder->Initialize(pDecoder, pStream));
|
||||
pDecoder->fStreamOwner = !0;
|
||||
|
||||
Cleanup:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
ERR ilPKCreateFactory(PKFactory** ppFactory, U32 uVersion)
|
||||
{
|
||||
ERR err = WMP_errSuccess;
|
||||
PKFactory* pFactory = NULL;
|
||||
|
||||
Call(PKAlloc(ppFactory, sizeof(**ppFactory)));
|
||||
pFactory = *ppFactory;
|
||||
|
||||
pFactory->CreateStream = PKCreateFactory_CreateStream;
|
||||
|
||||
pFactory->CreateStreamFromFilename = ilCreateWS_File;
|
||||
pFactory->CreateStreamFromMemory = CreateWS_Memory;
|
||||
|
||||
pFactory->Release = PKCreateFactory_Release;
|
||||
|
||||
Cleanup:
|
||||
return err;
|
||||
}
|
||||
|
||||
ILboolean iLoadWdpInternal(/*ILconst_string FileName*/)
|
||||
{
|
||||
ERR err = WMP_errSuccess;
|
||||
PKFactory* pFactory = NULL;
|
||||
PKCodecFactory* pCodecFactory = NULL;
|
||||
PKImageDecode* pDecoder = NULL;
|
||||
PKPixelInfo PI;
|
||||
PKPixelFormatGUID guidPixFormat;
|
||||
PKFormatConverter* pConverter = NULL;
|
||||
U32 cFrame = 0, i = 0;
|
||||
PKRect Rect;
|
||||
struct WMPStream* pEncodeStream = NULL;
|
||||
PKImageEncode* pEncoder = NULL;
|
||||
|
||||
//Call(PKCreateFactory(&pFactory, PK_SDK_VERSION));
|
||||
//Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION));
|
||||
//Call(pCodecFactory->CreateDecoderFromFile(FileName, &pDecoder));
|
||||
Call(ilPKCreateFactory(&pFactory, PK_SDK_VERSION));
|
||||
Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION));
|
||||
Call(ilPKCodecFactory_CreateDecoderFromFile(&pDecoder));
|
||||
|
||||
//guidPixFormat = GUID_PKPixelFormat24bppRGB;
|
||||
guidPixFormat = GUID_PKPixelFormat32bppBGRA;
|
||||
//guidPixFormat = GUID_PKPixelFormat8bppGray;
|
||||
//guidPixFormat = GUID_PKPixelFormat16bppGray;
|
||||
|
||||
// Color transcoding
|
||||
if (IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat8bppGray) || IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat16bppGray)){ // ** => Y transcoding
|
||||
pDecoder->guidPixFormat = guidPixFormat;
|
||||
pDecoder->WMP.wmiI.cfColorFormat = Y_ONLY;
|
||||
}
|
||||
else if(IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat24bppRGB) && pDecoder->WMP.wmiI.cfColorFormat == CMYK){ // CMYK = > RGB
|
||||
pDecoder->WMP.wmiI.cfColorFormat = CF_RGB;
|
||||
pDecoder->guidPixFormat = guidPixFormat;
|
||||
pDecoder->WMP.wmiI.bRGB = 1; //RGB
|
||||
}
|
||||
|
||||
PI.pGUIDPixFmt = &guidPixFormat;
|
||||
PixelFormatLookup(&PI, LOOKUP_FORWARD);
|
||||
|
||||
pDecoder->WMP.wmiSCP.bfBitstreamFormat = 0;
|
||||
pDecoder->WMP.wmiSCP.uAlphaMode = 0;
|
||||
pDecoder->WMP.wmiSCP.sbSubband = SB_ALL;
|
||||
pDecoder->WMP.bIgnoreOverlap = FALSE;
|
||||
|
||||
pDecoder->WMP.wmiI.cfColorFormat = PI.cfColorFormat;
|
||||
|
||||
pDecoder->WMP.wmiI.bdBitDepth = PI.bdBitDepth;
|
||||
pDecoder->WMP.wmiI.cBitsPerUnit = PI.cbitUnit;
|
||||
|
||||
//==== Validate thumbnail decode parameters =====
|
||||
pDecoder->WMP.wmiI.cThumbnailWidth = pDecoder->WMP.wmiI.cWidth;
|
||||
pDecoder->WMP.wmiI.cThumbnailHeight = pDecoder->WMP.wmiI.cHeight;
|
||||
pDecoder->WMP.wmiI.bSkipFlexbits = FALSE;
|
||||
|
||||
pCodecFactory->CreateFormatConverter(&pConverter);
|
||||
pConverter->Initialize(pConverter, pDecoder, NULL, guidPixFormat);
|
||||
|
||||
// Right now, we are just assuming one frame.
|
||||
// @TODO: Deal with multiple frames.
|
||||
//pDecoder->GetFrameCount(pDecoder, &cFrame);
|
||||
//pDecoder->SelectFrame(pDecoder, 1);
|
||||
|
||||
if (!ilTexImage(pDecoder->uWidth, pDecoder->uHeight, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL))
|
||||
goto Cleanup;
|
||||
//ilTexImage(pDecoder->uWidth, pDecoder->uHeight, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, Data);
|
||||
|
||||
pFactory->CreateStreamFromMemory(&pEncodeStream, iCurImage->Data, iCurImage->SizeOfData);
|
||||
iWmpDecAppCreateEncoderFromExt(pCodecFactory, ".wdp", &pEncoder);
|
||||
pEncoder->Initialize(pEncoder, pEncodeStream, ".wdp", 0);
|
||||
|
||||
pEncoder->pStream->GetPos(pEncoder->pStream, &pEncoder->offStart);
|
||||
|
||||
// Set the region that we want to be the whole image.
|
||||
Rect.X = 0; Rect.Y = 0; Rect.Height = pDecoder->uHeight; Rect.Width = pDecoder->uWidth;
|
||||
pEncoder->SetPixelFormat(pEncoder, guidPixFormat);
|
||||
pEncoder->SetSize(pEncoder, Rect.Width, Rect.Height);
|
||||
pEncoder->WriteSource = PKImageEncode_Transcode;
|
||||
pEncoder->WriteSource(pEncoder, pConverter, &Rect);
|
||||
|
||||
|
||||
Cleanup:
|
||||
// Release everything all at the end.
|
||||
PKImageDecode_Release(&pDecoder);
|
||||
if (pEncoder)
|
||||
PKImageEncode_Release(&pEncoder);
|
||||
PKCreateCodecFactory_Release(&pCodecFactory);
|
||||
PKCreateFactory_Release(&pFactory);
|
||||
PKFormatConverter_Release(&pConverter);
|
||||
|
||||
if (err != WMP_errSuccess)
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
#endif//IL_NO_WDP
|
||||
@@ -0,0 +1,655 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ImageLib Sources
|
||||
// Copyright (C) 2000-2009 by Denton Woods
|
||||
// Last modified: 01/04/2009
|
||||
//
|
||||
// Filename: src-IL/src/il_xpm.c
|
||||
//
|
||||
// Description: Reads from an .xpm file.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "il_internal.h"
|
||||
#ifndef IL_NO_XPM
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
//If this is defined, only xpm files with 1 char/pixel
|
||||
//can be loaded. They load somewhat faster then, though
|
||||
//(not much).
|
||||
//#define XPM_DONT_USE_HASHTABLE
|
||||
|
||||
ILboolean iIsValidXpm(void);
|
||||
ILboolean iLoadXpmInternal(void);
|
||||
ILint XpmGetsInternal(ILubyte *Buffer, ILint MaxLen);
|
||||
|
||||
//! Checks if the file specified in FileName is a valid XPM file.
|
||||
ILboolean ilIsValidXpm(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE XpmFile;
|
||||
ILboolean bXpm = IL_FALSE;
|
||||
|
||||
if (!iCheckExtension(FileName, IL_TEXT("xpm"))) {
|
||||
ilSetError(IL_INVALID_EXTENSION);
|
||||
return bXpm;
|
||||
}
|
||||
|
||||
XpmFile = iopenr(FileName);
|
||||
if (XpmFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bXpm;
|
||||
}
|
||||
|
||||
bXpm = ilIsValidXpmF(XpmFile);
|
||||
icloser(XpmFile);
|
||||
|
||||
return bXpm;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if the ILHANDLE contains a valid XPM file at the current position.
|
||||
ILboolean ilIsValidXpmF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iIsValidXpm();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if Lump is a valid XPM lump.
|
||||
ILboolean ilIsValidXpmL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iIsValidXpm();
|
||||
}
|
||||
|
||||
|
||||
// Internal function to get the header and check it.
|
||||
ILboolean iIsValidXpm(void)
|
||||
{
|
||||
ILubyte Buffer[10];
|
||||
ILuint Pos = itell();
|
||||
|
||||
XpmGetsInternal(Buffer, 10);
|
||||
iseek(Pos, IL_SEEK_SET); // Restore position
|
||||
|
||||
if (strncmp("/* XPM */", (char*)Buffer, strlen("/* XPM */")))
|
||||
return IL_FALSE;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Reads an .xpm file
|
||||
ILboolean ilLoadXpm(ILconst_string FileName)
|
||||
{
|
||||
ILHANDLE XpmFile;
|
||||
ILboolean bXpm = IL_FALSE;
|
||||
|
||||
XpmFile = iopenr(FileName);
|
||||
if (XpmFile == NULL) {
|
||||
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
||||
return bXpm;
|
||||
}
|
||||
|
||||
iSetInputFile(XpmFile);
|
||||
bXpm = ilLoadXpmF(XpmFile);
|
||||
icloser(XpmFile);
|
||||
|
||||
return bXpm;
|
||||
}
|
||||
|
||||
|
||||
//! Reads an already-opened .xpm file
|
||||
ILboolean ilLoadXpmF(ILHANDLE File)
|
||||
{
|
||||
ILuint FirstPos;
|
||||
ILboolean bRet;
|
||||
|
||||
iSetInputFile(File);
|
||||
FirstPos = itell();
|
||||
bRet = iLoadXpmInternal();
|
||||
iseek(FirstPos, IL_SEEK_SET);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
//! Reads from a memory "lump" that contains an .xpm
|
||||
ILboolean ilLoadXpmL(const void *Lump, ILuint Size)
|
||||
{
|
||||
iSetInputLump(Lump, Size);
|
||||
return iLoadXpmInternal();
|
||||
}
|
||||
|
||||
|
||||
typedef ILubyte XpmPixel[4];
|
||||
|
||||
#define XPM_MAX_CHAR_PER_PIXEL 2
|
||||
|
||||
|
||||
#ifndef XPM_DONT_USE_HASHTABLE
|
||||
|
||||
//The following hash table code was inspired by the xpm
|
||||
//loading code of xv, one of the best image viewers of X11
|
||||
|
||||
//For xpm files with more than one character/pixel, it is
|
||||
//impractical to use a simple lookup table for the
|
||||
//character-to-color mapping (because the table requires
|
||||
//2^(chars/pixel) entries, this is quite big).
|
||||
//Because of that, a hash table is used for the mapping.
|
||||
//The hash table has 257 entries, and collisions are
|
||||
//resolved by chaining.
|
||||
|
||||
//257 is the smallest prime > 256
|
||||
#define XPM_HASH_LEN 257
|
||||
|
||||
typedef struct XPMHASHENTRY
|
||||
{
|
||||
ILubyte ColourName[XPM_MAX_CHAR_PER_PIXEL];
|
||||
XpmPixel ColourValue;
|
||||
struct XPMHASHENTRY *Next;
|
||||
} XPMHASHENTRY;
|
||||
|
||||
|
||||
static ILuint XpmHash(const ILubyte* name, int len)
|
||||
{
|
||||
ILint i, sum;
|
||||
for (sum = i = 0; i < len; ++i)
|
||||
sum += name[i];
|
||||
return sum % XPM_HASH_LEN;
|
||||
}
|
||||
|
||||
|
||||
XPMHASHENTRY** XpmCreateHashTable()
|
||||
{
|
||||
XPMHASHENTRY** Table =
|
||||
(XPMHASHENTRY**)ialloc(XPM_HASH_LEN*sizeof(XPMHASHENTRY*));
|
||||
if (Table != NULL)
|
||||
memset(Table, 0, XPM_HASH_LEN*sizeof(XPMHASHENTRY*));
|
||||
return Table;
|
||||
}
|
||||
|
||||
|
||||
void XpmDestroyHashTable(XPMHASHENTRY **Table)
|
||||
{
|
||||
ILint i;
|
||||
XPMHASHENTRY* Entry;
|
||||
|
||||
for (i = 0; i < XPM_HASH_LEN; ++i) {
|
||||
while (Table[i] != NULL) {
|
||||
Entry = Table[i]->Next;
|
||||
ifree(Table[i]);
|
||||
Table[i] = Entry;
|
||||
}
|
||||
}
|
||||
|
||||
ifree(Table);
|
||||
}
|
||||
|
||||
|
||||
void XpmInsertEntry(XPMHASHENTRY **Table, const ILubyte* Name, int Len, XpmPixel Colour)
|
||||
{
|
||||
XPMHASHENTRY* NewEntry;
|
||||
ILuint Index;
|
||||
Index = XpmHash(Name, Len);
|
||||
|
||||
NewEntry = (XPMHASHENTRY*)ialloc(sizeof(XPMHASHENTRY));
|
||||
if (NewEntry != NULL) {
|
||||
NewEntry->Next = Table[Index];
|
||||
memcpy(NewEntry->ColourName, Name, Len);
|
||||
memcpy(NewEntry->ColourValue, Colour, sizeof(Colour));
|
||||
Table[Index] = NewEntry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void XpmGetEntry(XPMHASHENTRY **Table, const ILubyte* Name, int Len, XpmPixel Colour)
|
||||
{
|
||||
XPMHASHENTRY* Entry;
|
||||
ILuint Index;
|
||||
|
||||
Index = XpmHash(Name, Len);
|
||||
Entry = Table[Index];
|
||||
while (Entry != NULL && strncmp((char*)(Entry->ColourName), (char*)Name, Len) != 0)
|
||||
Entry = Entry->Next;
|
||||
|
||||
if (Entry != NULL)
|
||||
memcpy(Colour, Entry->ColourValue, sizeof(Colour));
|
||||
}
|
||||
|
||||
#endif //XPM_DONT_USE_HASHTABLE
|
||||
|
||||
|
||||
ILint XpmGetsInternal(ILubyte *Buffer, ILint MaxLen)
|
||||
{
|
||||
ILint i = 0, Current;
|
||||
|
||||
if (ieof())
|
||||
return IL_EOF;
|
||||
|
||||
while ((Current = igetc()) != IL_EOF && i < MaxLen - 1) {
|
||||
if (Current == IL_EOF)
|
||||
return 0;
|
||||
if (Current == '\n') //unix line ending
|
||||
break;
|
||||
|
||||
if (Current == '\r') { //dos/mac line ending
|
||||
Current = igetc();
|
||||
if (Current == '\n') //dos line ending
|
||||
break;
|
||||
|
||||
if (Current == IL_EOF)
|
||||
break;
|
||||
|
||||
Buffer[i++] = (ILubyte)Current;
|
||||
continue;
|
||||
}
|
||||
Buffer[i++] = (ILubyte)Current;
|
||||
}
|
||||
|
||||
Buffer[i++] = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
ILint XpmGets(ILubyte *Buffer, ILint MaxLen)
|
||||
{
|
||||
ILint Size, i, j;
|
||||
ILboolean NotComment = IL_FALSE, InsideComment = IL_FALSE;
|
||||
|
||||
do {
|
||||
Size = XpmGetsInternal(Buffer, MaxLen);
|
||||
if (Size == IL_EOF)
|
||||
return IL_EOF;
|
||||
|
||||
//skip leading whitespace (sometimes there's whitespace
|
||||
//before a comment or before the pixel data)
|
||||
|
||||
for(i = 0; i < Size && isspace(Buffer[i]); ++i) ;
|
||||
Size = Size - i;
|
||||
for(j = 0; j < Size; ++j)
|
||||
Buffer[j] = Buffer[j + i];
|
||||
|
||||
if (Size == 0)
|
||||
continue;
|
||||
|
||||
if (Buffer[0] == '/' && Buffer[1] == '*') {
|
||||
for (i = 2; i < Size; i++) {
|
||||
if (Buffer[i] == '*' && Buffer[i+1] == '/') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= Size)
|
||||
InsideComment = IL_TRUE;
|
||||
}
|
||||
else if (InsideComment) {
|
||||
for (i = 0; i < Size; i++) {
|
||||
if (Buffer[i] == '*' && Buffer[i+1] == '/') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < Size)
|
||||
InsideComment = IL_FALSE;
|
||||
}
|
||||
else {
|
||||
NotComment = IL_TRUE;
|
||||
}
|
||||
} while (!NotComment);
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
ILint XpmGetInt(ILubyte *Buffer, ILint Size, ILint *Position)
|
||||
{
|
||||
char Buff[1024];
|
||||
ILint i, j;
|
||||
ILboolean IsInNum = IL_FALSE;
|
||||
|
||||
for (i = *Position, j = 0; i < Size; i++) {
|
||||
if (isdigit(Buffer[i])) {
|
||||
IsInNum = IL_TRUE;
|
||||
Buff[j++] = Buffer[i];
|
||||
}
|
||||
else {
|
||||
if (IsInNum) {
|
||||
Buff[j] = 0;
|
||||
*Position = i;
|
||||
return atoi(Buff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
ILboolean XpmPredefCol(char *Buff, XpmPixel *Colour)
|
||||
{
|
||||
ILint len;
|
||||
ILint val = 128;
|
||||
|
||||
if (!stricmp(Buff, "none")) {
|
||||
(*Colour)[0] = 0;
|
||||
(*Colour)[1] = 0;
|
||||
(*Colour)[2] = 0;
|
||||
(*Colour)[3] = 0;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
(*Colour)[3] = 255;
|
||||
|
||||
if (!stricmp(Buff, "black")) {
|
||||
(*Colour)[0] = 0;
|
||||
(*Colour)[1] = 0;
|
||||
(*Colour)[2] = 0;
|
||||
return IL_TRUE;
|
||||
}
|
||||
if (!stricmp(Buff, "white")) {
|
||||
(*Colour)[0] = 255;
|
||||
(*Colour)[1] = 255;
|
||||
(*Colour)[2] = 255;
|
||||
return IL_TRUE;
|
||||
}
|
||||
if (!stricmp(Buff, "red")) {
|
||||
(*Colour)[0] = 255;
|
||||
(*Colour)[1] = 0;
|
||||
(*Colour)[2] = 0;
|
||||
return IL_TRUE;
|
||||
}
|
||||
if (!stricmp(Buff, "green")) {
|
||||
(*Colour)[0] = 0;
|
||||
(*Colour)[1] = 255;
|
||||
(*Colour)[2] = 0;
|
||||
return IL_TRUE;
|
||||
}
|
||||
if (!stricmp(Buff, "blue")) {
|
||||
(*Colour)[0] = 0;
|
||||
(*Colour)[1] = 0;
|
||||
(*Colour)[2] = 255;
|
||||
return IL_TRUE;
|
||||
}
|
||||
if (!stricmp(Buff, "yellow")) {
|
||||
(*Colour)[0] = 255;
|
||||
(*Colour)[1] = 255;
|
||||
(*Colour)[2] = 0;
|
||||
return IL_TRUE;
|
||||
}
|
||||
if (!stricmp(Buff, "cyan")) {
|
||||
(*Colour)[0] = 0;
|
||||
(*Colour)[1] = 255;
|
||||
(*Colour)[2] = 255;
|
||||
return IL_TRUE;
|
||||
}
|
||||
if (!stricmp(Buff, "gray")) {
|
||||
(*Colour)[0] = 128;
|
||||
(*Colour)[1] = 128;
|
||||
(*Colour)[2] = 128;
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
//check for grayXXX codes (added 20040218)
|
||||
len = ilCharStrLen(Buff);
|
||||
if (len >= 4) {
|
||||
if (Buff[0] == 'g' || Buff[0] == 'G'
|
||||
|| Buff[1] == 'r' || Buff[1] == 'R'
|
||||
|| Buff[2] == 'a' || Buff[2] == 'A'
|
||||
|| Buff[3] == 'y' || Buff[3] == 'Y') {
|
||||
if (isdigit(Buff[4])) { // isdigit returns false on '\0'
|
||||
val = Buff[4] - '0';
|
||||
if (isdigit(Buff[5])) {
|
||||
val = val*10 + Buff[5] - '0';
|
||||
if (isdigit(Buff[6]))
|
||||
val = val*10 + Buff[6] - '0';
|
||||
}
|
||||
val = (255*val)/100;
|
||||
}
|
||||
(*Colour)[0] = (ILubyte)val;
|
||||
(*Colour)[1] = (ILubyte)val;
|
||||
(*Colour)[2] = (ILubyte)val;
|
||||
return IL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Unknown colour string, so use black
|
||||
// (changed 20040218)
|
||||
(*Colour)[0] = 0;
|
||||
(*Colour)[1] = 0;
|
||||
(*Colour)[2] = 0;
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
#ifndef XPM_DONT_USE_HASHTABLE
|
||||
ILboolean XpmGetColour(ILubyte *Buffer, ILint Size, int Len, XPMHASHENTRY **Table)
|
||||
#else
|
||||
ILboolean XpmGetColour(ILubyte *Buffer, ILint Size, int Len, XpmPixel* Colours)
|
||||
#endif
|
||||
{
|
||||
ILint i = 0, j, strLen = 0;
|
||||
ILubyte ColBuff[3];
|
||||
char Buff[1024];
|
||||
|
||||
XpmPixel Colour;
|
||||
ILubyte Name[XPM_MAX_CHAR_PER_PIXEL];
|
||||
|
||||
for ( ; i < Size; i++) {
|
||||
if (Buffer[i] == '\"')
|
||||
break;
|
||||
}
|
||||
i++; // Skip the quotes.
|
||||
|
||||
if (i >= Size)
|
||||
return IL_FALSE;
|
||||
|
||||
// Get the characters.
|
||||
for (j = 0; j < Len; ++j) {
|
||||
Name[j] = Buffer[i++];
|
||||
}
|
||||
|
||||
// Skip to the colour definition.
|
||||
for ( ; i < Size; i++) {
|
||||
if (Buffer[i] == 'c')
|
||||
break;
|
||||
}
|
||||
i++; // Skip the 'c'.
|
||||
|
||||
if (i >= Size || Buffer[i] != ' ') { // no 'c' found...assume black
|
||||
#ifndef XPM_DONT_USE_HASHTABLE
|
||||
memset(Colour, 0, sizeof(Colour));
|
||||
Colour[3] = 255;
|
||||
XpmInsertEntry(Table, Name, Len, Colour);
|
||||
#else
|
||||
memset(Colours[Name[0]], 0, sizeof(Colour));
|
||||
Colours[Name[0]][3] = 255;
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
for ( ; i < Size; i++) {
|
||||
if (Buffer[i] != ' ')
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= Size)
|
||||
return IL_FALSE;
|
||||
|
||||
if (Buffer[i] == '#') {
|
||||
// colour string may 4 digits/color or 1 digit/color
|
||||
// (added 20040218) TODO: is isxdigit() ANSI???
|
||||
++i;
|
||||
while (i + strLen < Size && isxdigit(Buffer[i + strLen]))
|
||||
++strLen;
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
if (strLen >= 10) { // 4 digits
|
||||
ColBuff[0] = Buffer[i + j*4];
|
||||
ColBuff[1] = Buffer[i + j*4 + 1];
|
||||
}
|
||||
else if (strLen >= 8) { // 3 digits
|
||||
ColBuff[0] = Buffer[i + j*3];
|
||||
ColBuff[1] = Buffer[i + j*3 + 1];
|
||||
}
|
||||
else if (strLen >= 6) { // 2 digits
|
||||
ColBuff[0] = Buffer[i + j*2];
|
||||
ColBuff[1] = Buffer[i + j*2 + 1];
|
||||
}
|
||||
else if(j < strLen) { // 1 digit, strLen >= 1
|
||||
ColBuff[0] = Buffer[i + j];
|
||||
ColBuff[1] = 0;
|
||||
}
|
||||
|
||||
ColBuff[2] = 0; // add terminating '\0' char
|
||||
Colour[j] = (ILubyte)strtol((char*)ColBuff, NULL, 16);
|
||||
}
|
||||
Colour[3] = 255; // Full alpha.
|
||||
}
|
||||
else {
|
||||
for (j = 0; i < Size; i++) {
|
||||
if (!isalnum(Buffer[i]))
|
||||
break;
|
||||
Buff[j++] = Buffer[i];
|
||||
}
|
||||
Buff[j] = 0;
|
||||
|
||||
if (i >= Size)
|
||||
return IL_FALSE;
|
||||
|
||||
if (!XpmPredefCol(Buff, &Colour))
|
||||
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
#ifndef XPM_DONT_USE_HASHTABLE
|
||||
XpmInsertEntry(Table, Name, Len, Colour);
|
||||
#else
|
||||
memcpy(Colours[Name[0]], Colour, sizeof(Colour));
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
ILboolean iLoadXpmInternal()
|
||||
{
|
||||
#define BUFFER_SIZE 2000
|
||||
ILubyte Buffer[BUFFER_SIZE], *Data;
|
||||
ILint Size, Pos, Width, Height, NumColours, i, x, y;
|
||||
|
||||
ILint CharsPerPixel;
|
||||
|
||||
#ifndef XPM_DONT_USE_HASHTABLE
|
||||
XPMHASHENTRY **HashTable;
|
||||
#else
|
||||
XpmPixel *Colours;
|
||||
ILint Offset;
|
||||
#endif
|
||||
|
||||
Size = XpmGetsInternal(Buffer, BUFFER_SIZE);
|
||||
if (strncmp("/* XPM */", (char*)Buffer, strlen("/* XPM */"))) {
|
||||
ilSetError(IL_INVALID_FILE_HEADER);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Size = XpmGets(Buffer, BUFFER_SIZE);
|
||||
// @TODO: Actually check the variable name here.
|
||||
|
||||
Size = XpmGets(Buffer, BUFFER_SIZE);
|
||||
Pos = 0;
|
||||
Width = XpmGetInt(Buffer, Size, &Pos);
|
||||
Height = XpmGetInt(Buffer, Size, &Pos);
|
||||
NumColours = XpmGetInt(Buffer, Size, &Pos);
|
||||
|
||||
CharsPerPixel = XpmGetInt(Buffer, Size, &Pos);
|
||||
|
||||
#ifdef XPM_DONT_USE_HASHTABLE
|
||||
if (CharsPerPixel != 1) {
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (CharsPerPixel > XPM_MAX_CHAR_PER_PIXEL
|
||||
|| Width*CharsPerPixel > BUFFER_SIZE) {
|
||||
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
#ifndef XPM_DONT_USE_HASHTABLE
|
||||
HashTable = XpmCreateHashTable();
|
||||
if (HashTable == NULL)
|
||||
return IL_FALSE;
|
||||
#else
|
||||
Colours = ialloc(256 * sizeof(XpmPixel));
|
||||
if (Colours == NULL)
|
||||
return IL_FALSE;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < NumColours; i++) {
|
||||
Size = XpmGets(Buffer, BUFFER_SIZE);
|
||||
#ifndef XPM_DONT_USE_HASHTABLE
|
||||
if (!XpmGetColour(Buffer, Size, CharsPerPixel, HashTable)) {
|
||||
XpmDestroyHashTable(HashTable);
|
||||
#else
|
||||
if (!XpmGetColour(Buffer, Size, CharsPerPixel, Colours)) {
|
||||
ifree(Colours);
|
||||
#endif
|
||||
return IL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ilTexImage(Width, Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
|
||||
#ifndef XPM_DONT_USE_HASHTABLE
|
||||
XpmDestroyHashTable(HashTable);
|
||||
#else
|
||||
ifree(Colours);
|
||||
#endif
|
||||
return IL_FALSE;
|
||||
}
|
||||
|
||||
Data = iCurImage->Data;
|
||||
|
||||
for (y = 0; y < Height; y++) {
|
||||
Size = XpmGets(Buffer, BUFFER_SIZE);
|
||||
for (x = 0; x < Width; x++) {
|
||||
#ifndef XPM_DONT_USE_HASHTABLE
|
||||
XpmGetEntry(HashTable, &Buffer[1 + x*CharsPerPixel], CharsPerPixel, &Data[(x << 2)]);
|
||||
#else
|
||||
Offset = (x << 2);
|
||||
Data[Offset + 0] = Colours[Buffer[x + 1]][0];
|
||||
Data[Offset + 1] = Colours[Buffer[x + 1]][1];
|
||||
Data[Offset + 2] = Colours[Buffer[x + 1]][2];
|
||||
Data[Offset + 3] = Colours[Buffer[x + 1]][3];
|
||||
#endif
|
||||
}
|
||||
|
||||
Data += iCurImage->Bps;
|
||||
}
|
||||
|
||||
//added 20040218
|
||||
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
||||
|
||||
|
||||
#ifndef XPM_DONT_USE_HASHTABLE
|
||||
XpmDestroyHashTable(HashTable);
|
||||
#else
|
||||
ifree(Colours);
|
||||
#endif
|
||||
return IL_TRUE;
|
||||
|
||||
#undef BUFFER_SIZE
|
||||
}
|
||||
|
||||
#endif//IL_NO_XPM
|
||||
|
||||
Reference in New Issue
Block a user