diff options
Diffstat (limited to '3dc/win95/D3_IMAGE.CPP')
| -rw-r--r-- | 3dc/win95/D3_IMAGE.CPP | 2491 |
1 files changed, 2491 insertions, 0 deletions
diff --git a/3dc/win95/D3_IMAGE.CPP b/3dc/win95/D3_IMAGE.CPP new file mode 100644 index 0000000..c068b82 --- /dev/null +++ b/3dc/win95/D3_IMAGE.CPP @@ -0,0 +1,2491 @@ +#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; +} + + |
