avp/3dc/win95/D3_IMAGE.HPP
Rebellion Developments 218ca90543 Import Aliens vs Predator - Gold (Build 116)
Source code release, imported from:
https://www.gamefront.com/games/aliens-vs-predator-3/file/avp-gold-complete-source-code

All text files were converted to Unix format.
2019-08-19 05:45:17 +02:00

1223 lines
30 KiB
C++

#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_