summaryrefslogtreecommitdiff
path: root/3dc/win95/D3_IMAGE.HPP
diff options
context:
space:
mode:
Diffstat (limited to '3dc/win95/D3_IMAGE.HPP')
-rw-r--r--3dc/win95/D3_IMAGE.HPP1223
1 files changed, 1223 insertions, 0 deletions
diff --git a/3dc/win95/D3_IMAGE.HPP b/3dc/win95/D3_IMAGE.HPP
new file mode 100644
index 0000000..a2bc639
--- /dev/null
+++ b/3dc/win95/D3_IMAGE.HPP
@@ -0,0 +1,1223 @@
+#ifndef _included__d3_image_hpp_
+#define _included__d3_image_hpp_
+
+#error "This file is obsolete"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "list_tem.hpp"
+
+#include "ddraw.h"
+#include "d3d.h"
+#include "vramtime.h"
+
+#include "system.h"
+#include "mem3dc.h"
+
+#include "dxlog.h"
+// define = 1 if you want an output log file of all texture files loaded and for which DD surface format
+#if debug
+#define OUTPUT_LOG 1
+#else
+#define OUTPUT_LOG 0
+#endif
+
+// define = 1 to use fast files for loading (will still try normal files if fastfile doesn't contain correct data)
+#define USE_FASTFILE 1
+
+#if USE_FASTFILE
+
+#include "ffstdio.h"
+#define D3I_FILE FFILE
+#define d3i_fpos_t ffpos_t
+#define d3i_fclearerr ffclearerr
+#define d3i_fclose ffclose
+#define d3i_fcloseall ffcloseall
+#define d3i_feof ffeof
+#define d3i_ferror fferror
+#define d3i_fgetc ffgetc
+#define d3i_fgetpos ffgetpos
+#define d3i_fgets ffgets
+#define d3i_flook fflook
+#define d3i_flookb fflookb
+#define d3i_fopen ffopen
+#define d3i_fread ffread
+#define d3i_freadb ffreadb
+#define d3i_fseek ffseek
+#define d3i_fsetpos ffsetpos
+#define d3i_ftell fftell
+
+#else
+
+#define D3I_FILE FILE
+#define d3i_fpos_t fpos_t
+#define d3i_fclearerr fclearerr
+#define d3i_fclose fclose
+#define d3i_fcloseall fcloseall
+#define d3i_feof feof
+#define d3i_ferror ferror
+#define d3i_fgetc fgetc
+#define d3i_fgetpos fgetpos
+#define d3i_fgets fgets
+#define d3i_fopen fopen
+#define d3i_fread fread
+#define d3i_fseek fseek
+#define d3i_fsetpos fsetpos
+#define d3i_ftell ftell
+
+#endif
+
+
+// define = 1 if you do not want to handle the error return codes, and require a load failure to cause an exit
+#define EXIT_ON_LOAD_FAIL 0
+
+// define = 1 if you are locating images through rif files and expect this to always succeed
+// works like EXIT_ON_LOAD_FAIL, and only if EXIT_ON_LOAD_FAIL is set, but most failures are handled
+// by assuming the given name to be a complete path and filename
+#define EXIT_ON_LOCATE_FAIL 0
+
+// define = 1 to time file opens, file closes and file reads
+#define TIME_LOADS 0
+
+// I tested the times with a typically complex set of images from AVP,
+// loaded over a nework.
+// Opening took 16secs, Reading 38secs and Closing 2secs for approx
+// for about 500 images (including mip maps)
+
+#if TIME_LOADS
+#include <time.h>
+#define START_TIMER {clock_t __stime = clock();
+#define END_TIMER(__var) __var += (unsigned int) ((clock() - __stime) * 1000 / CLOCKS_PER_SEC);}
+#else
+#define START_TIMER
+#define END_TIMER(__var)
+#endif
+
+#if TIME_LOADS
+extern unsigned int OpenTime;
+extern unsigned int CloseTime;
+extern unsigned int ReadTime;
+#endif
+
+#if OUTPUT_LOG
+#include "debuglog.hpp"
+extern LogFile CL_LogFile;
+#endif
+
+// externs for 3dc things
+extern "C" {
+ extern LPDIRECTDRAW lpDD;
+ extern DDPIXELFORMAT DisplayPixelFormat;
+};
+
+enum CL_RGBFormat // for loading from files
+{
+ CLF_RGB, CLF_BGR, CLF_BGRX
+};
+
+struct CL_Pixel_24
+{
+ union
+ {
+ struct
+ {
+ unsigned char r,g,b;
+ unsigned char xx;
+ };
+ unsigned long l;
+ };
+
+ CL_Pixel_24() : l(0) {}
+ CL_Pixel_24(unsigned char const r,unsigned char const g,unsigned char const b) : r(r),g(g),b(b),xx(0) {}
+ CL_Pixel_24(CL_Pixel_24 const & p24) : l(p24.l) {}
+ CL_Pixel_24(unsigned long const i) : l(i) {}
+
+ operator unsigned long (void) const { return l; }
+
+ inline void Read (D3I_FILE * const f, CL_RGBFormat const t)
+ {
+ switch(t)
+ {
+ case CLF_RGB:
+ d3i_fread(&r,1,1,f);
+ d3i_fread(&g,1,1,f);
+ d3i_fread(&b,1,1,f);
+ break;
+ case CLF_BGR:
+ d3i_fread(&b,1,1,f);
+ d3i_fread(&g,1,1,f);
+ d3i_fread(&r,1,1,f);
+ break;
+ case CLF_BGRX:
+ d3i_fread(&b,1,1,f);
+ d3i_fread(&g,1,1,f);
+ d3i_fread(&r,1,1,f);
+ d3i_fseek(f,1,SEEK_CUR);
+ default:
+ break;
+ }
+ }
+
+ inline void Read (D3I_FILE * const f, CL_RGBFormat const t, unsigned int const maxval)
+ {
+ Read(f,t);
+ if (maxval != 255)
+ {
+ r = (unsigned char) ( ((unsigned int)r << 8) / (maxval+1) );
+ g = (unsigned char) ( ((unsigned int)g << 8) / (maxval+1) );
+ b = (unsigned char) ( ((unsigned int)b << 8) / (maxval+1) );
+ }
+ }
+
+ unsigned int FVD_Distance(CL_Pixel_24 const & p2) const;
+};
+
+
+struct CL_DX_Format
+{
+ unsigned int
+ red_mask,
+ red_shift,
+ red_bits,
+ red_bits_gt8,
+ red_bits_lt8,
+ blue_mask,
+ blue_shift,
+ blue_bits,
+ blue_bits_gt8,
+ blue_bits_lt8,
+ green_mask,
+ green_shift,
+ green_bits,
+ green_bits_gt8,
+ green_bits_lt8;
+
+ CL_Pixel_24 dx_black;
+
+ inline void Init(unsigned int rmask,unsigned int gmask,unsigned int bmask)
+ {
+ red_mask = rmask;
+ blue_mask = bmask;
+ green_mask = gmask;
+ for (red_shift = 0; !(rmask & 1); red_shift++, rmask>>=1);
+ for (green_shift = 0; !(gmask & 1); green_shift++, gmask>>=1);
+ for (blue_shift = 0; !(bmask & 1); blue_shift++, bmask>>=1);
+ for (red_bits = 0; rmask; red_bits++, rmask>>=1);
+ for (green_bits = 0; gmask; green_bits++, gmask>>=1);
+ for (blue_bits = 0; bmask; blue_bits++, bmask>>=1);
+ if (blue_bits >= green_bits && blue_bits >= red_bits)
+ {
+ dx_black = CL_Pixel_24(0,0,1);
+ }
+ else if (red_bits >= green_bits)
+ {
+ dx_black = CL_Pixel_24(1,0,0);
+ }
+ else
+ {
+ dx_black = CL_Pixel_24(0,1,0);
+ }
+ if (red_bits >= 8)
+ {
+ red_bits_gt8 = red_bits-8;
+ red_bits_lt8 = 0;
+ }
+ else
+ {
+ red_bits_lt8 = 8-red_bits;
+ red_bits_gt8 = 0;
+ }
+ if (green_bits >= 8)
+ {
+ green_bits_gt8 = green_bits-8;
+ green_bits_lt8 = 0;
+ }
+ else
+ {
+ green_bits_lt8 = 8-green_bits;
+ green_bits_gt8 = 0;
+ }
+ if (blue_bits >= 8)
+ {
+ blue_bits_gt8 = blue_bits-8;
+ blue_bits_lt8 = 0;
+ }
+ else
+ {
+ blue_bits_lt8 = 8-blue_bits;
+ blue_bits_gt8 = 0;
+ }
+ }
+};
+
+
+// for 32 bit and 24 bit DirectX formats
+template <class S>
+struct CL_Pixel_T
+{
+ static CL_DX_Format f;
+ static CL_DX_Format f_d3d;
+ static CL_DX_Format f_ddraw;
+
+ S p;
+
+ inline S r(void) const { return (S)((p & f.red_mask)>>f.red_shift); }
+ inline S g(void) const { return (S)((p & f.green_mask)>>f.green_shift); }
+ inline S b(void) const { return (S)((p & f.blue_mask)>>f.blue_shift); }
+
+ CL_Pixel_T() {}
+ CL_Pixel_T(CL_Pixel_T<S> const & p32) : p(p32.p) {}
+ CL_Pixel_T(CL_Pixel_24 const & p24)
+ : p((S)(
+ (S)p24.r>>f.red_bits_lt8<<f.red_shift+f.red_bits_gt8 |
+ (S)p24.g>>f.green_bits_lt8<<f.green_shift+f.green_bits_gt8 |
+ (S)p24.b>>f.blue_bits_lt8<<f.blue_shift+f.blue_bits_gt8 ))
+ {
+ // make the 32bit pixel non-black to avoid transparency problems
+ if (!p && p24.l) // if the 24bit pixel is not black and the 32 bit pixel is black
+ {
+ // choose which of r,g or b to make non-zero - try and get as close to black as poss
+ if ((1<<f.blue_bits_lt8)-p24.b <= (1<<f.red_bits_lt8)-p24.r && (1<<f.blue_bits_lt8)-p24.b <= (1<<f.green_bits_lt8)-p24.g)
+ p = (S)(1<<f.blue_shift);
+ else if ((1<<f.red_bits_lt8)-p24.r <= (1<<f.green_bits_lt8)-p24.g)
+ p = (S)(1<<f.red_shift);
+ else
+ p = (S)(1<<f.green_shift);
+ }
+ }
+
+ inline operator CL_Pixel_24 (void) const
+ {
+ S rr = (S)(r()>>f.red_bits_gt8<<f.red_bits_lt8);
+ S gg = (S)(g()>>f.green_bits_gt8<<f.green_bits_lt8);
+ S bb = (S)(b()>>f.blue_bits_gt8<<f.blue_bits_lt8);
+
+ if (!(rr|gg|bb) && p)
+ {
+ if (b()<<f.red_bits>=r()<<f.blue_bits && b()<<f.green_bits>=g()<<f.blue_bits) // make the 16bit pixel non-black to avoid transparency problems
+ bb = 1;
+ else if (r()<<f.green_bits>=g()<<f.red_bits)
+ rr = 1;
+ else
+ gg = 1;
+ }
+
+ return CL_Pixel_24((unsigned char)rr,(unsigned char)gg,(unsigned char)bb);
+ };
+ operator S (void) const { return p; }
+
+ inline void Read (D3I_FILE * const f, CL_RGBFormat const t)
+ {
+ CL_Pixel_24 p24;
+ p24.Read(f,t);
+ *this = (CL_Pixel_T<S>)p24;
+ }
+
+ inline void Read (D3I_FILE * const f, CL_RGBFormat const t, unsigned int const maxval)
+ {
+ CL_Pixel_24 p24;
+ p24.Read(f,t,maxval);
+ *this = (CL_Pixel_T<S>)p24;
+ }
+};
+
+
+typedef CL_Pixel_T<unsigned long> CL_Pixel_32;
+typedef CL_Pixel_T<unsigned short> CL_Pixel_16;
+
+
+enum CL_Error
+{
+ CLE_OK,
+ CLE_LOADERROR, // file cannot be loaded - format is wrong
+ CLE_OPENERROR, // file cannot be opened - does not exist?
+ CLE_FINDERROR, // file cannot be found - not listed in .RIF file
+ CLE_RIFFERROR, // rif file not loaded, or invalid
+ CLE_INVALIDGAMEMODE, // specified game mode does not exist
+ CLE_INVALIDDXMODE, // video mode is invalid
+ CLE_DXERROR, // other direct X related error
+ CLE_ALLOCFAIL // failed memory allocation
+};
+
+
+enum CL_ImageMode {
+
+ CLM_GLOBALPALETTE, // image shares a global palette in a palettized mode
+ CLM_TLTPALETTE, // images may also share an abstract palette which remaps via a tlt to a global display palette
+ CLM_ATTACHEDPALETTE, // 256 colour image with attached palette
+ CLM_16BIT, // 16 bit in specified RGB format
+ CLM_32BIT, // 32 bit in specified RGB format
+ CLM_24BIT // 24 bit truecolour image in 888 format
+};
+// Note:
+// currently 24-bit and 16-bit image formats are not output.
+// If the desired format is 24-bit or 16-bit then 256 colour BMPs are loaded
+// and 'unquantized' to generate the required format.
+
+
+enum CL_LoadMode {
+
+ CLL_D3DTEXTURE,
+ CLL_DDSURFACE
+};
+
+void CL_Select_Mode(CL_LoadMode const lmode);
+
+
+void CL_Init_D3DMode(LPDDSURFACEDESC const format);
+
+enum CL_VideoMode {
+
+ CLV_8,
+ CLV_15,
+ CLV_24,
+ CLV_8T,
+ CLV_8TLT
+};
+
+void CL_Init_DirectDrawMode(CL_VideoMode const vmode);
+
+
+
+// test!!!
+#if HwTextureHack
+static int craptest = 0;
+#endif
+
+#if EXIT_ON_LOAD_FAIL
+ extern "C"
+ {
+ #include "3dc.h"
+ }
+ #if EXIT_ON_LOCATE_FAIL
+ #define EXITONLOCATEFAIL(__errcode,__iname,__enum_id) \
+ if (CLE_RIFFERROR != __errcode) { \
+ if (__iname) textprint("Cannot figure path for:\n%s\n",__iname); \
+ else textprint("Cannot figure path for:\nImage ID %d\n",__enum_id); \
+ WaitForReturn(); \
+ ExitSystem(); \
+ exit(0x10cafa11); \
+ }
+ #else
+ #define EXITONLOCATEFAIL(__errcode,__iname,__enum_id)
+ #endif
+ #define EXITONLOADFAIL(__iname) \
+ { \
+ textprint("Cannot open:\n%s\n",__iname); \
+ WaitForReturn(); \
+ ExitSystem(); \
+ exit(0x10adfa11); \
+ }
+ #define EXITONREADFAIL(__iname) \
+ { \
+ textprint("Cannot read:\n%s\n",__iname); \
+ WaitForReturn(); \
+ ExitSystem(); \
+ exit(0x10adfa11); \
+ }
+#else
+ #define EXITONLOCATEFAIL(__errcode,__iname,__enum_id)
+ #define EXITONLOADFAIL(__iname)
+ #define EXITONREADFAIL(__iname)
+#endif
+
+struct CL_Flags
+{
+ unsigned int loaded : 1;
+ unsigned int located : 1;
+ unsigned int raw16bit : 1;
+ unsigned int tltpalette : 1;
+
+ CL_Flags()
+ : loaded(0)
+ , located(0)
+ , tltpalette(0)
+ , raw16bit(0)
+ {}
+};
+
+#define CL_EID_INVALID (-1)
+
+
+#if 0
+template <class I>
+class CL_MIP_Image
+{
+public:
+ unsigned int num_mipmaps;
+ I * * mipmaps; // array of CL_Image pointers of decreasing image size
+
+ unsigned int width; // == mipmaps[0]->width
+ unsigned int height; // == mipmaps[0]->height
+ unsigned int size; // == mipmaps[0]->size
+
+ char * fname; // full filename (including directory/path) of mipmap with index 0
+ char * name; // name of image without directory/path or extension
+
+ CL_MIP_Image() : mipmaps(0), num_mipmaps(0), fname(0), name(0) {}
+ ~CL_MIP_Image() { Delete(); }
+
+ CL_MIP_Image(CL_MIP_Image<I> const & i2)
+ : width (i2.width)
+ , height (i2.height)
+ , size (i2.size)
+ , num_mipmaps (i2.num_mipmaps)
+ { Copy(i2); }
+
+ CL_MIP_Image<I> & operator = (CL_MIP_Image<I> const & i2)
+ {
+ if (&i2 != this)
+ {
+ Delete();
+
+ width = i2.width;
+ height = i2.height;
+ size = i2.size;
+ num_mipmaps = i2.num_mipmaps;
+
+ Copy(i2);
+ }
+ return *this;
+ }
+
+private:
+ void Copy(CL_MIP_Image<I> const & i2)
+ {
+ if (i2.mipmaps)
+ {
+ mipmaps = new I * [num_mipmaps];
+ for (int i=0; i<num_mipmaps; ++i)
+ {
+ mipmaps[i] = new I(*i2.mipmaps[i]);
+ }
+ }
+
+ if (i2.fname)
+ {
+ fname = new char[strlen(i2.fname)+1];
+ strcpy(fname,i2.fname);
+ }
+
+ if (i2.name)
+ {
+ name = new char[strlen(i2.name)+1];
+ strcpy(name,i2.name);
+ }
+ }
+ void Delete(void)
+ {
+ if (mipmaps)
+ {
+ for (int i=0; i<num_mipmaps; ++i) delete mipmaps[i];
+ delete[] mipmaps;
+ mipmaps = 0;
+ }
+
+ if (name)
+ {
+ delete[] name;
+ name = 0;
+ }
+
+ if (fname)
+ {
+ delete[] fname;
+ fname = 0;
+ }
+ }
+
+ CL_Flags flags;
+
+public:
+ inline CL_Error Load(int const enum_id)
+ {
+ return Load(0,enum_id);
+ }
+ inline CL_Error Load(char const * const iname)
+ {
+ return Load(iname,CL_EID_INVALID);
+ }
+ inline CL_Error Load()
+ {
+ return Load(0,CL_EID_INVALID);
+ }
+
+ inline CL_Error PreLoad(int const enum_id)
+ {
+ return PreLoad(0,enum_id);
+ }
+ inline CL_Error PreLoad(char const * const iname)
+ {
+ return PreLoad(iname,CL_EID_INVALID);
+ }
+
+ CL_Error CopyToScanDrawTexture(unsigned char * * const ImagePtrA [], unsigned int maxnummips)
+ {
+ if (!flags.loaded) return CLE_LOADERROR;
+
+ if (CLL_DDSURFACE != I::lmode) CL_Select_Mode(CLL_DDSURFACE);
+
+ if (num_mipmaps < maxnummips) maxnummips = num_mipmaps;
+ if (!maxnummips) return CLE_ALLOCFAIL;
+
+ if (!*ImagePtrA[0]) *ImagePtrA[0] = (unsigned char *) AllocateMem((2*width+1)*(2*height+1)*I::bitsperpixel/24+(maxnummips-3)*I::bitsperpixel/8); // slightly more than 4/3 w*h*bytedepth
+
+ for (int i=0; i<maxnummips; ++i)
+ {
+ if (i) *ImagePtrA[i] = *ImagePtrA[i-1] + mipmaps[i-1]->width*mipmaps[i-1]->height*(I::bitsperpixel>>3);
+ CL_Error thismipmaperror = mipmaps[i]->CopyToScanDrawTexture(ImagePtrA[i]);
+ if (CLE_OK != thismipmaperror) return thismipmaperror;
+ }
+ return CLE_OK;
+ }
+
+ CL_Error CopyToD3DTexture(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], unsigned int maxnummips, int const MemoryType)
+ {
+ if (!flags.loaded) return CLE_LOADERROR;
+
+ WaitForVRamReady(VWS_D3DTEXCREATE);
+
+ if (CLL_D3DTEXTURE != I::lmode) CL_Select_Mode(CLL_D3DTEXTURE);
+
+ LPDIRECTDRAWSURFACE lpDDS;
+ DDSURFACEDESC ddsd;
+ HRESULT ddrval;
+
+ if (width & 3 || height & 3)
+ {
+ // return error code
+ return CLE_DXERROR;
+ }
+
+ /* test !!! */
+ {
+ #if HwTextureHack
+ craptest++;
+ if (craptest > 10)
+ return CLE_DXERROR;
+ #endif
+ }
+
+
+ if (num_mipmaps < maxnummips) maxnummips = num_mipmaps;
+ // Set up the mip-mapped surface description. starting
+ // with the passed texture format and then
+ // incorporating the information read from the
+ // ppm.
+ memcpy(&ddsd, I::format, sizeof(DDSURFACEDESC));
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
+ | DDSD_MIPMAPCOUNT);
+ ddsd.dwMipMapCount = maxnummips; // engine standard, primary plus six mip-maps
+ ddsd.ddsCaps.dwCaps = (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP
+ | DDSCAPS_COMPLEX | MemoryType);
+ ddsd.dwHeight = height;
+ ddsd.dwWidth = width;
+
+
+ // 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
+ }
+
+ // 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;
+
+ while ((ddrval == DD_OK) && (MipMapNum < maxnummips)) // both tests in case...
+ {
+ // Call LoadPPMIntoDDSurface with lpThisMipMap, new file name, and
+ // other values.
+
+ *DDSurfaceA[MipMapNum] = mipmaps[MipMapNum]->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++;
+ }
+
+ return CLE_OK;
+
+ }
+
+ CL_Error CopyToDirectDrawSurface(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], unsigned int maxnummips, int const MemoryType)
+ {
+ if (!flags.loaded) return CLE_LOADERROR;
+
+ WaitForVRamReady(VWS_DDCREATE);
+
+ if (CLL_DDSURFACE != I::lmode) CL_Select_Mode(CLL_DDSURFACE);
+
+ LPDIRECTDRAWSURFACE lpDDS;
+ DDSURFACEDESC ddsd;
+ HRESULT ddrval;
+
+ if (width & 3 || height & 3)
+ {
+ // return error code
+ return CLE_DXERROR;
+ }
+
+ if (num_mipmaps < maxnummips) maxnummips = num_mipmaps;
+ // Set up the mip-mapped 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
+ | DDSD_MIPMAPCOUNT);
+ ddsd.dwMipMapCount = maxnummips; // engine standard, primary plus six mip-maps
+ ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_MIPMAP
+ | DDSCAPS_COMPLEX | MemoryType);
+ ddsd.dwHeight = height;
+ ddsd.dwWidth = width;
+
+
+ // 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
+ }
+
+ // 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;
+
+ while ((ddrval == DD_OK) && (MipMapNum < maxnummips)) // both tests in case...
+ {
+ // Call LoadPPMIntoDDSurface with lpThisMipMap, new file name, and
+ // other values.
+
+ *DDSurfaceA[MipMapNum] = mipmaps[MipMapNum]->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++;
+ }
+
+ return CLE_OK;
+
+ }
+
+private:
+ // I was using Dan's list template for this,
+ // but since it is not a standard part of 3DC,
+ // I have had to write a specific simple list handler
+ struct TempListMember
+ {
+ I * mip;
+ TempListMember * next;
+ TempListMember(I * data) : mip(data), next(0) {}
+ //TempListMember() : next(0) {}
+ ~TempListMember() { if (next) delete next; }
+ };
+ struct TempList
+ {
+ unsigned int n_entries;
+ TempListMember * first;
+ TempListMember * last;
+ TempList(I * data) : first(new TempListMember(data)), n_entries(1) { last = first; }
+ TempList & operator += (I * data)
+ {
+ if (!first)
+ {
+ first = new TempListMember(data);
+ last = first;
+ }
+ else
+ {
+ last->next = new TempListMember(data);
+ last = last->next;
+ }
+ ++ n_entries;
+ return *this;
+ }
+ ~TempList()
+ {
+ if (first) delete first;
+ }
+ };
+
+ CL_Error Load(char const * const iname, int const enum_id)
+ {
+ if (iname || CL_EID_INVALID != enum_id) flags.located = 0;
+
+ I * mip0;
+
+ if (flags.located && mipmaps)
+ {
+ mip0 = mipmaps[0];
+ // we have grabbed the previously allocated pointer
+ // it will now be treated as if it were allocated here,
+ // so we must remove it from the class, in case the
+ // deconstructor tries to deallocate it
+ delete[] mipmaps;
+ mipmaps = 0;
+ }
+ else
+ {
+ mip0 = new I;
+
+ CL_Error locate_err = mip0->Locate(iname,enum_id);
+
+ if (locate_err != CLE_OK)
+ {
+ delete mip0;
+ 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 (I::imode)
+ {
+ case CLM_GLOBALPALETTE:
+ case CLM_TLTPALETTE:
+ texformat = "Palettized Display";
+ 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",mip0->fname,texformat,I::bitsperpixel,redbits,greenbits,bluebits);
+ #endif
+
+ START_TIMER
+ D3I_FILE * fp = d3i_fopen(mip0->fname,"rb");
+ END_TIMER(OpenTime)
+
+ if (!fp)
+ {
+ #if OUTPUT_LOG
+ CL_LogFile.lputs("** ERROR: unable to open\n");
+ #endif
+ EXITONLOADFAIL(mip0->fname)
+ delete mip0;
+ return CLE_OPENERROR;
+ }
+
+ CL_Error load_err = mip0->Load_Image(fp);
+ START_TIMER
+ d3i_fclose(fp);
+ END_TIMER(CloseTime)
+
+ if (load_err != CLE_OK)
+ {
+ if (!flags.located) delete mip0;
+ #if OUTPUT_LOG
+ CL_LogFile.lputs("** ERROR: unable to read\n");
+ #endif
+ EXITONREADFAIL(mip0->fname)
+ return load_err;
+ }
+
+ TempList miplist(mip0);
+
+ width = mip0->width;
+ height = mip0->height;
+ size = mip0->size;
+
+ if (!flags.located)
+ {
+ if (fname) delete[] fname;
+ if (name) delete[] name;
+ fname = new char[strlen(mip0->fname)+1];
+ name = new char[strlen(mip0->name)+1];
+ strcpy(fname,mip0->fname);
+ strcpy(name,mip0->name);
+ }
+
+ for (int mip_idx = 1; mip_idx < 7; ++mip_idx)
+ {
+ I * mip_n;
+
+ mip_n = new I;
+ 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);
+
+ #if OUTPUT_LOG
+ char const * texformat;
+ unsigned int redbits = 8;
+ unsigned int greenbits = 8;
+ unsigned int bluebits = 8;
+ switch (I::imode)
+ {
+ case CLM_GLOBALPALETTE:
+ case CLM_TLTPALETTE:
+ texformat = "Palettized Display";
+ 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",mip_n->fname,texformat,I::bitsperpixel,redbits,greenbits,bluebits);
+ #endif
+
+ START_TIMER
+ fp = d3i_fopen(mip_n->fname,"rb");
+ END_TIMER(OpenTime)
+
+ if (!fp)
+ {
+ delete mip_n;
+ #if OUTPUT_LOG
+ CL_LogFile.lputs("** Warning: unable to open\n");
+ #endif
+ break;
+ }
+
+ load_err = mip_n->Load_Image(fp);
+ START_TIMER
+ d3i_fclose(fp);
+ END_TIMER(CloseTime)
+
+ if (load_err != CLE_OK)
+ {
+ delete mip_n;
+ #if OUTPUT_LOG
+ CL_LogFile.lputs("** Warning: unable to read\n");
+ #endif
+ 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;
+ }
+
+ miplist += mip_n;
+ }
+
+ if (mipmaps)
+ {
+ for (int i = 0; i<num_mipmaps; ++i) delete mipmaps[i];
+ delete[] mipmaps;
+ }
+
+ num_mipmaps = miplist.n_entries;
+ mipmaps = new I * [num_mipmaps];
+
+ TempListMember * listP = miplist.first;
+ for (int i=0; i<num_mipmaps; ++i)
+ {
+ mipmaps[i] = listP->mip;
+ listP = listP->next;
+ }
+
+ flags.loaded = 1;
+ flags.located = 1;
+ return CLE_OK;
+ }
+
+ CL_Error PreLoad(char const * const iname, int const enum_id)
+ {
+ I * mip0 = new I;
+
+ CL_Error locate_err = mip0->Locate(iname,enum_id);
+
+ if (locate_err != CLE_OK)
+ {
+ delete mip0;
+ return locate_err;
+ }
+
+ if (fname) delete[] fname;
+ if (name) delete[] name;
+ fname = new char[strlen(mip0->fname)+1];
+ name = new char[strlen(mip0->name)+1];
+ strcpy(fname,mip0->fname);
+ strcpy(name,mip0->name);
+
+ if (mipmaps)
+ {
+ for (int i=0; i<num_mipmaps; ++i) delete mipmaps[i];
+ delete[] mipmaps;
+ }
+
+ num_mipmaps = 1;
+ mipmaps = new I * [1];
+ *mipmaps = mip0;
+
+ flags.loaded = 0;
+ flags.located = 1;
+
+ return CLE_OK;
+ }
+};
+#endif
+
+struct CL_Image
+{
+public:
+ static CL_ImageMode imode; // video mode defines which format images should be loaded
+ static CL_ImageMode imode_d3d; // video mode defines which format images should be loaded
+ static CL_ImageMode imode_ddraw; // video mode defines which format images should be loaded
+ static LPDDSURFACEDESC format;
+ static unsigned int bitsperpixel;
+ static unsigned int bitsperpixel_d3d;
+ static unsigned int bitsperpixel_ddraw;
+ static CL_LoadMode lmode;
+
+ // any one of these 3 may be valid
+ union
+ { // array of 24 bit or 32 bit pixels
+ CL_Pixel_24 * * im24; // array of 24 bit pixels
+ CL_Pixel_32 * * im32; // array of 32 bit pixels
+ // the data storage sizes of CL_Pixel_24 and CL_Pixel_32 must match
+ };
+ union
+ {
+ CL_Pixel_16 * * im16; // array of 16 bit pixels
+ unsigned short * * im16raw; // raw double-byte pixel data
+ };
+ unsigned char * * im8; // array of entrys into CLUT
+
+ unsigned int palette_size;
+ CL_Pixel_24 * palette; // CLUT (applicable only if 'im8' is valid)
+
+ unsigned int width;
+ unsigned int height;
+ unsigned int size; // width * height
+
+ char * fname; // full name of image including directory/path and extension
+ char * name; // name of image without directory/path or extension
+
+ List<CL_Image *> mipmaps;
+
+ CL_Image() : im8(0),im16(0),im24(0),palette(0),palette_size(0),fname(0),name(0) {}
+ virtual ~CL_Image();
+
+ CL_Image(CL_Image const &);
+ CL_Image & operator = (CL_Image const &);
+
+ inline CL_Error Load(char const * const iname) // looks at rif file and video mode to determine which file to load
+ {
+ return Load(iname,CL_EID_INVALID);
+ }
+ inline CL_Error Load(int const enum_id) // looks at rif file and video mode to determine which file to load
+ {
+ return Load(0,enum_id);
+ }
+ inline CL_Error Load() // assumes preload has been called
+ {
+ return Load(0,CL_EID_INVALID);
+ }
+
+ inline CL_Error PreLoad(char const * const iname) // looks at rif file and video mode to determine which file to load
+ {
+ return PreLoad(iname,CL_EID_INVALID);
+ }
+ inline CL_Error PreLoad(int const enum_id) // looks at rif file and video mode to determine which file to load
+ {
+ return PreLoad(0,enum_id);
+ }
+
+ CL_Error LoadMipMaps(int const n_mips = 7); // assumes locating has been done (ie. PreLoad or Load has been called)
+
+ CL_Error Load_BMP(D3I_FILE * f); // videomode != CLM_GLOBALPALETTE
+ CL_Error Load_PPM(D3I_FILE * f); // videomode == CLM_16BIT || CLM_24BIT
+ CL_Error Load_PGM(D3I_FILE * f); // videomode == CLM_GLOBALPALETTE
+ CL_Error Load_PWM(D3I_FILE * f); // videomode == CLM_GLOBALPALETTE
+
+ CL_Error Load_Image(D3I_FILE * f); // calls one of the above if correct format
+
+ CL_Error GetBitsPerPixel(unsigned int* bpp); //returns bitsperpixel;
+
+ // needs CL_Init_D3DMode((LPDDSURFACEDESC)format) to have been called
+ inline CL_Error CopyToD3DTexture(LPDIRECTDRAWSURFACE * const DDPtrA, LPVOID * const DDSurfaceA, int const MemoryType)
+ {
+ return CopyToD3DTexture(&DDPtrA,&DDSurfaceA,MemoryType);
+ }
+ CL_Error CopyToD3DTexture(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], int const MemoryType, unsigned int n_mips_max = 1);
+ // needs CL_Init_ScanDrawMode((CL_VideoMode) videomode) to have been called
+ inline CL_Error CopyToDirectDrawSurface(LPDIRECTDRAWSURFACE * const DDPtrA, LPVOID * const DDSurfaceA, int const MemoryType)
+ {
+ return CopyToDirectDrawSurface(&DDPtrA,&DDSurfaceA,MemoryType);
+ }
+ CL_Error CopyToDirectDrawSurface(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], int const MemoryType, unsigned int n_mips_max = 1);
+ // needs CL_Init_ScanDrawMode((CL_VideoMode) videomode) to have been called
+ inline CL_Error CopyToScanDrawTexture(unsigned char * * const ImagePtrA)
+ {
+ return CopyToScanDrawTexture(&ImagePtrA);
+ }
+ CL_Error CopyToScanDrawTexture(unsigned char * * const ImagePtrA [], unsigned int n_mips_max = 1);
+ // create an empty image for user manipulation
+ CL_Error Make(int const _width,int const _height);
+ // create an empty random image for user manipulation
+ CL_Error MakeRandom(int const _width,int const _height,int const seed = -1);
+ // ensure with and height are multiples of given units
+ void PadTo(int const width_unit,int const height_unit);
+
+ inline CL_Flags const & GetFlags() const
+ {
+ return flags;
+ }
+protected:
+ CL_Flags flags;
+
+ virtual CL_Error Locate(char const * iname, int const enum_id);
+ CL_Error Load(char const * const iname, int const enum_id);
+ CL_Error PreLoad(char const * const iname, int const enum_id);
+
+ CL_Error ReducePalette(unsigned int const num_colours);
+
+ // returns DDSURFACEDESC.lpSurface
+ // does what LoadPPMIntoDDSurface did
+ LPVOID CopyToDDSurface(LPDIRECTDRAWSURFACE lpDDS);
+
+private:
+ void Copy(CL_Image const &);
+ void Delete(void);
+ void DeleteNotMips(void);
+};
+
+#endif // !_included__d3_image_hpp_