2492 lines
52 KiB
C++
2492 lines
52 KiB
C++
![]() |
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "d3_image.hpp"
|
||
|
#include "platform.h"
|
||
|
|
||
|
// define = 1 if you dont have pre-quantized images to load into palettized D3D texture surfaces
|
||
|
#define QUANTISE_ON_LOAD 0
|
||
|
|
||
|
#if debug
|
||
|
#define DEBUG_TRANSPARENCY 1
|
||
|
#else
|
||
|
#define DEBUG_TRANSPARENCY 0
|
||
|
#endif
|
||
|
|
||
|
// image loader stuff
|
||
|
|
||
|
#if OUTPUT_LOG
|
||
|
#include "debuglog.hpp"
|
||
|
LogFile CL_LogFile("DB_IMLD.LOG");
|
||
|
#endif
|
||
|
|
||
|
#if TIME_LOADS
|
||
|
unsigned int OpenTime;
|
||
|
unsigned int CloseTime;
|
||
|
unsigned int ReadTime;
|
||
|
#endif
|
||
|
|
||
|
static inline unsigned long read_le_dword(D3I_FILE * f)
|
||
|
{
|
||
|
unsigned char d1,d2,d3,d4;
|
||
|
d3i_fread(&d1,1,1,f);
|
||
|
d3i_fread(&d2,1,1,f);
|
||
|
d3i_fread(&d3,1,1,f);
|
||
|
d3i_fread(&d4,1,1,f);
|
||
|
|
||
|
return (unsigned long)d1 | (unsigned long)d2<<8 | (unsigned long)d3<<16 | (unsigned long)d4<<24;
|
||
|
}
|
||
|
|
||
|
static inline unsigned short read_le_word(D3I_FILE * f)
|
||
|
{
|
||
|
unsigned char d1,d2;
|
||
|
d3i_fread(&d1,1,1,f);
|
||
|
d3i_fread(&d2,1,1,f);
|
||
|
|
||
|
return (unsigned short)d1 | (unsigned short)((unsigned short)d2<<8);
|
||
|
}
|
||
|
|
||
|
// some default globals
|
||
|
CL_ImageMode CL_Image::imode = CLM_GLOBALPALETTE;
|
||
|
CL_ImageMode CL_Image::imode_d3d = CLM_ATTACHEDPALETTE;
|
||
|
CL_ImageMode CL_Image::imode_ddraw = CLM_GLOBALPALETTE;
|
||
|
LPDDSURFACEDESC CL_Image::format = 0;
|
||
|
unsigned int CL_Image::bitsperpixel;
|
||
|
unsigned int CL_Image::bitsperpixel_d3d;
|
||
|
unsigned int CL_Image::bitsperpixel_ddraw;
|
||
|
CL_LoadMode CL_Image::lmode = CLL_DDSURFACE;
|
||
|
|
||
|
CL_DX_Format CL_Pixel_32::f;
|
||
|
CL_DX_Format CL_Pixel_32::f_d3d;
|
||
|
CL_DX_Format CL_Pixel_32::f_ddraw;
|
||
|
CL_DX_Format CL_Pixel_16::f;
|
||
|
CL_DX_Format CL_Pixel_16::f_d3d;
|
||
|
CL_DX_Format CL_Pixel_16::f_ddraw;
|
||
|
|
||
|
|
||
|
void CL_Image::DeleteNotMips(void)
|
||
|
{
|
||
|
if (im24)
|
||
|
{
|
||
|
delete[] *im24;
|
||
|
delete[] im24;
|
||
|
im24 = 0;
|
||
|
}
|
||
|
if (im16)
|
||
|
{
|
||
|
delete[] *im16;
|
||
|
delete[] im16;
|
||
|
im16 = 0;
|
||
|
}
|
||
|
if (im8)
|
||
|
{
|
||
|
delete[] *im8;
|
||
|
delete[] im8;
|
||
|
im8 = 0;
|
||
|
}
|
||
|
if (palette)
|
||
|
{
|
||
|
delete[] palette;
|
||
|
palette = 0;
|
||
|
palette_size = 0;
|
||
|
}
|
||
|
flags.loaded = 0;
|
||
|
flags.raw16bit = 0;
|
||
|
}
|
||
|
|
||
|
void CL_Image::Delete(void)
|
||
|
{
|
||
|
DeleteNotMips();
|
||
|
while (mipmaps.size())
|
||
|
{
|
||
|
delete mipmaps.last_entry();
|
||
|
mipmaps.delete_last_entry();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CL_Image::Copy(CL_Image const & i2)
|
||
|
{
|
||
|
if (i2.im24)
|
||
|
{
|
||
|
im24 = new CL_Pixel_24 * [height];
|
||
|
*im24 = new CL_Pixel_24 [size];
|
||
|
|
||
|
CL_Pixel_24 const * sptr = *i2.im24;
|
||
|
CL_Pixel_24 * dptr = *im24;
|
||
|
|
||
|
for (int i=size; i; --i)
|
||
|
{
|
||
|
*dptr++ = *sptr++;
|
||
|
}
|
||
|
|
||
|
CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24;
|
||
|
CL_Pixel_24 const * aptr = *im24;
|
||
|
for (i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i2.im16)
|
||
|
{
|
||
|
im16 = new CL_Pixel_16 * [height];
|
||
|
*im16 = new CL_Pixel_16 [size];
|
||
|
|
||
|
CL_Pixel_16 const * sptr = *i2.im16;
|
||
|
CL_Pixel_16 * dptr = *im16;
|
||
|
|
||
|
for (int i=size; i; --i)
|
||
|
{
|
||
|
*dptr++ = *sptr++;
|
||
|
}
|
||
|
|
||
|
CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16;
|
||
|
CL_Pixel_16 const * aptr = *im16;
|
||
|
for (i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i2.im8)
|
||
|
{
|
||
|
im8 = new unsigned char * [height];
|
||
|
*im8 = new unsigned char [size];
|
||
|
|
||
|
unsigned char const * sptr = *i2.im8;
|
||
|
unsigned char * dptr = *im8;
|
||
|
|
||
|
for (int i=size; i; --i)
|
||
|
{
|
||
|
*dptr++ = *sptr++;
|
||
|
}
|
||
|
|
||
|
unsigned char const * * dptrptr = (unsigned char const * *) im8;
|
||
|
unsigned char const * aptr = *im8;
|
||
|
for (i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i2.palette)
|
||
|
{
|
||
|
palette = new CL_Pixel_24 [palette_size];
|
||
|
|
||
|
CL_Pixel_24 const * sptr = i2.palette;
|
||
|
CL_Pixel_24 * dptr = palette;
|
||
|
|
||
|
for (int i=palette_size; i; --i)
|
||
|
{
|
||
|
*dptr++ = *sptr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i2.name)
|
||
|
{
|
||
|
name = new char [strlen(i2.name)+1];
|
||
|
strcpy(name,i2.name);
|
||
|
}
|
||
|
|
||
|
if (i2.fname)
|
||
|
{
|
||
|
fname = new char [strlen(i2.fname)+1];
|
||
|
strcpy(fname,i2.fname);
|
||
|
}
|
||
|
|
||
|
for (CLIF<CL_Image *> i_mip(&i2.mipmaps); !i_mip.done(); i_mip.next())
|
||
|
{
|
||
|
mipmaps.add_entry_end(new CL_Image(*i_mip()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Image::~CL_Image()
|
||
|
{
|
||
|
Delete();
|
||
|
if (fname) delete[] fname;
|
||
|
if (name) delete[] name;
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Image::CL_Image(CL_Image const & i2)
|
||
|
: width(i2.width)
|
||
|
, height(i2.height)
|
||
|
, size(i2.size)
|
||
|
, im24(0)
|
||
|
, im16(0)
|
||
|
, im8(0)
|
||
|
, palette(0)
|
||
|
, palette_size(i2.palette_size)
|
||
|
, fname(0)
|
||
|
, name(0)
|
||
|
, flags(i2.flags)
|
||
|
{
|
||
|
Copy(i2);
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Image & CL_Image::operator = (CL_Image const & i2)
|
||
|
{
|
||
|
if (&i2 != this)
|
||
|
{
|
||
|
Delete();
|
||
|
if (fname) delete[] fname;
|
||
|
if (name) delete[] name;
|
||
|
|
||
|
width = i2.width;
|
||
|
height = i2.height;
|
||
|
size = i2.size;
|
||
|
palette_size = i2.palette_size;
|
||
|
|
||
|
fname = 0;
|
||
|
name = 0;
|
||
|
|
||
|
flags = i2.flags;
|
||
|
|
||
|
Copy(i2);
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Error CL_Image::Make(int const _width, int const _height)
|
||
|
{
|
||
|
Delete();
|
||
|
|
||
|
width = _width;
|
||
|
height = _height;
|
||
|
palette_size = 0;
|
||
|
size = width*height;
|
||
|
|
||
|
switch (imode)
|
||
|
{
|
||
|
case CLM_ATTACHEDPALETTE:
|
||
|
{
|
||
|
palette_size = 256;
|
||
|
palette = new CL_Pixel_24 [palette_size];
|
||
|
}
|
||
|
case CLM_GLOBALPALETTE:
|
||
|
case CLM_TLTPALETTE:
|
||
|
{
|
||
|
im8 = new unsigned char * [height];
|
||
|
*im8 = new unsigned char [size];
|
||
|
|
||
|
unsigned char const * * dptrptr = (unsigned char const * *) im8;
|
||
|
unsigned char * dptr = *im8;
|
||
|
for (int i=height; i; --i, dptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = dptr;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case CLM_24BIT:
|
||
|
{
|
||
|
im24 = new CL_Pixel_24 * [height];
|
||
|
*im24 = new CL_Pixel_24 [size];
|
||
|
|
||
|
CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24;
|
||
|
CL_Pixel_24 const * aptr = *im24;
|
||
|
for (int i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case CLM_16BIT:
|
||
|
{
|
||
|
im16 = new CL_Pixel_16 * [height];
|
||
|
*im16 = new CL_Pixel_16 [size];
|
||
|
|
||
|
CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16;
|
||
|
CL_Pixel_16 const * aptr = *im16;
|
||
|
for (int i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case CLM_32BIT:
|
||
|
{
|
||
|
im32 = new CL_Pixel_32 * [height];
|
||
|
*im32 = new CL_Pixel_32 [size];
|
||
|
|
||
|
CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32;
|
||
|
CL_Pixel_32 const * aptr = *im32;
|
||
|
for (int i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
return CLE_INVALIDDXMODE;
|
||
|
}
|
||
|
|
||
|
flags.loaded = 1;
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Error CL_Image::MakeRandom(int const _width, int const _height, int const seed)
|
||
|
{
|
||
|
Delete();
|
||
|
|
||
|
if (-1!=seed) srand((unsigned int)seed);
|
||
|
|
||
|
width = _width;
|
||
|
height = _height;
|
||
|
size = width*height;
|
||
|
palette_size = 0;
|
||
|
|
||
|
switch (imode)
|
||
|
{
|
||
|
case CLM_ATTACHEDPALETTE:
|
||
|
{
|
||
|
palette_size = 256;
|
||
|
palette = new CL_Pixel_24 [palette_size];
|
||
|
CL_Pixel_24 * palP = palette;
|
||
|
for (int i=palette_size; i; --i, ++palP)
|
||
|
{
|
||
|
*palP = CL_Pixel_24(rand()&255,rand()&255,rand()&255);
|
||
|
}
|
||
|
}
|
||
|
case CLM_GLOBALPALETTE:
|
||
|
case CLM_TLTPALETTE:
|
||
|
{
|
||
|
im8 = new unsigned char * [height];
|
||
|
*im8 = new unsigned char [size];
|
||
|
|
||
|
unsigned char const * * dptrptr = (unsigned char const * *) im8;
|
||
|
unsigned char * dptr = *im8;
|
||
|
for (int i=height; i; --i)
|
||
|
{
|
||
|
*dptrptr++ = dptr;
|
||
|
for (int j=width; j; --j, ++dptr)
|
||
|
*dptr = (unsigned char)(rand()&(palette_size-1));
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case CLM_24BIT:
|
||
|
{
|
||
|
im24 = new CL_Pixel_24 * [height];
|
||
|
*im24 = new CL_Pixel_24 [size];
|
||
|
|
||
|
CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24;
|
||
|
CL_Pixel_24 * aptr = *im24;
|
||
|
for (int i=height; i; --i)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
for (int j=width; j; --j, ++aptr)
|
||
|
*aptr = CL_Pixel_24(rand()&255,rand()&255,rand()&255);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case CLM_16BIT:
|
||
|
{
|
||
|
im16 = new CL_Pixel_16 * [height];
|
||
|
*im16 = new CL_Pixel_16 [size];
|
||
|
|
||
|
CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16;
|
||
|
CL_Pixel_16 * aptr = *im16;
|
||
|
for (int i=height; i; --i)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
for (int j=width; j; --j, ++aptr)
|
||
|
*aptr = CL_Pixel_24(rand()&255,rand()&255,rand()&255);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case CLM_32BIT:
|
||
|
{
|
||
|
im32 = new CL_Pixel_32 * [height];
|
||
|
*im32 = new CL_Pixel_32 [size];
|
||
|
|
||
|
CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32;
|
||
|
CL_Pixel_32 * aptr = *im32;
|
||
|
for (int i=height; i; --i)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
for (int j=width; j; --j, ++aptr)
|
||
|
*aptr = CL_Pixel_24(rand()&255,rand()&255,rand()&255);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
return CLE_INVALIDDXMODE;
|
||
|
}
|
||
|
|
||
|
flags.loaded = 1;
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Error CL_Image::Load_BMP(D3I_FILE * f)
|
||
|
{
|
||
|
if (!f) return CLE_OPENERROR;
|
||
|
|
||
|
DeleteNotMips();
|
||
|
|
||
|
switch (imode)
|
||
|
{
|
||
|
case CLM_ATTACHEDPALETTE:
|
||
|
case CLM_24BIT:
|
||
|
case CLM_16BIT:
|
||
|
case CLM_32BIT:
|
||
|
break;
|
||
|
default:
|
||
|
return CLE_INVALIDDXMODE;
|
||
|
}
|
||
|
|
||
|
d3i_fseek(f,0,SEEK_SET);
|
||
|
unsigned short magic;
|
||
|
d3i_fread(&magic,2,1,f);
|
||
|
if (magic != *(unsigned short const *)"BM") return CLE_LOADERROR;
|
||
|
|
||
|
size_t filesize = read_le_dword(f);
|
||
|
d3i_fseek(f,4,SEEK_CUR);
|
||
|
size_t offset = read_le_dword(f);
|
||
|
size_t headsize = read_le_dword(f);
|
||
|
|
||
|
unsigned short bitdepth;
|
||
|
|
||
|
if (12 == headsize) // OS/2 1.x
|
||
|
{
|
||
|
width = read_le_word(f);
|
||
|
height = read_le_word(f);
|
||
|
size = width * height;
|
||
|
if (!width || !height) return CLE_LOADERROR;
|
||
|
unsigned short planes = read_le_word(f);
|
||
|
if (1 != planes) return CLE_LOADERROR;
|
||
|
bitdepth = read_le_word(f);
|
||
|
|
||
|
if (bitdepth != 24)
|
||
|
{
|
||
|
palette_size = 1<<bitdepth;
|
||
|
palette = new CL_Pixel_24 [palette_size];
|
||
|
CL_Pixel_24 * rptr = palette;
|
||
|
for (int i=palette_size; i; --i)
|
||
|
{
|
||
|
rptr++->Read(f,CLF_BGR);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (40 == headsize || 64 == headsize) // Windows 3.x || OS/2 2.x
|
||
|
{
|
||
|
width = read_le_dword(f);
|
||
|
height = read_le_dword(f);
|
||
|
unsigned short planes = read_le_word(f);
|
||
|
if (1 != planes) return CLE_LOADERROR;
|
||
|
bitdepth = read_le_word(f);
|
||
|
|
||
|
if (read_le_dword(f)) return CLE_LOADERROR; // compressed bmps not supported
|
||
|
|
||
|
size = read_le_dword(f);
|
||
|
|
||
|
d3i_fseek(f,8,SEEK_CUR);
|
||
|
palette_size = read_le_dword(f);
|
||
|
if (!palette_size && bitdepth != 24) palette_size = 1<<bitdepth;
|
||
|
|
||
|
if (palette_size)
|
||
|
{
|
||
|
d3i_fseek(f,headsize+14,SEEK_SET);
|
||
|
palette = new CL_Pixel_24 [palette_size];
|
||
|
CL_Pixel_24 * rptr = palette;
|
||
|
for (int i=palette_size; i; --i)
|
||
|
{
|
||
|
rptr++->Read(f,CLF_BGRX);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else return CLE_LOADERROR;
|
||
|
|
||
|
d3i_fseek(f,offset,SEEK_SET);
|
||
|
|
||
|
if (palette_size)
|
||
|
{
|
||
|
if (bitdepth < 4)
|
||
|
{
|
||
|
delete[] palette;
|
||
|
palette_size = 0;
|
||
|
return CLE_LOADERROR;
|
||
|
}
|
||
|
|
||
|
im8 = new unsigned char * [height];
|
||
|
*im8 = new unsigned char [size];
|
||
|
|
||
|
unsigned char const * * dptrptr = (unsigned char const * *) im8;
|
||
|
unsigned char * dptr = *im8;
|
||
|
for (int i=height; i; --i, dptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = dptr;
|
||
|
}
|
||
|
|
||
|
#if DEBUG_TRANSPARENCY
|
||
|
int num_tps=0;
|
||
|
#endif
|
||
|
for (i=height-1; i>=0; --i)
|
||
|
{
|
||
|
dptr = im8[i];
|
||
|
|
||
|
if (4==bitdepth)
|
||
|
{
|
||
|
for (int i=width>>1; i; --i)
|
||
|
{
|
||
|
unsigned char byte;
|
||
|
d3i_fread(&byte,1,1,f);
|
||
|
#if DEBUG_TRANSPARENCY
|
||
|
*dptr = (unsigned char)(byte >> 4 & 0xf);
|
||
|
if (!*dptr) num_tps++;
|
||
|
*++dptr = (unsigned char)(byte & 0xf);
|
||
|
if (!*dptr) num_tps++;
|
||
|
++dptr;
|
||
|
#else
|
||
|
*dptr++ = (unsigned char)(byte >> 4 & 0xf);
|
||
|
*dptr++ = (unsigned char)(byte & 0xf);
|
||
|
#endif
|
||
|
}
|
||
|
if (width & 1)
|
||
|
{
|
||
|
d3i_fread(dptr,1,1,f);
|
||
|
*dptr &= 0xf;
|
||
|
#if DEBUG_TRANSPARENCY
|
||
|
if (!*dptr) num_tps++;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
d3i_fseek(f,(~(width-1) & 7)>>1,SEEK_CUR);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (int i=width; i; --i)
|
||
|
{
|
||
|
#if DEBUG_TRANSPARENCY
|
||
|
d3i_fread(dptr,1,1,f);
|
||
|
if (!*dptr) num_tps++;
|
||
|
dptr++;
|
||
|
#else
|
||
|
d3i_fread(dptr++,1,1,f);
|
||
|
#endif
|
||
|
}
|
||
|
d3i_fseek(f,~(width-1) & 3,SEEK_CUR);
|
||
|
}
|
||
|
}
|
||
|
#if DEBUG_TRANSPARENCY
|
||
|
if (num_tps) CL_LogFile.lprintf("-- %d TRANSPARENT PIXELS FOUND\n",num_tps);
|
||
|
#endif
|
||
|
}
|
||
|
else if (CLM_16BIT == imode)
|
||
|
{
|
||
|
im16 = new CL_Pixel_16 * [height];
|
||
|
*im16 = new CL_Pixel_16 [size];
|
||
|
|
||
|
CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16;
|
||
|
CL_Pixel_16 const * aptr = *im16;
|
||
|
for (int i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
|
||
|
for (i=height-1; i>=0; --i)
|
||
|
{
|
||
|
CL_Pixel_16 * dptr = im16[i];
|
||
|
|
||
|
for (int i=width; i; --i)
|
||
|
{
|
||
|
dptr++->Read(f,CLF_BGR);
|
||
|
}
|
||
|
d3i_fseek(f,~(width*3-1) & 3,SEEK_CUR);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if (CLM_32BIT == imode)
|
||
|
{
|
||
|
im32 = new CL_Pixel_32 * [height];
|
||
|
*im32 = new CL_Pixel_32 [size];
|
||
|
|
||
|
CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32;
|
||
|
CL_Pixel_32 const * aptr = *im32;
|
||
|
for (int i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
|
||
|
for (i=height-1; i>=0; --i)
|
||
|
{
|
||
|
CL_Pixel_32 * dptr = im32[i];
|
||
|
|
||
|
for (int i=width; i; --i)
|
||
|
{
|
||
|
dptr++->Read(f,CLF_BGR);
|
||
|
}
|
||
|
d3i_fseek(f,~(width*3-1) & 3,SEEK_CUR);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if (CLM_24BIT == imode)
|
||
|
{
|
||
|
im24 = new CL_Pixel_24 * [height];
|
||
|
*im24 = new CL_Pixel_24 [size];
|
||
|
|
||
|
CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24;
|
||
|
CL_Pixel_24 const * aptr = *im24;
|
||
|
for (int i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
|
||
|
for (i=height-1; i>=0; --i)
|
||
|
{
|
||
|
CL_Pixel_24 * dptr = im24[i];
|
||
|
|
||
|
for (int i=width; i; --i)
|
||
|
{
|
||
|
dptr++->Read(f,CLF_BGR);
|
||
|
}
|
||
|
d3i_fseek(f,~(width*3-1) & 3,SEEK_CUR);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else return CLE_INVALIDDXMODE;
|
||
|
|
||
|
if (palette_size && CLM_ATTACHEDPALETTE != imode)
|
||
|
{
|
||
|
if (CLM_16BIT == imode)
|
||
|
{
|
||
|
im16 = new CL_Pixel_16 * [height];
|
||
|
*im16 = new CL_Pixel_16 [size];
|
||
|
|
||
|
unsigned char const * sptr = *im8;
|
||
|
CL_Pixel_16 * dptr = *im16;
|
||
|
|
||
|
for (int i=size; i; --i, ++dptr,++sptr)
|
||
|
{
|
||
|
if (*sptr && !palette[*sptr])
|
||
|
*dptr = dptr->f.dx_black;
|
||
|
else
|
||
|
*dptr = palette[*sptr];
|
||
|
}
|
||
|
|
||
|
CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16;
|
||
|
CL_Pixel_16 const * aptr = *im16;
|
||
|
for (i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
}
|
||
|
else if (CLM_32BIT == imode)
|
||
|
{
|
||
|
im32 = new CL_Pixel_32 * [height];
|
||
|
*im32 = new CL_Pixel_32 [size];
|
||
|
|
||
|
unsigned char const * sptr = *im8;
|
||
|
CL_Pixel_32 * dptr = *im32;
|
||
|
|
||
|
for (int i=size; i; --i, ++dptr,++sptr)
|
||
|
{
|
||
|
if (*sptr && !palette[*sptr])
|
||
|
*dptr = dptr->f.dx_black;
|
||
|
else
|
||
|
*dptr = palette[*sptr];
|
||
|
}
|
||
|
|
||
|
CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32;
|
||
|
CL_Pixel_32 const * aptr = *im32;
|
||
|
for (i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
im24 = new CL_Pixel_24 * [height];
|
||
|
*im24 = new CL_Pixel_24 [size];
|
||
|
|
||
|
unsigned char const * sptr = *im8;
|
||
|
CL_Pixel_24 * dptr = *im24;
|
||
|
|
||
|
for (int i=size; i; --i, ++dptr,++sptr)
|
||
|
{
|
||
|
if (*sptr && !palette[*sptr])
|
||
|
*dptr = CL_Pixel_24(0,1,0);
|
||
|
else
|
||
|
*dptr = palette[*sptr];
|
||
|
}
|
||
|
|
||
|
CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24;
|
||
|
CL_Pixel_24 const * aptr = *im24;
|
||
|
for (i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete[] palette;
|
||
|
palette = 0;
|
||
|
palette_size = 0;
|
||
|
delete[] *im8;
|
||
|
delete[] im8;
|
||
|
im8 = 0;
|
||
|
}
|
||
|
|
||
|
if (d3i_ferror(f) || d3i_feof(f))
|
||
|
{
|
||
|
DeleteNotMips();
|
||
|
return CLE_LOADERROR;
|
||
|
}
|
||
|
|
||
|
flags.loaded = 1;
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Error CL_Image::Load_PPM(D3I_FILE * f)
|
||
|
{
|
||
|
if (!f) return CLE_OPENERROR;
|
||
|
|
||
|
DeleteNotMips();
|
||
|
|
||
|
switch (imode)
|
||
|
{
|
||
|
case CLM_24BIT:
|
||
|
case CLM_16BIT:
|
||
|
case CLM_32BIT:
|
||
|
break;
|
||
|
default:
|
||
|
return CLE_INVALIDDXMODE;
|
||
|
}
|
||
|
|
||
|
d3i_fseek(f,0,SEEK_SET);
|
||
|
unsigned short magic;
|
||
|
d3i_fread(&magic,2,1,f);
|
||
|
if (magic != *(unsigned short const *)"P6") return CLE_LOADERROR;
|
||
|
|
||
|
d3i_fseek(f,1,SEEK_CUR);
|
||
|
char buf[256];
|
||
|
char * bufptr = buf;
|
||
|
unsigned int fields[5];
|
||
|
unsigned int fields_read = 0;
|
||
|
while (fields_read < 3 && bufptr)
|
||
|
{
|
||
|
do bufptr = d3i_fgets(buf, sizeof buf, f);
|
||
|
while ('#'==buf[0] && bufptr);
|
||
|
|
||
|
int num_fields_read = sscanf(buf,"%u %u %u",&fields[fields_read],&fields[fields_read+1],&fields[fields_read+2]);
|
||
|
if (EOF != num_fields_read) fields_read += num_fields_read;
|
||
|
}
|
||
|
if (fields_read < 3) return CLE_LOADERROR;
|
||
|
width = fields[0];
|
||
|
height = fields[1];
|
||
|
unsigned int maxval = fields[2];
|
||
|
if (maxval > 255) return CLE_LOADERROR;
|
||
|
|
||
|
size = width * height;
|
||
|
|
||
|
if (CLM_16BIT == imode)
|
||
|
{
|
||
|
im16 = new CL_Pixel_16 * [height];
|
||
|
*im16 = new CL_Pixel_16 [size];
|
||
|
|
||
|
CL_Pixel_16 * rptr = *im16;
|
||
|
for (int i=size; i; --i)
|
||
|
{
|
||
|
rptr++->Read(f,CLF_RGB,maxval);
|
||
|
}
|
||
|
|
||
|
CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16;
|
||
|
CL_Pixel_16 const * aptr = *im16;
|
||
|
for (i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
}
|
||
|
else if (CLM_32BIT == imode)
|
||
|
{
|
||
|
im32 = new CL_Pixel_32 * [height];
|
||
|
*im32 = new CL_Pixel_32 [size];
|
||
|
|
||
|
CL_Pixel_32 * rptr = *im32;
|
||
|
for (int i=size; i; --i)
|
||
|
{
|
||
|
rptr++->Read(f,CLF_RGB,maxval);
|
||
|
}
|
||
|
|
||
|
CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32;
|
||
|
CL_Pixel_32 const * aptr = *im32;
|
||
|
for (i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
im24 = new CL_Pixel_24 * [height];
|
||
|
*im24 = new CL_Pixel_24 [size];
|
||
|
|
||
|
CL_Pixel_24 * rptr = *im24;
|
||
|
for (int i=size; i; --i)
|
||
|
{
|
||
|
rptr++->Read(f,CLF_RGB,maxval);
|
||
|
}
|
||
|
|
||
|
CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24;
|
||
|
CL_Pixel_24 const * aptr = *im24;
|
||
|
for (i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (d3i_ferror(f) || d3i_feof(f))
|
||
|
{
|
||
|
DeleteNotMips();
|
||
|
return CLE_LOADERROR;
|
||
|
}
|
||
|
|
||
|
flags.loaded = 1;
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Error CL_Image::Load_PGM(D3I_FILE * f)
|
||
|
{
|
||
|
if (!f) return CLE_OPENERROR;
|
||
|
|
||
|
DeleteNotMips();
|
||
|
|
||
|
switch (imode)
|
||
|
{
|
||
|
case CLM_GLOBALPALETTE:
|
||
|
case CLM_TLTPALETTE:
|
||
|
break;
|
||
|
default:
|
||
|
return CLE_INVALIDDXMODE;
|
||
|
}
|
||
|
|
||
|
d3i_fseek(f,0,SEEK_SET);
|
||
|
unsigned short magic;
|
||
|
d3i_fread(&magic,2,1,f);
|
||
|
if (magic != *(unsigned short const *)"P5") return CLE_LOADERROR;
|
||
|
|
||
|
d3i_fseek(f,1,SEEK_CUR);
|
||
|
char buf[256];
|
||
|
char * bufptr = buf;
|
||
|
unsigned int fields[5];
|
||
|
unsigned int fields_read = 0;
|
||
|
while (fields_read < 3 && bufptr)
|
||
|
{
|
||
|
do bufptr = d3i_fgets(buf, sizeof buf, f);
|
||
|
while ('#'==buf[0] && bufptr);
|
||
|
|
||
|
int num_fields_read = sscanf(buf,"%u %u %u",&fields[fields_read],&fields[fields_read+1],&fields[fields_read+2]);
|
||
|
if (EOF != num_fields_read) fields_read += num_fields_read;
|
||
|
}
|
||
|
if (fields_read < 3) return CLE_LOADERROR;
|
||
|
width = fields[0];
|
||
|
height = fields[1];
|
||
|
unsigned int maxval = fields[2];
|
||
|
if (maxval > 255) return CLE_LOADERROR;
|
||
|
|
||
|
size = width * height;
|
||
|
|
||
|
im8 = new unsigned char * [height];
|
||
|
*im8 = new unsigned char [size];
|
||
|
|
||
|
d3i_fread(*im8,1,size,f);
|
||
|
|
||
|
unsigned char const * * dptrptr = (unsigned char const * *) im8;
|
||
|
unsigned char const * aptr = *im8;
|
||
|
for (int i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
|
||
|
if (d3i_ferror(f) || d3i_feof(f))
|
||
|
{
|
||
|
DeleteNotMips();
|
||
|
return CLE_LOADERROR;
|
||
|
}
|
||
|
|
||
|
flags.loaded = 1;
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Error CL_Image::Load_PWM(D3I_FILE * f)
|
||
|
{
|
||
|
if (!f) return CLE_OPENERROR;
|
||
|
|
||
|
DeleteNotMips();
|
||
|
|
||
|
switch (imode)
|
||
|
{
|
||
|
case CLM_TLTPALETTE:
|
||
|
break;
|
||
|
default:
|
||
|
return CLE_INVALIDDXMODE;
|
||
|
}
|
||
|
|
||
|
d3i_fseek(f,0,SEEK_SET);
|
||
|
unsigned short magic;
|
||
|
d3i_fread(&magic,2,1,f);
|
||
|
if (magic != *(unsigned short const *)"P8") return CLE_LOADERROR;
|
||
|
|
||
|
d3i_fseek(f,1,SEEK_CUR);
|
||
|
char buf[256];
|
||
|
char * bufptr = buf;
|
||
|
unsigned int fields[5];
|
||
|
unsigned int fields_read = 0;
|
||
|
while (fields_read < 3 && bufptr)
|
||
|
{
|
||
|
do bufptr = d3i_fgets(buf, sizeof buf, f);
|
||
|
while ('#'==buf[0] && bufptr);
|
||
|
|
||
|
int num_fields_read = sscanf(buf,"%u %u %u",&fields[fields_read],&fields[fields_read+1],&fields[fields_read+2]);
|
||
|
if (EOF != num_fields_read) fields_read += num_fields_read;
|
||
|
}
|
||
|
if (fields_read < 3) return CLE_LOADERROR;
|
||
|
width = fields[0];
|
||
|
height = fields[1];
|
||
|
unsigned int maxval = fields[2];
|
||
|
if (maxval > 65535) return CLE_LOADERROR;
|
||
|
|
||
|
size = width * height;
|
||
|
|
||
|
im16raw = new unsigned short * [height];
|
||
|
*im16raw = new unsigned short [size];
|
||
|
|
||
|
d3i_fread(*im16raw,2,size,f);
|
||
|
|
||
|
unsigned short const * * dptrptr = (unsigned short const * *) im16raw;
|
||
|
unsigned short const * aptr = *im16raw;
|
||
|
for (int i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
|
||
|
if (d3i_ferror(f) || d3i_feof(f))
|
||
|
{
|
||
|
DeleteNotMips();
|
||
|
return CLE_LOADERROR;
|
||
|
}
|
||
|
|
||
|
flags.loaded = 1;
|
||
|
flags.raw16bit = 1;
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CL_Error CL_Image::GetBitsPerPixel(unsigned int* bpp)
|
||
|
{
|
||
|
*bpp = bitsperpixel;
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
CL_Error CL_Image::Load_Image(D3I_FILE * f)
|
||
|
{
|
||
|
if (!f) return CLE_OPENERROR;
|
||
|
|
||
|
CL_Error retval = CLE_LOADERROR;
|
||
|
|
||
|
START_TIMER
|
||
|
|
||
|
d3i_fseek(f,0,SEEK_SET);
|
||
|
unsigned short magic;
|
||
|
d3i_fread(&magic,2,1,f);
|
||
|
|
||
|
if ( *(unsigned short const *)"BM" == magic)
|
||
|
retval = Load_BMP(f);
|
||
|
else if ( *(unsigned short const *)"P6" == magic)
|
||
|
retval = Load_PPM(f);
|
||
|
else if ( *(unsigned short const *)"P5" == magic)
|
||
|
retval = Load_PGM(f);
|
||
|
else if ( *(unsigned short const *)"P8" == magic)
|
||
|
retval = Load_PWM(f);
|
||
|
#if OUTPUT_LOG
|
||
|
else CL_LogFile.lputs("** ERROR: Not a recognized file format\n");
|
||
|
#endif
|
||
|
|
||
|
END_TIMER(ReadTime)
|
||
|
|
||
|
#if OUTPUT_LOG
|
||
|
#if TIME_LOADS
|
||
|
CL_LogFile.lprintf("-- Timer Stats (ms): Open %d Read %d Close %d\n",OpenTime,ReadTime,CloseTime);
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CL_Image::PadTo(int const width_unit,int const height_unit)
|
||
|
{
|
||
|
if (!flags.loaded) return;
|
||
|
|
||
|
unsigned int const owidth = width;
|
||
|
unsigned int const oheight = height;
|
||
|
|
||
|
width += width_unit-1;
|
||
|
width &= ~(width_unit-1);
|
||
|
height += height_unit-1;
|
||
|
height &= ~(height_unit-1);
|
||
|
|
||
|
if (width == owidth && height == oheight) return; // already in spec
|
||
|
|
||
|
size = width * height;
|
||
|
|
||
|
CL_Pixel_32 * * const oim32 = im32;
|
||
|
CL_Pixel_16 * * const oim16 = im16;
|
||
|
unsigned char * * const oim8 = im8;
|
||
|
|
||
|
if (oim32)
|
||
|
{
|
||
|
im32 = new CL_Pixel_32 * [height];
|
||
|
*im32 = new CL_Pixel_32 [size];
|
||
|
|
||
|
CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32;
|
||
|
CL_Pixel_32 const * aptr = *im32;
|
||
|
for (unsigned int i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
|
||
|
for (unsigned int y = 0; y < oheight; ++y)
|
||
|
{
|
||
|
CL_Pixel_32 const * sptr = oim32[y];
|
||
|
CL_Pixel_32 * dptr = im32[y];
|
||
|
|
||
|
for (unsigned int x = 0; x < owidth; ++x, ++dptr, ++sptr)
|
||
|
*dptr = *sptr;
|
||
|
|
||
|
for (; x < width; ++x, ++dptr)
|
||
|
*dptr = CL_Pixel_24(0,0,0);
|
||
|
}
|
||
|
|
||
|
for (; y < height; ++y)
|
||
|
{
|
||
|
CL_Pixel_32 * dptr = im32[y];
|
||
|
for (unsigned int x = 0; x < width; ++x, ++dptr)
|
||
|
*dptr = CL_Pixel_24(0,0,0);
|
||
|
}
|
||
|
|
||
|
delete[] *oim32;
|
||
|
delete[] oim32;
|
||
|
}
|
||
|
|
||
|
if (oim16)
|
||
|
{
|
||
|
im16 = new CL_Pixel_16 * [height];
|
||
|
*im16 = new CL_Pixel_16 [size];
|
||
|
|
||
|
CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16;
|
||
|
CL_Pixel_16 const * aptr = *im16;
|
||
|
for (unsigned int i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
|
||
|
for (unsigned int y = 0; y < oheight; ++y)
|
||
|
{
|
||
|
CL_Pixel_16 const * sptr = oim16[y];
|
||
|
CL_Pixel_16 * dptr = im16[y];
|
||
|
|
||
|
for (unsigned int x = 0; x < owidth; ++x, ++dptr, ++sptr)
|
||
|
*dptr = *sptr;
|
||
|
|
||
|
for (; x < width; ++x, ++dptr)
|
||
|
*dptr = CL_Pixel_24(0,0,0);
|
||
|
}
|
||
|
|
||
|
for (; y < height; ++y)
|
||
|
{
|
||
|
CL_Pixel_16 * dptr = im16[y];
|
||
|
for (unsigned int x = 0; x < width; ++x, ++dptr)
|
||
|
*dptr = CL_Pixel_24(0,0,0);
|
||
|
}
|
||
|
|
||
|
delete[] *oim16;
|
||
|
delete[] oim16;
|
||
|
}
|
||
|
|
||
|
if (oim8)
|
||
|
{
|
||
|
im8 = new unsigned char * [height];
|
||
|
*im8 = new unsigned char [size];
|
||
|
|
||
|
unsigned char const * * dptrptr = (unsigned char const * *) im8;
|
||
|
unsigned char const * aptr = *im8;
|
||
|
for (unsigned int i=height; i; --i, aptr+=width)
|
||
|
{
|
||
|
*dptrptr++ = aptr;
|
||
|
}
|
||
|
|
||
|
for (unsigned int y = 0; y < oheight; ++y)
|
||
|
{
|
||
|
unsigned char const * sptr = oim8[y];
|
||
|
unsigned char * dptr = im8[y];
|
||
|
|
||
|
for (unsigned int x = 0; x < owidth; ++x, ++dptr, ++sptr)
|
||
|
*dptr = *sptr;
|
||
|
|
||
|
for (; x < width; ++x, ++dptr)
|
||
|
*dptr = 0;
|
||
|
}
|
||
|
|
||
|
for (; y < height; ++y)
|
||
|
{
|
||
|
unsigned char * dptr = im8[y];
|
||
|
for (unsigned int x = 0; x < width; ++x, ++dptr)
|
||
|
*dptr = 0;
|
||
|
}
|
||
|
|
||
|
delete[] *oim8;
|
||
|
delete[] oim8;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// implementation of the 'popularity algorithm' for reducing palette
|
||
|
|
||
|
unsigned int CL_Pixel_24::FVD_Distance(CL_Pixel_24 const & p2) const
|
||
|
{
|
||
|
unsigned int dg = g > p2.g ? g - p2.g : p2.g - g;
|
||
|
unsigned int db = b > p2.b ? b - p2.b : p2.b - b;
|
||
|
|
||
|
unsigned int dgb = dg + db + ((dg > db ? dg : db)<<1);
|
||
|
|
||
|
unsigned int dr = r > p2.r ? r - p2.r : p2.r - r;
|
||
|
dr += dr<<1; // *= 3
|
||
|
|
||
|
return dr + dgb + ((dr > dgb ? dr : dgb)<<1);
|
||
|
}
|
||
|
|
||
|
struct _CL_palpixcnt
|
||
|
{
|
||
|
unsigned int cnt;
|
||
|
unsigned int palpos;
|
||
|
};
|
||
|
|
||
|
int _CL_cmp_palpixcnt(void const * e1, void const * e2)
|
||
|
{
|
||
|
return ((_CL_palpixcnt *)e2)->cnt - ((_CL_palpixcnt *)e1)->cnt;
|
||
|
}
|
||
|
|
||
|
CL_Error CL_Image::ReducePalette(unsigned int const num_colours)
|
||
|
{
|
||
|
if (!flags.loaded) return CLE_LOADERROR;
|
||
|
|
||
|
if (!palette) return CLE_INVALIDDXMODE;
|
||
|
if (!im8) return CLE_INVALIDDXMODE;
|
||
|
|
||
|
if (palette_size <= num_colours) return CLE_OK;
|
||
|
|
||
|
_CL_palpixcnt * const sortarray = new _CL_palpixcnt[palette_size];
|
||
|
|
||
|
for (unsigned int i=0; i<palette_size; ++i)
|
||
|
{
|
||
|
sortarray[i].cnt = 0;
|
||
|
sortarray[i].palpos = i;
|
||
|
}
|
||
|
|
||
|
for (unsigned int y=0; y<height; ++y)
|
||
|
{
|
||
|
unsigned char const * sptr = im8[y];
|
||
|
|
||
|
for (unsigned int x=width; x; --x, ++sptr)
|
||
|
++ sortarray[*sptr].cnt;
|
||
|
}
|
||
|
|
||
|
unsigned int const palstart = CL_Pixel_24(0,0,0) == palette[0] ? 1 : 0;
|
||
|
qsort(sortarray + palstart, palette_size - palstart, sizeof(_CL_palpixcnt), _CL_cmp_palpixcnt);
|
||
|
|
||
|
CL_Pixel_24 * const opalette = palette;
|
||
|
unsigned int const opalette_size = palette_size;
|
||
|
palette = new CL_Pixel_24[num_colours];
|
||
|
palette_size = num_colours;
|
||
|
|
||
|
for (i=0; i<palette_size; ++i)
|
||
|
palette[i] = opalette[sortarray[i].palpos];
|
||
|
|
||
|
delete[] sortarray;
|
||
|
|
||
|
// umm - if theres black thats not transparent, make sure it doesnt become colour 0 in palette
|
||
|
for (unsigned int pswap=1; pswap<palette_size && 0==palstart && CL_Pixel_24(0,0,0)==palette[0]; ++pswap)
|
||
|
{
|
||
|
palette[0]=palette[pswap];
|
||
|
palette[pswap]=CL_Pixel_24(0,0,0);
|
||
|
}
|
||
|
|
||
|
// emergency?
|
||
|
if (0==palstart && CL_Pixel_24(0,0,0)==palette[0])
|
||
|
palette[0] = CL_Pixel_24(1,1,1);
|
||
|
|
||
|
unsigned int * const palmaps = new unsigned int [opalette_size];
|
||
|
palmaps[0] = 0;
|
||
|
for (i=palstart; i<opalette_size; ++i)
|
||
|
{
|
||
|
unsigned int closest = palstart;
|
||
|
unsigned int distance = opalette[i].FVD_Distance(palette[palstart]);
|
||
|
|
||
|
for (unsigned int j = palstart+1; j<palette_size; ++j)
|
||
|
{
|
||
|
unsigned int thisdist = opalette[i].FVD_Distance(palette[j]);
|
||
|
if (thisdist < distance)
|
||
|
{
|
||
|
distance = thisdist;
|
||
|
closest = j;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
palmaps[i] = closest;
|
||
|
}
|
||
|
|
||
|
delete[] opalette;
|
||
|
|
||
|
for (y=0; y<height; ++y)
|
||
|
{
|
||
|
unsigned char * sptr = im8[y];
|
||
|
|
||
|
for (unsigned int x=width; x; --x, ++sptr)
|
||
|
*sptr = (unsigned char)palmaps[*sptr];
|
||
|
}
|
||
|
|
||
|
delete[] palmaps;
|
||
|
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
// useful filename handling functions
|
||
|
|
||
|
// returns pointer into string pointing to filename without dirname
|
||
|
static char const * strip_path(char const * n)
|
||
|
{
|
||
|
char const * rm = strrchr(n,':');
|
||
|
if (rm) n = rm+1;
|
||
|
rm = strrchr(n,'/');
|
||
|
if (rm) n = rm+1;
|
||
|
rm = strrchr(n,'\\');
|
||
|
if (rm) n = rm+1;
|
||
|
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
static char * strip_path(char * n)
|
||
|
{
|
||
|
char * rm = strrchr(n,':');
|
||
|
if (rm) n = rm+1;
|
||
|
rm = strrchr(n,'/');
|
||
|
if (rm) n = rm+1;
|
||
|
rm = strrchr(n,'\\');
|
||
|
if (rm) n = rm+1;
|
||
|
|
||
|
return n;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// removes any .extension from filename by inserting null character
|
||
|
static void strip_file_extension(char * n)
|
||
|
{
|
||
|
char * dotpos = strrchr(n,'.');
|
||
|
if (dotpos) *dotpos = 0;
|
||
|
}
|
||
|
|
||
|
static char * strip_file_extension(char const * n)
|
||
|
{
|
||
|
char * nn = new char[strlen(n)+1];
|
||
|
strcpy(nn,n);
|
||
|
strip_file_extension(nn);
|
||
|
return nn;
|
||
|
}
|
||
|
|
||
|
// CL_Image functions
|
||
|
|
||
|
CL_Error CL_Image::Locate(char const * iname, int const /* enum_id */)
|
||
|
{
|
||
|
if (!iname) return CLE_RIFFERROR;
|
||
|
|
||
|
if (name)
|
||
|
delete[] name;
|
||
|
name = strip_file_extension(strip_path(iname));
|
||
|
|
||
|
if (fname)
|
||
|
delete[] fname;
|
||
|
fname = new char[strlen(iname)+1];
|
||
|
strcpy(fname,iname);
|
||
|
|
||
|
flags.located = 1;
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
CL_Error CL_Image::Load(char const * const iname, int const enum_id)
|
||
|
{
|
||
|
if (iname || CL_EID_INVALID != enum_id || !flags.located)
|
||
|
{
|
||
|
CL_Error locate_err = Locate(iname,enum_id);
|
||
|
|
||
|
if (locate_err != CLE_OK)
|
||
|
{
|
||
|
EXITONLOCATEFAIL(locate_err,iname,enum_id)
|
||
|
return locate_err;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if OUTPUT_LOG
|
||
|
char const * texformat;
|
||
|
unsigned int redbits = 8;
|
||
|
unsigned int greenbits = 8;
|
||
|
unsigned int bluebits = 8;
|
||
|
switch (imode)
|
||
|
{
|
||
|
case CLM_GLOBALPALETTE:
|
||
|
texformat = "Palettized Display";
|
||
|
break;
|
||
|
case CLM_TLTPALETTE:
|
||
|
texformat = "Palettized Display with Abstract TLT Palette";
|
||
|
break;
|
||
|
case CLM_ATTACHEDPALETTE:
|
||
|
texformat = "Palettized Textures";
|
||
|
break;
|
||
|
case CLM_32BIT:
|
||
|
texformat = "32BIT DX";
|
||
|
redbits += CL_Pixel_32::f.red_bits_gt8;
|
||
|
redbits -= CL_Pixel_32::f.red_bits_lt8;
|
||
|
greenbits += CL_Pixel_32::f.green_bits_gt8;
|
||
|
greenbits -= CL_Pixel_32::f.green_bits_lt8;
|
||
|
bluebits += CL_Pixel_32::f.blue_bits_gt8;
|
||
|
bluebits -= CL_Pixel_32::f.blue_bits_lt8;
|
||
|
break;
|
||
|
case CLM_24BIT:
|
||
|
texformat = "24-bit for runtime conversion";
|
||
|
break;
|
||
|
case CLM_16BIT:
|
||
|
texformat = "16BIT DX";
|
||
|
redbits += CL_Pixel_16::f.red_bits_gt8;
|
||
|
redbits -= CL_Pixel_16::f.red_bits_lt8;
|
||
|
greenbits += CL_Pixel_16::f.green_bits_gt8;
|
||
|
greenbits -= CL_Pixel_16::f.green_bits_lt8;
|
||
|
bluebits += CL_Pixel_16::f.blue_bits_gt8;
|
||
|
bluebits -= CL_Pixel_16::f.blue_bits_lt8;
|
||
|
break;
|
||
|
}
|
||
|
CL_LogFile.lprintf("--%s %s (%u-bit, %u-%u-%u)\n",fname,texformat,bitsperpixel,redbits,greenbits,bluebits);
|
||
|
#endif
|
||
|
|
||
|
START_TIMER
|
||
|
D3I_FILE * fp = d3i_fopen(fname,"rb");
|
||
|
END_TIMER(OpenTime)
|
||
|
|
||
|
if (fp)
|
||
|
{
|
||
|
CL_Error retval = Load_Image(fp);
|
||
|
START_TIMER
|
||
|
d3i_fclose(fp);
|
||
|
END_TIMER(CloseTime)
|
||
|
if (CLE_OK != retval)
|
||
|
{
|
||
|
#if OUTPUT_LOG
|
||
|
CL_LogFile.lputs("** ERROR: unable to read\n");
|
||
|
#endif
|
||
|
EXITONREADFAIL(fname)
|
||
|
}
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
#if OUTPUT_LOG
|
||
|
CL_LogFile.lputs("** ERROR: unable to open\n");
|
||
|
#endif
|
||
|
EXITONLOADFAIL(fname)
|
||
|
return CLE_OPENERROR;
|
||
|
}
|
||
|
|
||
|
CL_Error CL_Image::PreLoad(char const * const iname, int const enum_id)
|
||
|
{
|
||
|
CL_Error locate_err = Locate(iname,enum_id);
|
||
|
|
||
|
if (locate_err != CLE_OK)
|
||
|
{
|
||
|
return locate_err;
|
||
|
}
|
||
|
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
CL_Error CL_Image::LoadMipMaps(int const n_mips) // assumes locating has been done (ie. PreLoad or Load has been called)
|
||
|
{
|
||
|
if (!flags.located) return CLE_FINDERROR;
|
||
|
|
||
|
while (mipmaps.size())
|
||
|
{
|
||
|
delete mipmaps.last_entry();
|
||
|
mipmaps.delete_last_entry();
|
||
|
}
|
||
|
|
||
|
for (int mip_idx = 1; mip_idx < n_mips; ++mip_idx)
|
||
|
{
|
||
|
CL_Image * mip_n = new CL_Image;
|
||
|
|
||
|
mip_n->name = new char[strlen(name)+1];
|
||
|
mip_n->fname = new char[strlen(fname)+1];
|
||
|
strcpy(mip_n->name,name);
|
||
|
strcpy(mip_n->fname,fname);
|
||
|
|
||
|
char * dotpos = strrchr(mip_n->fname,'.');
|
||
|
if (!dotpos)
|
||
|
{
|
||
|
delete mip_n;
|
||
|
break;
|
||
|
}
|
||
|
sprintf(dotpos+3,"%1d",mip_idx);
|
||
|
|
||
|
mip_n->flags.located = 1;
|
||
|
|
||
|
if (CLE_OK!=mip_n->Load())
|
||
|
{
|
||
|
delete mip_n;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (mip_n->width << mip_idx < width || mip_n->height << mip_idx < height)
|
||
|
{
|
||
|
delete mip_n;
|
||
|
#if OUTPUT_LOG
|
||
|
CL_LogFile.lputs("** Warning: less than half size\n");
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
mipmaps.add_entry_end(mip_n);
|
||
|
}
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
void CL_Select_Mode(CL_LoadMode const lmode)
|
||
|
{
|
||
|
switch (lmode)
|
||
|
{
|
||
|
case CLL_D3DTEXTURE:
|
||
|
CL_Image::imode = CL_Image::imode_d3d;
|
||
|
CL_Image::bitsperpixel = CL_Image::bitsperpixel_d3d;
|
||
|
CL_Pixel_16::f = CL_Pixel_16::f_d3d;
|
||
|
CL_Pixel_32::f = CL_Pixel_32::f_d3d;
|
||
|
break;
|
||
|
case CLL_DDSURFACE:
|
||
|
CL_Image::imode = CL_Image::imode_ddraw;
|
||
|
CL_Image::bitsperpixel = CL_Image::bitsperpixel_ddraw;
|
||
|
CL_Pixel_16::f = CL_Pixel_16::f_ddraw;
|
||
|
CL_Pixel_32::f = CL_Pixel_32::f_ddraw;
|
||
|
break;
|
||
|
}
|
||
|
CL_Image::lmode = lmode;
|
||
|
}
|
||
|
|
||
|
// 3DC interface
|
||
|
|
||
|
void CL_Init_DirectDrawMode(CL_VideoMode const vmode)
|
||
|
{
|
||
|
switch (vmode)
|
||
|
{
|
||
|
case CLV_8:
|
||
|
CL_Image::bitsperpixel_ddraw = 8;
|
||
|
CL_Image::imode_ddraw = CLM_GLOBALPALETTE;
|
||
|
break;
|
||
|
case CLV_8TLT:
|
||
|
CL_Image::bitsperpixel_ddraw = 8;
|
||
|
CL_Image::imode_ddraw = CLM_TLTPALETTE;
|
||
|
break;
|
||
|
case CLV_15:
|
||
|
CL_Image::bitsperpixel_ddraw = 16;
|
||
|
CL_Image::imode_ddraw = CLM_16BIT;
|
||
|
CL_Pixel_16::f_ddraw.Init
|
||
|
(
|
||
|
DisplayPixelFormat.dwRBitMask,
|
||
|
DisplayPixelFormat.dwGBitMask,
|
||
|
DisplayPixelFormat.dwBBitMask
|
||
|
);
|
||
|
break;
|
||
|
case CLV_24:
|
||
|
CL_Image::bitsperpixel_ddraw = DisplayPixelFormat.dwRGBBitCount;
|
||
|
if (24 == CL_Image::bitsperpixel_ddraw)
|
||
|
CL_Image::imode_ddraw = CLM_24BIT;
|
||
|
else
|
||
|
{
|
||
|
CL_Image::imode_ddraw = CLM_32BIT;
|
||
|
CL_Pixel_32::f_ddraw.Init
|
||
|
(
|
||
|
DisplayPixelFormat.dwRBitMask,
|
||
|
DisplayPixelFormat.dwGBitMask,
|
||
|
DisplayPixelFormat.dwBBitMask
|
||
|
);
|
||
|
}
|
||
|
break;
|
||
|
case CLV_8T:
|
||
|
CL_Image::bitsperpixel_ddraw = 8;
|
||
|
CL_Image::imode_ddraw = CLM_16BIT;
|
||
|
CL_Pixel_16::f_ddraw.Init(7<<5,7<<2,3);
|
||
|
break;
|
||
|
}
|
||
|
CL_Select_Mode(CLL_DDSURFACE);
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Error CL_Image::CopyToScanDrawTexture(unsigned char * * const ImagePtrA [], unsigned int n_mips_max)
|
||
|
{
|
||
|
if (!flags.loaded) return CLE_LOADERROR;
|
||
|
|
||
|
if (CLL_DDSURFACE != lmode) CL_Select_Mode(CLL_DDSURFACE);
|
||
|
|
||
|
if (n_mips_max > mipmaps.size()+1) n_mips_max = mipmaps.size()+1;
|
||
|
|
||
|
if (!*ImagePtrA[0])
|
||
|
{
|
||
|
if (flags.raw16bit)
|
||
|
{
|
||
|
if (n_mips_max>1)
|
||
|
*ImagePtrA[0] = (unsigned char *) AllocateMem((2*width+1)*(2*height+1)*2/3+(n_mips_max-3)*2); // slightly more than 4/3 w*h*bytedepth
|
||
|
else
|
||
|
*ImagePtrA[0] = (unsigned char *) AllocateMem(width*height*2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (n_mips_max>1)
|
||
|
*ImagePtrA[0] = (unsigned char *) AllocateMem((2*width+1)*(2*height+1)*bitsperpixel/24+(n_mips_max-3)*(bitsperpixel/8)); // slightly more than 4/3 w*h*bytedepth
|
||
|
else
|
||
|
*ImagePtrA[0] = (unsigned char *) AllocateMem(width*height*(bitsperpixel>>3));
|
||
|
}
|
||
|
}
|
||
|
if (!*ImagePtrA[0])
|
||
|
return CLE_ALLOCFAIL;
|
||
|
|
||
|
unsigned int my_bitsperpixel = bitsperpixel;
|
||
|
|
||
|
switch (imode)
|
||
|
{
|
||
|
unsigned char * tptr;
|
||
|
unsigned short * tSptr;
|
||
|
unsigned long * tLptr;
|
||
|
|
||
|
case CLM_GLOBALPALETTE:
|
||
|
case CLM_TLTPALETTE:
|
||
|
if (flags.raw16bit)
|
||
|
{
|
||
|
my_bitsperpixel = 16;
|
||
|
tSptr = (unsigned short *)*ImagePtrA[0];
|
||
|
if (tSptr)
|
||
|
{
|
||
|
for (int i=0; i<height; ++i)
|
||
|
{
|
||
|
memcpy(tSptr,im16raw[i],width*sizeof(unsigned short));
|
||
|
tSptr += width;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tptr = *ImagePtrA[0];
|
||
|
if (tptr)
|
||
|
{
|
||
|
for (int i=0; i<height; ++i)
|
||
|
{
|
||
|
memcpy(tptr,im8[i],width);
|
||
|
tptr += width;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case CLM_16BIT:
|
||
|
switch (bitsperpixel)
|
||
|
{
|
||
|
case 8:
|
||
|
tptr = *ImagePtrA[0];
|
||
|
if (tptr)
|
||
|
{
|
||
|
for (int i=0; i<height; ++i)
|
||
|
{
|
||
|
unsigned char const * i8ptr = im8[i];
|
||
|
for (int j=width; j; --j)
|
||
|
{
|
||
|
*tptr++ = *i8ptr++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 16:
|
||
|
tSptr = (unsigned short *)*ImagePtrA[0];
|
||
|
if (tSptr)
|
||
|
{
|
||
|
for (int i=0; i<height; ++i)
|
||
|
{
|
||
|
CL_Pixel_16 const * i16ptr = im16[i];
|
||
|
for (int j=width; j; --j)
|
||
|
{
|
||
|
*tSptr++ = *i16ptr++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case CLM_24BIT:
|
||
|
switch (bitsperpixel)
|
||
|
{
|
||
|
case 24:
|
||
|
tptr = *ImagePtrA[0];
|
||
|
if (tptr)
|
||
|
{
|
||
|
for (int i=0; i<height; ++i)
|
||
|
{
|
||
|
CL_Pixel_24 const * i24ptr = im24[i];
|
||
|
for (int j=width; j; --j)
|
||
|
{
|
||
|
*tptr++ = i24ptr->b;
|
||
|
*tptr++ = i24ptr->g;
|
||
|
*tptr++ = i24ptr->r;
|
||
|
i24ptr++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 32:
|
||
|
tLptr = (unsigned long *)*ImagePtrA[0];
|
||
|
if (tLptr)
|
||
|
{
|
||
|
for (int i=0; i<height; ++i)
|
||
|
{
|
||
|
CL_Pixel_32 const * i32ptr = im32[i];
|
||
|
for (int j=width; j; --j)
|
||
|
{
|
||
|
*tLptr++ = *i32ptr++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
return CLE_INVALIDDXMODE;
|
||
|
}
|
||
|
|
||
|
// now do mipmaps if avail
|
||
|
|
||
|
CL_Image * last_mipP = this;
|
||
|
|
||
|
LIF<CL_Image *> i_mip(&mipmaps);
|
||
|
for (int i=1; i<n_mips_max && !i_mip.done(); ++i, i_mip.next())
|
||
|
{
|
||
|
*ImagePtrA[i] = *ImagePtrA[i-1] + last_mipP->width*last_mipP->height*(my_bitsperpixel>>3);
|
||
|
CL_Error thismipmaperror = i_mip()->CopyToScanDrawTexture(&ImagePtrA[i],1);
|
||
|
if (CLE_OK != thismipmaperror) return thismipmaperror;
|
||
|
last_mipP = i_mip();
|
||
|
}
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Direct X interface
|
||
|
|
||
|
void CL_Init_D3DMode(LPDDSURFACEDESC const format)
|
||
|
{
|
||
|
CL_Image::format = format;
|
||
|
|
||
|
if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
|
||
|
{
|
||
|
#if QUANTISE_ON_LOAD
|
||
|
CL_Image::imode_d3d = CLM_24BIT;
|
||
|
#else
|
||
|
CL_Image::imode_d3d = CLM_ATTACHEDPALETTE;
|
||
|
#endif
|
||
|
CL_Image::bitsperpixel_d3d = 8;
|
||
|
}
|
||
|
else if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4)
|
||
|
{
|
||
|
#if QUANTISE_ON_LOAD
|
||
|
CL_Image::imode_d3d = CLM_24BIT;
|
||
|
#else
|
||
|
CL_Image::imode_d3d = CLM_ATTACHEDPALETTE;
|
||
|
#endif
|
||
|
CL_Image::bitsperpixel_d3d = 4;
|
||
|
}
|
||
|
else if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED2)
|
||
|
{
|
||
|
#if QUANTISE_ON_LOAD
|
||
|
CL_Image::imode_d3d = CLM_24BIT;
|
||
|
#else
|
||
|
CL_Image::imode_d3d = CLM_ATTACHEDPALETTE;
|
||
|
#endif
|
||
|
CL_Image::bitsperpixel_d3d = 2;
|
||
|
}
|
||
|
else if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED1)
|
||
|
{
|
||
|
#if QUANTISE_ON_LOAD
|
||
|
CL_Image::imode_d3d = CLM_24BIT;
|
||
|
#else
|
||
|
CL_Image::imode_d3d = CLM_ATTACHEDPALETTE;
|
||
|
#endif
|
||
|
CL_Image::bitsperpixel_d3d = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CL_Image::bitsperpixel_d3d = format->ddpfPixelFormat.dwRGBBitCount;
|
||
|
if (format->ddpfPixelFormat.dwRGBBitCount > 16)
|
||
|
{
|
||
|
CL_Image::imode_d3d = CLM_32BIT;
|
||
|
CL_Pixel_32::f_d3d.Init
|
||
|
(
|
||
|
format->ddpfPixelFormat.dwRBitMask,
|
||
|
format->ddpfPixelFormat.dwGBitMask,
|
||
|
format->ddpfPixelFormat.dwBBitMask
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CL_Image::imode_d3d = CLM_16BIT;
|
||
|
CL_Pixel_16::f_d3d.Init
|
||
|
(
|
||
|
format->ddpfPixelFormat.dwRBitMask,
|
||
|
format->ddpfPixelFormat.dwGBitMask,
|
||
|
format->ddpfPixelFormat.dwBBitMask
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
CL_Select_Mode(CLL_D3DTEXTURE);
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Error CL_Image::CopyToD3DTexture(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], int const MemoryType, unsigned int n_mips_max)
|
||
|
{
|
||
|
if (!flags.loaded) return CLE_LOADERROR;
|
||
|
|
||
|
WaitForVRamReady(VWS_D3DTEXCREATE);
|
||
|
|
||
|
if (CLL_D3DTEXTURE != lmode) CL_Select_Mode(CLL_D3DTEXTURE);
|
||
|
|
||
|
LPDIRECTDRAWSURFACE lpDDS;
|
||
|
DDSURFACEDESC ddsd;
|
||
|
HRESULT ddrval;
|
||
|
|
||
|
// Check for image being 4 byte aligned
|
||
|
// and fail if it is not
|
||
|
if (width & 3 || height & 3)
|
||
|
{
|
||
|
// return error code
|
||
|
return CLE_DXERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set up the surface description. starting
|
||
|
// with the passed texture format and then
|
||
|
// incorporating the information read from the
|
||
|
// ppm.
|
||
|
memcpy(&ddsd, format, sizeof(DDSURFACEDESC));
|
||
|
ddsd.dwSize = sizeof(DDSURFACEDESC);
|
||
|
ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT);
|
||
|
ddsd.ddsCaps.dwCaps = (DDSCAPS_TEXTURE | MemoryType);
|
||
|
ddsd.dwHeight = height;
|
||
|
ddsd.dwWidth = width;
|
||
|
|
||
|
if (n_mips_max > mipmaps.size()+1) n_mips_max = mipmaps.size()+1;
|
||
|
|
||
|
if (n_mips_max>1)
|
||
|
{
|
||
|
ddsd.dwFlags |= DDSD_MIPMAPCOUNT;
|
||
|
ddsd.ddsCaps.dwCaps |= DDSCAPS_MIPMAP | DDSCAPS_COMPLEX;
|
||
|
ddsd.dwMipMapCount = n_mips_max;
|
||
|
}
|
||
|
|
||
|
// Create the surface
|
||
|
ddrval = lpDD->CreateSurface(&ddsd, &lpDDS, NULL);
|
||
|
|
||
|
LOGDXERR(ddrval);
|
||
|
if (ddrval != DD_OK)
|
||
|
{
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Release();
|
||
|
return CLE_DXERROR;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
// now do mipmaps if avail
|
||
|
|
||
|
if (n_mips_max>1)
|
||
|
{
|
||
|
// We must now traverse the mip-map chain from highest to lowest
|
||
|
// resolutions, For each surface AFTER the first one, we must
|
||
|
// load a new file, using a name obtained from the mip map number
|
||
|
|
||
|
int MipMapNum = 0;
|
||
|
LPDIRECTDRAWSURFACE lpThisMipMap, lpNextMipMap;
|
||
|
DDSCAPS ddsCaps;
|
||
|
|
||
|
|
||
|
lpThisMipMap = lpDDS;
|
||
|
// Component Object Model, increase reference count on
|
||
|
// mip-map surface by one.
|
||
|
lpThisMipMap->AddRef();
|
||
|
ddsCaps.dwCaps = (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP);
|
||
|
ddrval = DD_OK;
|
||
|
|
||
|
LIF<CL_Image *> i_mip(&mipmaps);
|
||
|
|
||
|
CL_Image * last_mipP = this;
|
||
|
|
||
|
while ((ddrval == DD_OK) && (MipMapNum < n_mips_max)) // both tests in case...
|
||
|
{
|
||
|
// Call LoadPPMIntoDDSurface with lpThisMipMap, new file name, and
|
||
|
// other values.
|
||
|
|
||
|
*DDSurfaceA[MipMapNum] = last_mipP->CopyToDDSurface(lpThisMipMap);
|
||
|
|
||
|
// Death trap
|
||
|
if (!*DDSurfaceA[MipMapNum])
|
||
|
{
|
||
|
return CLE_DXERROR;
|
||
|
}
|
||
|
*DDPtrA[MipMapNum] = lpThisMipMap;
|
||
|
|
||
|
// Proceed to the next level.
|
||
|
// Collect bonus rings.
|
||
|
ddrval = lpThisMipMap->GetAttachedSurface(&ddsCaps, &lpNextMipMap);
|
||
|
// Necessary to match the manual increment of the reference count on the
|
||
|
// COM texture. I think.
|
||
|
lpThisMipMap->Release();
|
||
|
// ?? lpNextMipMap = lpThisMipMap;
|
||
|
lpThisMipMap = lpNextMipMap;
|
||
|
|
||
|
MipMapNum++;
|
||
|
if (!i_mip.done())
|
||
|
{
|
||
|
last_mipP = i_mip();
|
||
|
i_mip.next();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*DDSurfaceA[0] = CopyToDDSurface(lpDDS);
|
||
|
|
||
|
if (!*DDSurfaceA[0]) return CLE_DXERROR;
|
||
|
|
||
|
*DDPtrA[0] = lpDDS;
|
||
|
}
|
||
|
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
CL_Error CL_Image::CopyToDirectDrawSurface(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], int const MemoryType, unsigned int n_mips_max)
|
||
|
{
|
||
|
if (!flags.loaded) return CLE_LOADERROR;
|
||
|
|
||
|
WaitForVRamReady(VWS_DDCREATE);
|
||
|
|
||
|
if (CLL_DDSURFACE != lmode) CL_Select_Mode(CLL_DDSURFACE);
|
||
|
|
||
|
LPDIRECTDRAWSURFACE lpDDS;
|
||
|
DDSURFACEDESC ddsd;
|
||
|
HRESULT ddrval;
|
||
|
|
||
|
// Check for image being 4 byte aligned
|
||
|
// and fail if it is not
|
||
|
if (width & 3 || height & 3)
|
||
|
{
|
||
|
// return error code
|
||
|
return CLE_DXERROR;
|
||
|
}
|
||
|
|
||
|
if (n_mips_max > mipmaps.size()+1) n_mips_max = mipmaps.size()+1;
|
||
|
|
||
|
// Set up the surface description. starting
|
||
|
// with the passed texture format and then
|
||
|
// incorporating the information read from the
|
||
|
// ppm.
|
||
|
memset(&ddsd, 0, sizeof ddsd);
|
||
|
ddsd.dwSize = sizeof ddsd;
|
||
|
ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT);
|
||
|
// Ensure that created surface has same pixel desription
|
||
|
// as primary
|
||
|
memcpy(&ddsd.ddpfPixelFormat, &DisplayPixelFormat, sizeof(DDPIXELFORMAT));
|
||
|
ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN | MemoryType);
|
||
|
ddsd.dwHeight = height;
|
||
|
ddsd.dwWidth = width;
|
||
|
|
||
|
if (n_mips_max>1)
|
||
|
{
|
||
|
ddsd.dwFlags |= DDSD_MIPMAPCOUNT;
|
||
|
ddsd.ddsCaps.dwCaps |= DDSCAPS_MIPMAP | DDSCAPS_COMPLEX;
|
||
|
ddsd.dwMipMapCount = n_mips_max;
|
||
|
}
|
||
|
|
||
|
// Create the surface
|
||
|
ddrval = lpDD->CreateSurface(&ddsd, &lpDDS, NULL);
|
||
|
|
||
|
LOGDXERR(ddrval);
|
||
|
if (ddrval != DD_OK)
|
||
|
{
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Release();
|
||
|
return CLE_DXERROR;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
DDCOLORKEY set_zero = {0,0};
|
||
|
ddrval = lpDDS->SetColorKey(DDCKEY_SRCBLT, &set_zero);
|
||
|
|
||
|
LOGDXERR(ddrval);
|
||
|
if(ddrval != DD_OK)
|
||
|
{
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Release();
|
||
|
return CLE_DXERROR;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
// now do mipmaps if avail
|
||
|
|
||
|
if (n_mips_max>1)
|
||
|
{
|
||
|
// We must now traverse the mip-map chain from highest to lowest
|
||
|
// resolutions, For each surface AFTER the first one, we must
|
||
|
// load a new file, using a name obtained from the mip map number
|
||
|
|
||
|
int MipMapNum = 0;
|
||
|
LPDIRECTDRAWSURFACE lpThisMipMap, lpNextMipMap;
|
||
|
DDSCAPS ddsCaps;
|
||
|
|
||
|
|
||
|
lpThisMipMap = lpDDS;
|
||
|
// Component Object Model, increase reference count on
|
||
|
// mip-map surface by one.
|
||
|
lpThisMipMap->AddRef();
|
||
|
ddsCaps.dwCaps = (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP);
|
||
|
ddrval = DD_OK;
|
||
|
|
||
|
LIF<CL_Image *> i_mip(&mipmaps);
|
||
|
|
||
|
CL_Image * last_mipP = this;
|
||
|
|
||
|
while ((ddrval == DD_OK) && (MipMapNum < n_mips_max)) // both tests in case...
|
||
|
{
|
||
|
// Call LoadPPMIntoDDSurface with lpThisMipMap, new file name, and
|
||
|
// other values.
|
||
|
|
||
|
*DDSurfaceA[MipMapNum] = last_mipP->CopyToDDSurface(lpThisMipMap);
|
||
|
|
||
|
// Death trap
|
||
|
if (!*DDSurfaceA[MipMapNum])
|
||
|
{
|
||
|
return CLE_DXERROR;
|
||
|
}
|
||
|
*DDPtrA[MipMapNum] = lpThisMipMap;
|
||
|
|
||
|
// Proceed to the next level.
|
||
|
// Collect bonus rings.
|
||
|
ddrval = lpThisMipMap->GetAttachedSurface(&ddsCaps, &lpNextMipMap);
|
||
|
// Necessary to match the manual increment of the reference count on the
|
||
|
// COM texture. I think.
|
||
|
lpThisMipMap->Release();
|
||
|
// ?? lpNextMipMap = lpThisMipMap;
|
||
|
lpThisMipMap = lpNextMipMap;
|
||
|
|
||
|
MipMapNum++;
|
||
|
if (!i_mip.done())
|
||
|
{
|
||
|
last_mipP = i_mip();
|
||
|
i_mip.next();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*DDSurfaceA[0] = CopyToDDSurface(lpDDS);
|
||
|
|
||
|
if (!*DDSurfaceA[0]) return CLE_DXERROR;
|
||
|
|
||
|
*DDPtrA[0] = lpDDS;
|
||
|
}
|
||
|
|
||
|
return CLE_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
LPVOID CL_Image::CopyToDDSurface(LPDIRECTDRAWSURFACE lpDDS)
|
||
|
{
|
||
|
if (!flags.loaded) return 0;
|
||
|
|
||
|
LPDIRECTDRAWPALETTE lpDDPPMPal;
|
||
|
PALETTEENTRY ppe[256];
|
||
|
DDSURFACEDESC ddsd;
|
||
|
#if QUANTISE_ON_LOAD
|
||
|
D3DCOLOR colors[256];
|
||
|
D3DCOLOR c;
|
||
|
int color_count;
|
||
|
#endif
|
||
|
int psize;
|
||
|
char *lpC;
|
||
|
HRESULT ddrval;
|
||
|
unsigned int i, j;
|
||
|
unsigned int pcaps;
|
||
|
|
||
|
// Lock the surface so it can be filled with the PPM file
|
||
|
|
||
|
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
|
||
|
ddsd.dwSize = sizeof(DDSURFACEDESC);
|
||
|
ddrval = lpDDS->Lock(NULL, &ddsd, 0, NULL);
|
||
|
|
||
|
if (!ddsd.lpSurface)
|
||
|
{
|
||
|
lpDDS->Unlock(NULL);
|
||
|
lpDDS->Release();
|
||
|
LOGDXSTR("No surface");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
LOGDXERR(ddrval);
|
||
|
if (ddrval != DD_OK)
|
||
|
{
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Release();
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// The method of loading depends on the pixel format of the dest surface
|
||
|
|
||
|
switch (imode)
|
||
|
{
|
||
|
case CLM_32BIT:
|
||
|
switch (bitsperpixel)
|
||
|
{
|
||
|
case 32:
|
||
|
for (j = 0; j < height; j++)
|
||
|
{
|
||
|
// Point to next row in texture surface
|
||
|
unsigned long * lpLP = (unsigned long*)((char*)ddsd.lpSurface
|
||
|
+ ddsd.lPitch * j);
|
||
|
CL_Pixel_32 * lpP32 = im32[j];
|
||
|
for (i = width; i; --i)
|
||
|
{
|
||
|
*lpLP++ = *lpP32++;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 24:
|
||
|
for (j = 0; j < height; j++)
|
||
|
{
|
||
|
// Point to next row in texture surface
|
||
|
unsigned char * lpCP = (unsigned char*)ddsd.lpSurface
|
||
|
+ ddsd.lPitch * j;
|
||
|
CL_Pixel_32 * lpP32 = im32[j];
|
||
|
for (i = width; i; --i)
|
||
|
{
|
||
|
unsigned long lv = *lpP32++;
|
||
|
unsigned char const * lpSrcCP = (unsigned char const *)&lv;
|
||
|
// dodgy - makes assumtions about 24-bit values...
|
||
|
*lpCP++ = *lpSrcCP++;
|
||
|
*lpCP++ = *lpSrcCP++;
|
||
|
*lpCP++ = *lpSrcCP++;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Unlock(NULL);
|
||
|
lpDDS->Release();
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
lpDDS->Unlock(NULL);
|
||
|
break;
|
||
|
case CLM_16BIT:
|
||
|
switch (bitsperpixel)
|
||
|
{
|
||
|
case 16:
|
||
|
for (j = 0; j < height; j++)
|
||
|
{
|
||
|
// Point to next row in texture surface
|
||
|
unsigned short * lpSP = (unsigned short*)((char*)ddsd.lpSurface
|
||
|
+ ddsd.lPitch * j);
|
||
|
CL_Pixel_16 * lpP16 = im16[j];
|
||
|
for (i = width; i; --i)
|
||
|
{
|
||
|
*lpSP++ = *lpP16++;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 8:
|
||
|
for (j = 0; j < height; j++)
|
||
|
{
|
||
|
// Point to next row in texture surface
|
||
|
unsigned char * lpCP = (unsigned char*)ddsd.lpSurface
|
||
|
+ ddsd.lPitch * j;
|
||
|
CL_Pixel_16 * lpP16 = im16[j];
|
||
|
for (i = width; i; --i)
|
||
|
{
|
||
|
*lpCP++ = *lpP16++;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
// Everything's gone pear-shaped...
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Unlock(NULL);
|
||
|
lpDDS->Release();
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
lpDDS->Unlock(NULL);
|
||
|
break;
|
||
|
case CLM_24BIT:
|
||
|
if (24==bitsperpixel)
|
||
|
{
|
||
|
for (j = 0; j < height; j++)
|
||
|
{
|
||
|
// Point to next row in surface
|
||
|
unsigned char * lpCP = ((unsigned char*)ddsd.lpSurface) + ddsd.lPitch * j;
|
||
|
CL_Pixel_24 * lpP24 = im24[j];
|
||
|
for (i = 0; i < width; i++)
|
||
|
{
|
||
|
// making an assumption about the ordering of r,g,b on the video card
|
||
|
*lpCP++ = lpP24->b;
|
||
|
*lpCP++ = lpP24->g;
|
||
|
*lpCP++ = lpP24->r;
|
||
|
lpP24++;
|
||
|
}
|
||
|
}
|
||
|
lpDDS->Unlock(NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#if QUANTISE_ON_LOAD // Neal's quantize on load stuff
|
||
|
|
||
|
// Paletted target texture surface
|
||
|
psize = 1<<bitsperpixel;
|
||
|
color_count = 0; // number of colors in the texture
|
||
|
for (j = 0; j < height; j++)
|
||
|
{
|
||
|
// Point to next row in surface
|
||
|
lpC = ((char*)ddsd.lpSurface) + ddsd.lPitch * j;
|
||
|
CL_Pixel_24 * lpP24 = im24[j];
|
||
|
for (i = 0; i < width; i++, lpP24++)
|
||
|
{
|
||
|
int k;
|
||
|
// Get the next red, green and blue values and turn them into a
|
||
|
// D3DCOLOR.
|
||
|
c = RGB_MAKE(lpP24->r, lpP24->g, lpP24->b);
|
||
|
// Search for this color in a table of colors in this texture
|
||
|
for (k = 0; k < color_count; k++)
|
||
|
if (c == colors[k]) break;
|
||
|
if (k == color_count)
|
||
|
{
|
||
|
// This is a new color, so add it to the list
|
||
|
color_count++;
|
||
|
// More than 256 and we fail (8-bit)
|
||
|
if (color_count > psize)
|
||
|
{
|
||
|
color_count--;
|
||
|
k = color_count - 1;
|
||
|
}
|
||
|
colors[k] = c;
|
||
|
}
|
||
|
// Set the "pixel" value on the surface to be the index into the
|
||
|
// color table
|
||
|
if (psize<256)
|
||
|
{
|
||
|
unsigned int bitmask;
|
||
|
switch (psize)
|
||
|
{
|
||
|
default:
|
||
|
bitmask = 1;
|
||
|
break;
|
||
|
case 4:
|
||
|
bitmask = 3;
|
||
|
break;
|
||
|
case 2:
|
||
|
bitmask = 7;
|
||
|
break;
|
||
|
}
|
||
|
if ((i & bitmask) == 0)
|
||
|
*lpC = (char)(k & (psize-1));
|
||
|
else
|
||
|
*lpC |= (char)((k & (psize-1)) << (i & (psize-1)));
|
||
|
if ((~i & bitmask) == 0)
|
||
|
lpC++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*lpC = (char)k;
|
||
|
lpC++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Close the file and unlock the surface
|
||
|
|
||
|
lpDDS->Unlock(NULL);
|
||
|
|
||
|
if (color_count > psize)
|
||
|
{
|
||
|
// If there are more than 256 colors, we overran our palette
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(0x321123);
|
||
|
#else
|
||
|
lpDDS->Release();
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Create a palette with the colors in our color table
|
||
|
|
||
|
memset(ppe, 0, sizeof(PALETTEENTRY) * 256);
|
||
|
for (i = 0; i < color_count; i++)
|
||
|
{
|
||
|
ppe[i].peRed = (unsigned char)RGB_GETRED(colors[i]);
|
||
|
ppe[i].peGreen = (unsigned char)RGB_GETGREEN(colors[i]);
|
||
|
ppe[i].peBlue = (unsigned char)RGB_GETBLUE(colors[i]);
|
||
|
}
|
||
|
|
||
|
// Set all remaining entry flags to D3DPAL_RESERVED, which are ignored by
|
||
|
// the renderer.
|
||
|
|
||
|
for (; i < 256; i++)
|
||
|
ppe[i].peFlags = D3DPAL_RESERVED;
|
||
|
|
||
|
// Create the palette with the DDPCAPS_ALLOW256 flag because we want to
|
||
|
// have access to all entries.
|
||
|
|
||
|
switch (bitsperpixel)
|
||
|
{
|
||
|
default:
|
||
|
pcaps = DDPCAPS_8BIT | DDPCAPS_ALLOW256;
|
||
|
break;
|
||
|
case 4:
|
||
|
pcaps = DDPCAPS_4BIT;
|
||
|
break;
|
||
|
case 2:
|
||
|
pcaps = DDPCAPS_2BIT;
|
||
|
break;
|
||
|
case 1:
|
||
|
pcaps = DDPCAPS_1BIT;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ddrval = lpDD->CreatePalette
|
||
|
(DDPCAPS_INITIALIZE | pcaps,
|
||
|
ppe, &lpDDPPMPal, NULL);
|
||
|
LOGDXERR(ddrval);
|
||
|
|
||
|
if (ddrval != DD_OK)
|
||
|
{
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Release();
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Finally, bind the palette to the surface
|
||
|
|
||
|
ddrval = lpDDS->SetPalette(lpDDPPMPal);
|
||
|
LOGDXERR(ddrval);
|
||
|
if (ddrval != DD_OK)
|
||
|
{
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Release();
|
||
|
lpDDPPMPal->Release();
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
lpDDPPMPal->Release();
|
||
|
}
|
||
|
break;
|
||
|
#else
|
||
|
// Everything's gone pear-shaped...
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Unlock(NULL);
|
||
|
lpDDS->Release();
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
break;
|
||
|
case CLM_ATTACHEDPALETTE:
|
||
|
#endif
|
||
|
case CLM_GLOBALPALETTE:
|
||
|
case CLM_TLTPALETTE:
|
||
|
// Paletted target texture surface
|
||
|
|
||
|
psize = 1<<bitsperpixel;
|
||
|
ReducePalette(psize); // will do nothing if palette is already small enough
|
||
|
// ignore returned error code, because I don't care if it failed
|
||
|
for (j = 0; j < height; j++)
|
||
|
{
|
||
|
// Point to next row in surface
|
||
|
lpC = ((char*)ddsd.lpSurface) + ddsd.lPitch * j;
|
||
|
unsigned char * lpP8 = im8[j];
|
||
|
|
||
|
if (psize<256)
|
||
|
{
|
||
|
unsigned int bitmask;
|
||
|
unsigned int nextpixelshift;
|
||
|
switch (psize)
|
||
|
{
|
||
|
default:
|
||
|
nextpixelshift = 2;
|
||
|
break;
|
||
|
case 4:
|
||
|
nextpixelshift = 1;
|
||
|
break;
|
||
|
case 2:
|
||
|
nextpixelshift = 0;
|
||
|
break;
|
||
|
}
|
||
|
bitmask = 7 >> nextpixelshift;
|
||
|
for (i = 0; i < width; i++)
|
||
|
{
|
||
|
unsigned char k = *lpP8++;
|
||
|
// Set the "pixel" value on the surface to be the index into the
|
||
|
// color table
|
||
|
if ((i & bitmask) == 0)
|
||
|
*lpC = (char) (k & (psize-1));
|
||
|
else
|
||
|
*lpC |= (char) ((k & (psize-1)) << ((i & bitmask)<<nextpixelshift));
|
||
|
if ((~i & bitmask) == 0)
|
||
|
lpC++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memcpy(lpC,lpP8,width);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Close the file and unlock the surface
|
||
|
|
||
|
lpDDS->Unlock(NULL);
|
||
|
|
||
|
// Create a palette with the colors in our color table
|
||
|
|
||
|
memset(ppe, 0, sizeof(PALETTEENTRY) * 256);
|
||
|
for (i = 0; i < palette_size; i++)
|
||
|
{
|
||
|
ppe[i].peRed = palette[i].r;
|
||
|
ppe[i].peGreen = palette[i].g;
|
||
|
ppe[i].peBlue = palette[i].b;
|
||
|
}
|
||
|
|
||
|
// Set all remaining entry flags to D3DPAL_RESERVED, which are ignored by
|
||
|
// the renderer.
|
||
|
|
||
|
for (; i < 256; i++)
|
||
|
ppe[i].peFlags = D3DPAL_RESERVED;
|
||
|
|
||
|
// Create the palette with the DDPCAPS_ALLOW256 flag because we want to
|
||
|
// have access to all entries.
|
||
|
|
||
|
switch (bitsperpixel)
|
||
|
{
|
||
|
default:
|
||
|
pcaps = DDPCAPS_8BIT | DDPCAPS_ALLOW256;
|
||
|
break;
|
||
|
case 4:
|
||
|
pcaps = DDPCAPS_4BIT;
|
||
|
break;
|
||
|
case 2:
|
||
|
pcaps = DDPCAPS_2BIT;
|
||
|
break;
|
||
|
case 1:
|
||
|
pcaps = DDPCAPS_1BIT;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ddrval = lpDD->CreatePalette
|
||
|
(DDPCAPS_INITIALIZE | pcaps,
|
||
|
ppe, &lpDDPPMPal, NULL);
|
||
|
LOGDXERR(ddrval);
|
||
|
|
||
|
if (ddrval != DD_OK)
|
||
|
{
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Release();
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Finally, bind the palette to the surface
|
||
|
|
||
|
ddrval = lpDDS->SetPalette(lpDDPPMPal);
|
||
|
LOGDXERR(ddrval);
|
||
|
if (ddrval != DD_OK)
|
||
|
{
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Release();
|
||
|
lpDDPPMPal->Release();
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
lpDDPPMPal->Release();
|
||
|
break;
|
||
|
default:
|
||
|
// Everything's gone pear-shaped...
|
||
|
#if debug
|
||
|
ReleaseDirect3D();
|
||
|
exit(ddrval);
|
||
|
#else
|
||
|
lpDDS->Unlock(NULL);
|
||
|
lpDDS->Release();
|
||
|
return 0;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
return ddsd.lpSurface;
|
||
|
}
|
||
|
|
||
|
|