deargui-vpl/ref/virtools/Samples/Plugins/DDS Reader/DDSReader.cpp

658 lines
17 KiB
C++

// DDSReader.cpp : Defines the entry point for the DLL application.
//
#include "DDSReader.h"
#include "dds.h"
#include "ddraw.h"
////////////////////////////////////////////////////////////////////
#ifdef USE_DX9
#include "d3dx9.h"
#define LPDIRECT3DDEVICE LPDIRECT3DDEVICE9
#define LPDIRECT3DTEXTURE LPDIRECT3DTEXTURE9
#define LPDIRECT3DSURFACE LPDIRECT3DSURFACE9
#define Direct3DCreate Direct3DCreate9
IDirect3D9* g_D3D = NULL;
IDirect3DDevice9* g_Device = NULL;
////////////////////////////////////////////////////////////////////
#else
#include "d3dx8.h"
#define LPDIRECT3DDEVICE LPDIRECT3DDEVICE8
#define LPDIRECT3DTEXTURE LPDIRECT3DTEXTURE8
#define LPDIRECT3DSURFACE LPDIRECT3DSURFACE8
#define Direct3DCreate Direct3DCreate8
IDirect3D8* g_D3D = NULL;
IDirect3DDevice8* g_Device = NULL;
#endif
#define READER_COUNT 1
#define DDS_READER_ID 0
/*********************************************************
Since we are using D3D8 for file io and format conversion
we need a IDirect3D8 interface created and destroyed with this DLL
**********************************************************/
#ifndef CK_LIB
BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_D3D = Direct3DCreate(D3D_SDK_VERSION);
if (!g_D3D) return FALSE;
break;
case DLL_PROCESS_DETACH:
if(g_Device) g_Device->Release();
if (g_D3D) g_D3D->Release();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
#endif
/************************************************************************
PLUGIN DECLARATION
**************************************************************************/
CKPluginInfo g_DDSReader_PInfo[READER_COUNT]={
CKPluginInfo( DDS_READER_GUID, // GUID
"Dds", // Extension supported
"Direct Draw Surface", // Reader Name
"Virtools", // Company
"Direct Draw Surface", // Summary String
DDS_READER_VERSION, // Reader Version
NULL, // No Init Instance function needed
NULL, // No Exit Instance function needed
CKPLUGIN_BITMAP_READER)}; // Plugin Type : Bitmap Reader
/**********************************************
Called by the engine when a file with the DDS
extension is being loaded, a reader has to be
created.
***********************************************/
#ifdef CK_LIB
CKDataReader *CKGet_DDSReader_Static(int pos)
#else
CKDataReader *CKGetReader(int pos)
#endif
{
switch(pos) {
case DDS_READER_ID: return new DDSReader(); break;
}
return NULL;
}
/******************************************
Returns information about the reader which
is the same as given to the engine at
initialisation.
*******************************************/
#ifndef CK_LIB
CKPluginInfo* CKGetPluginInfo(int index)
#else
CKPluginInfo* CKGet_DDSReader_PluginInfo(int index)
#endif
{
return &g_DDSReader_PInfo[index];
}
/************************************************************************
PLUGIN IMPLEMENTATION
**************************************************************************/
//-----------------------------------------
// Construction...
DDSReader::DDSReader()
{
m_Properties.m_Extension = "dds";
m_Properties.m_ReaderGuid = DDS_READER_GUID;
m_Properties.m_Data = NULL;
VxPixelFormat2ImageDesc(_32_ARGB8888,m_Properties.m_Format);
}
DDSReader::~DDSReader()
{
delete[] m_Properties.m_Data;
m_Properties.m_Data = NULL;
}
CKPluginInfo* DDSReader::GetReaderInfo()
{
return &g_DDSReader_PInfo[DDS_READER_ID];
}
//-----------------------------------------
// Get Options Count (1 in our case which is the
// pixel format when saving..)
int DDSReader::GetOptionsCount() { return 1; }
/*--------------------------------------------------
Get Options Description: Returns a string describing the
options this reader has when writing to file...
In this case we want to alias a DirectX enumeration (D3DFormat)
typedef enum _D3DFORMAT {
D3DFMT_R8G8B8 = 20,
D3DFMT_A8R8G8B8 = 21,
D3DFMT_R5G6B5 = 23,
D3DFMT_A1R5G5B5 = 25,
D3DFMT_A4R4G4B4 = 26,
D3DFMT_R3G3B2 = 27,
D3DFMT_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'),
D3DFMT_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'),
D3DFMT_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'),
D3DFMT_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'),
D3DFMT_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'),
} D3DFORMAT;
*/
CKSTRING
DDSReader::GetOptionDescription(int i)
{
static XString OptionsString;
OptionsString.Format("Enum:Pixel Format:"
"D3DFMT_R8G8B8=%d,"
"D3DFMT_A8R8G8B8=%d,"
"D3DFMT_R5G6B5=%d,"
"D3DFMT_A1R5G5B5=%d,"
"D3DFMT_A4R4G4B4=%d,"
"D3DFMT_R3G3B2=%d,"
"D3DFMT_DXT1=%d,"
"D3DFMT_DXT2=%d,"
"D3DFMT_DXT3=%d,"
"D3DFMT_DXT4=%d,"
"D3DFMT_DXT5=%d"
,D3DFMT_R8G8B8
,D3DFMT_A8R8G8B8
,D3DFMT_R5G6B5
,D3DFMT_A1R5G5B5
,D3DFMT_A4R4G4B4
,D3DFMT_R3G3B2
,D3DFMT_DXT1
,D3DFMT_DXT2
,D3DFMT_DXT3
,D3DFMT_DXT4
,D3DFMT_DXT5);
switch(i) {
case 0:
return OptionsString.Str();
break;
}
return "";
}
//-------------------------------------
// Alpha Support : This function must return
// whether the format stored in bp will handle
// alpha information..
CKBOOL DDSReader::IsAlphaSaved(CKBitmapProperties* bp)
{
// TODO : optimize...
DDSBitmapProperties dds_bp;
if(bp->m_Size == dds_bp.m_Size) { // It's a Jpg Properties
memcpy(&dds_bp,bp,bp->m_Size);
} else {
memcpy(&dds_bp,bp,sizeof(CKBitmapProperties));
}
switch ( dds_bp.m_PixelFormat) {
case D3DFMT_R8G8B8:
case D3DFMT_R5G6B5:
case D3DFMT_R3G3B2: return FALSE;
}
return TRUE;
}
BOOL CreateTemporaryDevice(LPDIRECT3DDEVICE* Device)
{
D3DDISPLAYMODE dispMode;
D3DPRESENT_PARAMETERS presentParams;
//----- Create a D3D Device for the time to load the file...
g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dispMode);
ZeroMemory(&presentParams, sizeof(presentParams));
presentParams.Windowed = TRUE;
#ifdef USE_DX9
presentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
#else
presentParams.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC;
#endif
presentParams.BackBufferWidth = 8;
presentParams.BackBufferHeight = 8;
presentParams.BackBufferFormat = dispMode.Format;
HRESULT res = g_D3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,GetDesktopWindow(),
D3DCREATE_MULTITHREADED|D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE,&presentParams,Device);
return SUCCEEDED(res);
}
#define CLEANUPIFFAILED(res,error)\
if (FAILED(res)) {\
if (Surface) Surface->Release();\
if (TextureSurface) TextureSurface->Release();\
if (Texture) Texture->Release();\
return error;\
}\
/************************************************************
Load a .dds file (from memory or from file)
*************************************************************/
CKERROR DDS_Read(void* memptr,int size,CKBitmapProperties* bp)
{
LPDIRECT3DTEXTURE Texture = NULL;
LPDIRECT3DSURFACE Surface = NULL;
LPDIRECT3DSURFACE TextureSurface = NULL;
HRESULT res;
#ifdef CK_LIB
if (!g_D3D) {
g_D3D = Direct3DCreate(D3D_SDK_VERSION);
}
#endif
if(!g_Device){
CreateTemporaryDevice(&g_Device);
}
//-------- Create a texture from this file
if (!size) {
// Loads from a file
//res = D3DXCreateTextureFromFile(Device,(char *)memptr,&Texture);
res = D3DXCreateTextureFromFileEx(g_Device,(char *)memptr,D3DX_DEFAULT,D3DX_DEFAULT,1,0,
D3DFMT_UNKNOWN,D3DPOOL_SCRATCH ,D3DX_DEFAULT,D3DX_DEFAULT,0x00000000,NULL,NULL,&Texture);
} else {
// Loads from a file in a memory buffer
//res = D3DXCreateTextureFromFileInMemory(Device,memptr,size,&Texture);
res = D3DXCreateTextureFromFileInMemoryEx(g_Device,(char *)memptr,size,D3DX_DEFAULT,D3DX_DEFAULT,1,0,
D3DFMT_UNKNOWN,D3DPOOL_SCRATCH ,D3DX_DEFAULT,D3DX_DEFAULT,0x00000000,NULL,NULL,&Texture);
}
CLEANUPIFFAILED(res,CKBITMAPERROR_READERROR);
D3DSURFACE_DESC TextureDesc;
Texture->GetLevelDesc(0,&TextureDesc);
VX_PIXELFORMAT vpf = VxImageDesc2PixelFormat(((CKBitmapProperties*)bp)->m_Format);
D3DFORMAT dpf = DDS_VxPixelFormatToD3DFormat(vpf);
vpf = DDS_D3DFormatToVxPixelFormat(dpf);
if(TextureDesc.Format != dpf){
//--- Create a surface to perform conversion from the loaded image..
VxPixelFormat2ImageDesc(vpf,((CKBitmapProperties*)bp)->m_Format);
#ifdef USE_DX9
res = g_Device->CreateOffscreenPlainSurface(TextureDesc.Width, TextureDesc.Height, dpf, D3DPOOL_SCRATCH, &Surface, NULL);
#else
res = g_Device->CreateImageSurface(TextureDesc.Width,TextureDesc.Height,dpf,&Surface);
#endif
CLEANUPIFFAILED(res,CKBITMAPERROR_READERROR);
res= Texture->GetSurfaceLevel(0,&TextureSurface);
CLEANUPIFFAILED(res,CKBITMAPERROR_READERROR);
res= D3DXLoadSurfaceFromSurface(Surface,NULL,NULL,TextureSurface,NULL,NULL,D3DX_FILTER_NONE,0);
TextureSurface->Release();
TextureSurface = NULL;
CLEANUPIFFAILED(res,CKBITMAPERROR_READERROR);
}else{
Texture->GetSurfaceLevel(0,&Surface);
}
//--------- Copy bits from DX surface to our surface...
D3DLOCKED_RECT src;
res= Surface->LockRect(&src,NULL,D3DLOCK_READONLY);
CLEANUPIFFAILED(res,CKBITMAPERROR_READERROR);
//-------- Create the Image in virtools format
VxPixelFormat2ImageDesc(vpf,bp->m_Format);
bp->m_Format.Width = TextureDesc.Width;
bp->m_Format.Height = TextureDesc.Height;
bp->m_Format.BytesPerLine = TextureDesc.Width*(bp->m_Format.BitsPerPixel/8);
BYTE* memory = NULL;
if(bp->m_Format.BytesPerLine){
memory = new BYTE[ bp->m_Format.BytesPerLine * bp->m_Format.Height ];
}else{
memory = new BYTE[ src.Pitch/4 * bp->m_Format.Height ];
}
BYTE* Src = (BYTE *)src.pBits;
BYTE* Dst = memory;
bp->m_Data = memory;
if(bp->m_Format.BytesPerLine){
for (unsigned int i = 0; i< TextureDesc.Height; ++i,Src+=src.Pitch,Dst+=bp->m_Format.BytesPerLine) {
memcpy(Dst,Src,bp->m_Format.BytesPerLine);
}
}else{
memcpy(Dst,Src,src.Pitch/4 * bp->m_Format.Height);
}
Surface->UnlockRect();
Surface->Release();
Texture->Release();
#ifdef CK_LIB
if(g_Device) {
g_Device->Release();
g_Device=NULL;
}
if (g_D3D) {
g_D3D->Release();
g_D3D=NULL;
}
#endif
return 0;
}
///------------------------------------------------------------
// Saving Functions
int DDS_Save(void** memptr,DDSBitmapProperties* bp)
{
LPDIRECT3DTEXTURE Texture = NULL;
LPDIRECT3DSURFACE Surface = NULL;
LPDIRECT3DSURFACE TextureSurface = NULL;
HRESULT res;
if(!g_Device){
CreateTemporaryDevice(&g_Device);
}
//--- Source format can only be a 32 bits image
// if (bp->m_Format.BitsPerPixel != 32) return 0;
D3DFORMAT fmt = DDS_VxPixelFormatToD3DFormat(VxImageDesc2PixelFormat(bp->m_Format));
//---- Create Source image surface
#ifdef USE_DX9
res = g_Device->CreateOffscreenPlainSurface(bp->m_Format.Width, bp->m_Format.Height, fmt, D3DPOOL_SCRATCH, &Surface, NULL);
#else
res = g_Device->CreateImageSurface(bp->m_Format.Width,bp->m_Format.Height,fmt,&Surface);
#endif
CLEANUPIFFAILED(res,0);
//--------- Copy bits from our surface to DX 32 bit surface
D3DLOCKED_RECT SrcLock;
res= Surface->LockRect(&SrcLock,NULL,0 );
CLEANUPIFFAILED(res,CKBITMAPERROR_READERROR);
BYTE* Src = (BYTE *)bp->m_Data;
BYTE* Dst = (BYTE*)SrcLock.pBits;
if(bp->m_Format.BytesPerLine){
for (int i = 0; i< bp->m_Format.Height; ++i,Src+=SrcLock.Pitch,Dst+=bp->m_Format.BytesPerLine) {
memcpy(Dst,Src,bp->m_Format.BytesPerLine);
}
}else{
memcpy(Dst,Src,SrcLock.Pitch/4 * bp->m_Format.Height);
}
Surface->UnlockRect();
if(bp->m_PixelFormat != fmt){
//---- Create destnation image surface
#ifdef USE_DX9
res = g_Device->CreateOffscreenPlainSurface(bp->m_Format.Width, bp->m_Format.Height, bp->m_PixelFormat, D3DPOOL_SCRATCH, &TextureSurface, NULL);
#else
res = g_Device->CreateImageSurface(bp->m_Format.Width,bp->m_Format.Height,bp->m_PixelFormat,&TextureSurface);
#endif
CLEANUPIFFAILED(res,0);
//---- Convert formats
res= D3DXLoadSurfaceFromSurface(TextureSurface,NULL,NULL,Surface,NULL,NULL,D3DX_FILTER_NONE,0);
CLEANUPIFFAILED(res,CKBITMAPERROR_READERROR);
}else{
TextureSurface = Surface;
Surface->AddRef();
}
//---- And Save
D3DSURFACE_DESC Desc;
TextureSurface->GetDesc(&Desc);
//--------- Copy bits from DX surface to a DDS file buffer...
D3DLOCKED_RECT Dest;
res = TextureSurface->LockRect(&Dest,NULL,D3DLOCK_READONLY);
//-- Prepare a big buffer to store the file
#ifdef USE_DX9
int DataSize = Dest.Pitch * Desc.Height;
if ( bp->m_PixelFormat == D3DFMT_DXT1 )
DataSize = max(1, Desc.Width/4) * max(1,Desc.Height/4) * 8;
else if ( (bp->m_PixelFormat == D3DFMT_DXT2) ||
(bp->m_PixelFormat == D3DFMT_DXT3) ||
(bp->m_PixelFormat == D3DFMT_DXT4) ||
(bp->m_PixelFormat == D3DFMT_DXT5) )
DataSize = max(1, Desc.Width/4) * max(1, Desc.Height/4) * 16;
#else
int DataSize = Desc.Size;
#endif
DWORD FileSize = 4 + sizeof(DDS_HEADER) + DataSize;
BYTE* FileData = new BYTE[FileSize];
//memset(&FileData[4 + sizeof(DDS_HEADER)],0xFF,Desc.Size);
memcpy(&FileData[4 + sizeof(DDS_HEADER)],Dest.pBits,DataSize);
TextureSurface->UnlockRect();
//---- Release all Dx Objects...
Surface->Release();
TextureSurface->Release();
//------ Now write Header
DWORD MagicDword = MAKEFOURCC('D','D','S',' ');
DDS_HEADER Header;
memset(&Header,0,sizeof(Header));
BOOL Compressed = ((bp->m_PixelFormat == D3DFMT_DXT1) ||
(bp->m_PixelFormat == D3DFMT_DXT2) ||
(bp->m_PixelFormat == D3DFMT_DXT3) ||
(bp->m_PixelFormat == D3DFMT_DXT4) ||
(bp->m_PixelFormat == D3DFMT_DXT5));
Header.dwSize = 124;
Header.dwHeaderFlags = DDSD_CAPS|DDSD_PIXELFORMAT|DDSD_WIDTH|DDSD_HEIGHT;
if (Compressed) {
Header.dwHeaderFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
} else {
Header.dwHeaderFlags |= DDS_HEADER_FLAGS_PITCH;
}
Header.dwHeight = bp->m_Format.Height;
Header.dwWidth = bp->m_Format.Width;
Header.dwPitchOrLinearSize = Compressed ? DataSize : Dest.Pitch;
Header.dwSurfaceFlags = DDSCAPS_TEXTURE;
//--- Pixel Format
Header.ddspf.dwSize = 32;
if (Compressed) {
Header.ddspf.dwFlags = DDPF_FOURCC;
Header.ddspf.dwFourCC = bp->m_PixelFormat;
} else {
switch ( bp->m_PixelFormat) {
case D3DFMT_R8G8B8:
case D3DFMT_R5G6B5:
case D3DFMT_R3G3B2:
Header.ddspf.dwFlags = DDS_RGB;
break;
default:
Header.ddspf.dwFlags = DDS_RGBA;
break;
}
VxImageDescEx TempFormat;
VxPixelFormat2ImageDesc(DDS_D3DFormatToVxPixelFormat(bp->m_PixelFormat),TempFormat);
Header.ddspf.dwRGBBitCount = TempFormat.BitsPerPixel;
Header.ddspf.dwRBitMask = TempFormat.RedMask;
Header.ddspf.dwGBitMask = TempFormat.GreenMask;
Header.ddspf.dwBBitMask = TempFormat.BlueMask;
Header.ddspf.dwABitMask = TempFormat.AlphaMask;
}
//----- And Write to buffer
memcpy(FileData,&MagicDword,sizeof(DWORD));
memcpy(&FileData[4],&Header,sizeof(Header));
//---- File ? or memory
if (*memptr == NULL) {
// Memory
*memptr = FileData;
} else{
// File
XString filename = (char*)*memptr;
filename.CheckFileNameValidity();
FILE* f = fopen(filename.Str(),"wb");
if (!f) {
delete[] FileData;
return 0;
}
fwrite(FileData,FileSize,1,f);
fclose(f);
}
return FileSize;
}
///-----------------------------------------------
// Loading Functions
// Synchronous Reading from file or URL
int DDSReader::ReadFile(char* name,CKBitmapProperties** bp)
{
if (!name || !bp) return CKBITMAPERROR_GENERIC;
CKERROR ret=DDS_Read(name,0,&m_Properties);
*bp=&m_Properties;
return ret;
}
// Synchronous Reading from memory
int DDSReader::ReadMemory(void* memory,int size,CKBitmapProperties** bp)
{
if (!bp) return CKBITMAPERROR_GENERIC;
CKERROR ret=DDS_Read(memory,size,&m_Properties);
*bp=&m_Properties;
return ret;
}
///-----------------------------------------------
// Saving Functions
// Synchronous Reading from file or URL
int DDSReader::SaveFile(char* name,CKBitmapProperties* bp)
{
if (!name || !bp) return 0;
DDSBitmapProperties jbp;
if(bp->m_Size == jbp.m_Size) { // It's a Bmp Properties
memcpy(&jbp,bp,bp->m_Size);
} else {
memcpy(&jbp,bp,sizeof(CKBitmapProperties));
}
return DDS_Save((void**)&name,&jbp);
}
// Synchronous Reading from memory, return number of bytes written
int DDSReader::SaveMemory(void** memory,CKBitmapProperties* bp)
{
if (!memory || !bp) return 0;
DDSBitmapProperties jbp;
if(bp->m_Size == jbp.m_Size) { // It's a DDS Properties
memcpy(&jbp,bp,bp->m_Size);
} else {
memcpy(&jbp,bp,sizeof(CKBitmapProperties));
}
*memory=NULL;
return DDS_Save(memory,&jbp);
}
///-----------------------------------------------
// Image Properties
void DDSReader::SetBitmapDefaultProperties(CKBitmapProperties* bm)
{
if(bm->m_Size == m_Properties.m_Size) {
// It's a valid DDS Properties we can copy our properties
memcpy(&m_Properties,bm,bm->m_Size);
} else {
memcpy(&m_Properties,bm,sizeof(CKBitmapProperties));
}
}
void DDSReader::GetBitmapDefaultProperties(CKBitmapProperties** bm)
{
// We return the properties
*bm = &m_Properties;
}
//--------------------------------------------
// Cleaning
void DDSReader::ReleaseMemory(void* memory)
{
delete [] memory;
}
void DDSReader::Release()
{
delete this;
}