Blame |
Last modification |
View Log
| RSS feed
#include "D3DInterface.h"
#include "DDInterface.h"
#include "Graphics.h"
#include "DirectXErrorString.h"
#include "SexyMatrix.h"
#include "SexyAppBase.h"
#include "TriVertex.h"
#include <assert.h>
#include <algorithm>
#pragma warning(disable:4244)
using namespace Sexy;
static int gMinTextureWidth;
static int gMinTextureHeight;
static int gMaxTextureWidth;
static int gMaxTextureHeight;
static int gMaxTextureAspectRatio;
static DWORD gSupportedPixelFormats;
static bool gTextureSizeMustBePow2;
static const int MAX_TEXTURE_SIZE = 1024;
static bool gLinearFilter = false;
std::string D3DInterface::mErrorString;
static const int gVertexType = D3DFVF_TLVERTEX;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void DisplayError(HRESULT theError, const char *theMsg)
{
static bool hadError = false;
if (!hadError)
{
std::string aMsg;
std::string anError = GetDirectXErrorString(theError);
aMsg = theMsg;
aMsg += ": ";
aMsg += anError;
hadError = true;
int aResult = MessageBoxA(NULL,aMsg.c_str(),"Error",MB_ABORTRETRYIGNORE);
if (aResult==IDABORT)
exit(0);
else if (aResult==IDRETRY)
_asm int 3;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool D3DInterface::CheckDXError(HRESULT theError, const char *theMsg)
{
if(FAILED(theError))
{
std::string aMsg;
std::string anError = GetDirectXErrorString(theError);
aMsg = theMsg;
aMsg += ": ";
aMsg += anError;
mErrorString = aMsg;
gSexyAppBase->RegistryWriteString("Test3D\\RuntimeError",aMsg);
// DisplayError(theError,theMsg);
return true;
}
else
return false;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
D3DInterface::D3DInterface()
{
mHWnd = NULL;
mWidth = 640;
mHeight = 480;
mDD = NULL;
mDDSDrawSurface = NULL;
mZBuffer = NULL;
mD3D = NULL;
mD3DDevice = NULL;
//mD3DViewport = NULL;
mSceneBegun = false;
mIsWindowed = true;
gMinTextureWidth = 64;
gMinTextureHeight = 64;
gMaxTextureWidth = 64;
gMaxTextureHeight = 64;
gMaxTextureAspectRatio = 1;
/*
//Test Transform
SexyTransform2D aTrans;
aTrans.Translate(-320,-240);
aTrans.Rotate(45*3.14159f/180);
// aTrans.Scale(1.3f,1.3f);
aTrans.Translate(320,240);
PushTransform(aTrans);
*/
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
D3DInterface::~D3DInterface()
{
Cleanup();
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::MakeDDPixelFormat(PixelFormat theFormatType, DDPIXELFORMAT* theFormat)
{
ZeroMemory(theFormat,sizeof(DDPIXELFORMAT));
theFormat->dwSize = sizeof(DDPIXELFORMAT);
switch(theFormatType)
{
case PixelFormat_A8R8G8B8:
theFormat->dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB;
theFormat->dwRGBBitCount = 32;
theFormat->dwRGBAlphaBitMask = 0xFF000000;
theFormat->dwRBitMask = 0x00FF0000;
theFormat->dwGBitMask = 0x0000FF00;
theFormat->dwBBitMask = 0x000000FF;
break;
case PixelFormat_A4R4G4B4:
theFormat->dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB;
theFormat->dwRGBBitCount = 16;
theFormat->dwRGBAlphaBitMask = 0xF000;
theFormat->dwRBitMask = 0x0F00;
theFormat->dwGBitMask = 0x00F0;
theFormat->dwBBitMask = 0x000F;
break;
case PixelFormat_R5G6B5:
theFormat->dwFlags = DDPF_RGB;
theFormat->dwRGBBitCount = 16;
theFormat->dwRBitMask = 0xF800;
theFormat->dwGBitMask = 0x07E0;
theFormat->dwBBitMask = 0x001F;
break;
case PixelFormat_Palette8:
theFormat->dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
theFormat->dwRGBBitCount = 8;
break;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
PixelFormat D3DInterface::GetDDPixelFormat(LPDDPIXELFORMAT theFormat)
{
if (theFormat->dwFlags == (DDPF_ALPHAPIXELS | DDPF_RGB) &&
theFormat->dwRGBBitCount == 32 &&
theFormat->dwRGBAlphaBitMask == 0xFF000000 &&
theFormat->dwRBitMask == 0x00FF0000 &&
theFormat->dwGBitMask == 0x0000FF00 &&
theFormat->dwBBitMask == 0x000000FF)
{
return PixelFormat_A8R8G8B8;
}
if (theFormat->dwFlags == (DDPF_ALPHAPIXELS | DDPF_RGB) &&
theFormat->dwRGBBitCount == 16 &&
theFormat->dwRGBAlphaBitMask == 0xF000 &&
theFormat->dwRBitMask == 0x0F00 &&
theFormat->dwGBitMask == 0x00F0 &&
theFormat->dwBBitMask == 0x000F)
{
return PixelFormat_A4R4G4B4;
}
if (theFormat->dwFlags == DDPF_RGB &&
theFormat->dwRGBBitCount == 16 &&
theFormat->dwRGBAlphaBitMask == 0x0000 &&
theFormat->dwRBitMask == 0xF800 &&
theFormat->dwGBitMask == 0x07E0 &&
theFormat->dwBBitMask == 0x001F)
{
return PixelFormat_R5G6B5;
}
if (theFormat->dwFlags == (DDPF_RGB | DDPF_PALETTEINDEXED8) &&
theFormat->dwRGBBitCount == 8)
{
return PixelFormat_Palette8;
}
return PixelFormat_Unknown;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
HRESULT CALLBACK D3DInterface::PixelFormatsCallback(LPDDPIXELFORMAT theFormat, LPVOID lpContext)
{
gSupportedPixelFormats |= D3DInterface::GetDDPixelFormat(theFormat);
return D3DENUMRET_OK;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::UpdateViewport()
{
HRESULT hr;
RECT aRect;
GetClientRect(mHWnd, &aRect);
POINT aTopLeft = {aRect.left, aRect.top};
POINT aBotRight = {aRect.right, aRect.bottom};
::ClientToScreen(mHWnd, &aTopLeft);
::ClientToScreen(mHWnd, &aBotRight);
RECT aScreenRect = {aTopLeft.x, aTopLeft.y, aBotRight.x, aBotRight.y};
D3DVIEWPORT7 &aD3DViewport = mD3DViewport;
aD3DViewport.dwX = 0;
aD3DViewport.dwY = 0;
aD3DViewport.dwWidth = aScreenRect.right - aScreenRect.left;
aD3DViewport.dwHeight = aScreenRect.bottom - aScreenRect.top;
aD3DViewport.dvMinZ = 0; //-2048.0f;
aD3DViewport.dvMaxZ = 1; //2048.0f;
hr = mD3DDevice->SetViewport(&mD3DViewport);
}
//-----------------------------------------------------------------------------
// Name: EnumZBufferCallback()
// Desc: Enumeration function to report valid pixel formats for z-buffers.
//-----------------------------------------------------------------------------
static HRESULT WINAPI EnumZBufferCallback( DDPIXELFORMAT* pddpf, VOID* pddpfDesired )
{
if( pddpf->dwFlags == DDPF_ZBUFFER )
{
memcpy( pddpfDesired, pddpf, sizeof(DDPIXELFORMAT) );
return D3DENUMRET_CANCEL;
}
return D3DENUMRET_OK;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool D3DInterface::InitD3D()
{
if(CheckDXError(mDD->QueryInterface(IID_IDirect3D7, (LPVOID*) &mD3D),"QueryInterface IID_IDirect3D7"))
return false;
if(CheckDXError(mD3D->CreateDevice(IID_IDirect3DHALDevice, mDDSDrawSurface, &mD3DDevice),"CreateDevice IID_IDirect3DHALDevice"))
return false;
D3DDEVICEDESC7 aCaps;
ZeroMemory(&aCaps,sizeof(aCaps));
if(CheckDXError(mD3DDevice->GetCaps(&aCaps)))
return false;
gTextureSizeMustBePow2 = aCaps.dpcTriCaps.dwTextureCaps&D3DPTEXTURECAPS_NONPOW2CONDITIONAL?false:true;
gMinTextureWidth = aCaps.dwMinTextureWidth;
gMinTextureHeight = aCaps.dwMinTextureHeight;
gMaxTextureWidth = aCaps.dwMaxTextureWidth;
gMaxTextureHeight = aCaps.dwMaxTextureHeight;
gMaxTextureAspectRatio = aCaps.dwMaxTextureAspectRatio;
gLinearFilter = false;
if (gMaxTextureWidth==0) // the card is not filling in these values so default them to something that will work
{
gMaxTextureWidth = 64;
gMaxTextureHeight = 64;
gMinTextureWidth = 64;
gMinTextureHeight = 64;
gMaxTextureAspectRatio = 1;
}
if (gMaxTextureWidth > MAX_TEXTURE_SIZE)
gMaxTextureWidth = MAX_TEXTURE_SIZE;
if (gMaxTextureHeight > MAX_TEXTURE_SIZE)
gMaxTextureHeight = MAX_TEXTURE_SIZE;
if (gMinTextureWidth < 1)
gMinTextureWidth = 1;
if (gMinTextureHeight < 1)
gMinTextureWidth = 1;
if (gMaxTextureAspectRatio==0)
gMaxTextureAspectRatio = 65536;
gSupportedPixelFormats = 0;
mD3DDevice->EnumTextureFormats(PixelFormatsCallback,NULL);
/* if (!(gSupportedPixelFormats & PixelFormat_A8R8G8B8))
{
mErrorString = "A8R8G8B8 texture format not supported.";
return false;
}*/
if (!(aCaps.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE)) // need alpha in palettes
gSupportedPixelFormats &= ~PixelFormat_Palette8;
UpdateViewport();
// Create ZBuffer
DDPIXELFORMAT ddpfZBuffer;
mD3D->EnumZBufferFormats( IID_IDirect3DHALDevice, EnumZBufferCallback, (VOID*)&ddpfZBuffer );
DDSURFACEDESC2 ddsd;
ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2) );
ddsd.dwSize = sizeof(DDSURFACEDESC2);
ddsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY;
ddsd.dwWidth = mD3DViewport.dwWidth;
ddsd.dwHeight = mD3DViewport.dwHeight;
memcpy( &ddsd.ddpfPixelFormat, &ddpfZBuffer, sizeof(DDPIXELFORMAT) );
/*
// Create z-buffer
if( CheckDXError(mDD->CreateSurface( &ddsd, &mZBuffer, NULL ) ) )
return false;
// Attach the z-buffer to the back buffer.
if( CheckDXError( mDDSDrawSurface->AddAttachedSurface( mZBuffer ) ) )
return false;*/
mD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET ,0xff000000, 1.0f, 0L);
return true;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool D3DInterface::InitFromDDInterface(DDInterface *theInterface)
{
mErrorString.erase();
mDD = theInterface->mDD7;
mHWnd = theInterface->mHWnd;
mWidth = theInterface->mWidth;
mHeight = theInterface->mHeight;
if (CheckDXError(theInterface->mDrawSurface->QueryInterface(IID_IDirectDrawSurface7,(LPVOID*)&mDDSDrawSurface), "Query DrawSurface"))
return false;
mIsWindowed = theInterface->mIsWindowed;
return InitD3D();
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool gD3DInterfacePreDrawError = false;
bool D3DInterface::PreDraw()
{
if (gSexyAppBase->mPhysMinimized)
return false;
if (!mSceneBegun)
{
HRESULT hr;
if (!SUCCEEDED(mD3DDevice->SetRenderTarget(mDDSDrawSurface, 0))) // this happens when there's been a mode switch (this caused the nvidia screensaver bluescreen)
{
gD3DInterfacePreDrawError = true;
return false;
}
else
gD3DInterfacePreDrawError = false;
// mD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET ,0xff000000, 1.0f, 0L);
hr = mD3DDevice->BeginScene();
// alphablend states
mD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
mD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
mD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
mD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING , FALSE);
// filter states
mD3DDevice->SetTextureStageState(0,D3DTSS_MINFILTER, D3DTFG_POINT);
mD3DDevice->SetTextureStageState(0,D3DTSS_MAGFILTER, D3DTFG_POINT);
mD3DDevice->SetTextureStageState(0,D3DTSS_MIPFILTER, D3DTFG_POINT);
// mD3DDevice->SetTextureStageState(0,D3DTSS_COLORARG2, D3DTA_CURRENT );
// mD3DDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2, D3DTA_CURRENT );
// mD3DDevice->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE );
// mD3DDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
// mD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP , D3DTOP_MODULATE );
mD3DDevice->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_MODULATE );
mD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
hr = mD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
// Setup non-texture render states
mD3DDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, FALSE);
mD3DDevice->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, FALSE);
mD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
mD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
hr = mD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
mSceneBegun = true;
gLinearFilter = false;
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static LPDIRECTDRAWSURFACE7 CreateTextureSurface(LPDIRECT3DDEVICE7 theDevice, LPDIRECTDRAW7 theDraw, int theWidth, int theHeight, PixelFormat theFormat)
{
if (D3DInterface::CheckDXError(theDevice->SetTexture(0, NULL),"SetTexture NULL"))
return NULL;
DDSURFACEDESC2 aDesc;
LPDIRECTDRAWSURFACE7 aSurface;
ZeroMemory(&aDesc, sizeof(aDesc));
aDesc.dwSize = sizeof(aDesc);
aDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
aDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
// aDesc.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
aDesc.ddsCaps.dwCaps2 = DDSCAPS2_D3DTEXTUREMANAGE;
aDesc.dwWidth = theWidth;
aDesc.dwHeight = theHeight;
aDesc.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
D3DInterface::MakeDDPixelFormat(theFormat, &aDesc.ddpfPixelFormat);
// D3DXMakeDDPixelFormat(theFormat, &aDesc.ddpfPixelFormat);
HRESULT hr = theDraw->CreateSurface(&aDesc, &aSurface, NULL);
if (FAILED(hr))
{
std::string anError = GetDirectXErrorString(hr);
return NULL;
}
return aSurface;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void CopyImageToTexture8888(void *theDest, DWORD theDestPitch, MemoryImage *theImage, int offx, int offy, int theWidth, int theHeight, bool rightPad)
{
if (theImage->mColorTable == NULL)
{
DWORD *srcRow = theImage->GetBits() + offy * theImage->GetWidth() + offx;
char *dstRow = (char*)theDest;
for(int y=0; y<theHeight; y++)
{
DWORD *src = srcRow;
DWORD *dst = (DWORD*)dstRow;
for(int x=0; x<theWidth; x++)
{
*dst++ = *src++;
}
if (rightPad)
*dst = *(dst-1);
srcRow += theImage->GetWidth();
dstRow += theDestPitch;
}
}
else // palette
{
uchar *srcRow = (uchar*)theImage->mColorIndices + offy * theImage->GetWidth() + offx;
uchar *dstRow = (uchar*)theDest;
DWORD *palette = theImage->mColorTable;
for(int y=0; y<theHeight; y++)
{
uchar *src = srcRow;
DWORD *dst = (DWORD*)dstRow;
for(int x=0; x<theWidth; x++)
*dst++ = palette[*src++];
if (rightPad)
*dst = *(dst-1);
srcRow += theImage->GetWidth();
dstRow += theDestPitch;
}
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void CopyTexture8888ToImage(void *theDest, DWORD theDestPitch, MemoryImage *theImage, int offx, int offy, int theWidth, int theHeight)
{
char *srcRow = (char*)theDest;
DWORD *dstRow = theImage->GetBits() + offy * theImage->GetWidth() + offx;
for(int y=0; y<theHeight; y++)
{
DWORD *src = (DWORD*)srcRow;
DWORD *dst = dstRow;
for(int x=0; x<theWidth; x++)
*dst++ = *src++;
dstRow += theImage->GetWidth();
srcRow += theDestPitch;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void CopyImageToTexture4444(void *theDest, DWORD theDestPitch, MemoryImage *theImage, int offx, int offy, int theWidth, int theHeight, bool rightPad)
{
if (theImage->mColorTable == NULL)
{
DWORD *srcRow = theImage->GetBits() + offy * theImage->GetWidth() + offx;
char *dstRow = (char*)theDest;
for(int y=0; y<theHeight; y++)
{
DWORD *src = srcRow;
ushort *dst = (ushort*)dstRow;
for(int x=0; x<theWidth; x++)
{
DWORD aPixel = *src++;
*dst++ = ((aPixel>>16)&0xF000) | ((aPixel>>12)&0x0F00) | ((aPixel>>8)&0x00F0) | ((aPixel>>4)&0x000F);
}
if (rightPad)
*dst = *(dst-1);
srcRow += theImage->GetWidth();
dstRow += theDestPitch;
}
}
else // palette
{
uchar *srcRow = (uchar*)theImage->mColorIndices + offy * theImage->GetWidth() + offx;
uchar *dstRow = (uchar*)theDest;
DWORD *palette = theImage->mColorTable;
for(int y=0; y<theHeight; y++)
{
uchar *src = srcRow;
ushort *dst = (ushort*)dstRow;
for(int x=0; x<theWidth; x++)
{
DWORD aPixel = palette[*src++];
*dst++ = ((aPixel>>16)&0xF000) | ((aPixel>>12)&0x0F00) | ((aPixel>>8)&0x00F0) | ((aPixel>>4)&0x000F);
}
if (rightPad)
*dst = *(dst-1);
srcRow += theImage->GetWidth();
dstRow += theDestPitch;
}
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void CopyTexture4444ToImage(void *theDest, DWORD theDestPitch, MemoryImage *theImage, int offx, int offy, int theWidth, int theHeight)
{
char *srcRow = (char*)theDest;
DWORD *dstRow = theImage->GetBits() + offy * theImage->GetWidth() + offx;
for(int y=0; y<theHeight; y++)
{
ushort *src = (ushort*)srcRow;
DWORD *dst = dstRow;
for(int x=0; x<theWidth; x++)
{
ushort aPixel = *src++;
*dst++ = 0xFF000000 | ((aPixel & 0xF000) << 16) | ((aPixel & 0x0F00) << 12) | ((aPixel & 0x00F0) << 8) | ((aPixel & 0x000F) << 4);
}
dstRow += theImage->GetWidth();
srcRow += theDestPitch;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void CopyImageToTexture565(void *theDest, DWORD theDestPitch, MemoryImage *theImage, int offx, int offy, int theWidth, int theHeight, bool rightPad)
{
if (theImage->mColorTable == NULL)
{
DWORD *srcRow = theImage->GetBits() + offy * theImage->GetWidth() + offx;
char *dstRow = (char*)theDest;
for(int y=0; y<theHeight; y++)
{
DWORD *src = srcRow;
ushort *dst = (ushort*)dstRow;
for(int x=0; x<theWidth; x++)
{
DWORD aPixel = *src++;
*dst++ = ((aPixel>>8)&0xF800) | ((aPixel>>5)&0x07E0) | ((aPixel>>3)&0x001F);
}
if (rightPad)
*dst = *(dst-1);
srcRow += theImage->GetWidth();
dstRow += theDestPitch;
}
}
else // palette
{
uchar *srcRow = (uchar*)theImage->mColorIndices + offy * theImage->GetWidth() + offx;
uchar *dstRow = (uchar*)theDest;
DWORD *palette = theImage->mColorTable;
for(int y=0; y<theHeight; y++)
{
uchar *src = srcRow;
ushort *dst = (ushort*)dstRow;
for(int x=0; x<theWidth; x++)
{
DWORD aPixel = palette[*src++];
*dst++ = ((aPixel>>8)&0xF800) | ((aPixel>>5)&0x07E0) | ((aPixel>>3)&0x001F);
}
if (rightPad)
*dst = *(dst-1);
srcRow += theImage->GetWidth();
dstRow += theDestPitch;
}
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void CopyTexture565ToImage(void *theDest, DWORD theDestPitch, MemoryImage *theImage, int offx, int offy, int theWidth, int theHeight)
{
char *srcRow = (char*)theDest;
DWORD *dstRow = theImage->GetBits() + offy * theImage->GetWidth() + offx;
for(int y=0; y<theHeight; y++)
{
ushort *src = (ushort*)srcRow;
DWORD *dst = dstRow;
for(int x=0; x<theWidth; x++)
{
ushort aPixel = *src++;
*dst++ = 0xFF000000 | ((aPixel & 0xF800) << 8) | ((aPixel & 0x07E0) << 5) | ((aPixel & 0x001F) << 3);
}
dstRow += theImage->GetWidth();
srcRow += theDestPitch;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void CopyImageToTexturePalette8(void *theDest, DWORD theDestPitch, MemoryImage *theImage, int offx, int offy, int theWidth, int theHeight, bool rightPad)
{
uchar *srcRow = (uchar*)theImage->mColorIndices + offy * theImage->GetWidth() + offx;
uchar *dstRow = (uchar*)theDest;
for(int y=0; y<theHeight; y++)
{
uchar *src = srcRow;
uchar *dst = dstRow;
for(int x=0; x<theWidth; x++)
*dst++ = *src++;
if (rightPad)
*dst = *(dst-1);
srcRow += theImage->GetWidth();
dstRow += theDestPitch;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void CopyTexturePalette8ToImage(void *theDest, DWORD theDestPitch, MemoryImage *theImage, int offx, int offy, int theWidth, int theHeight, LPDIRECTDRAWPALETTE thePalette)
{
char *srcRow = (char*)theDest;
DWORD *dstRow = theImage->GetBits() + offy * theImage->GetWidth() + offx;
PALETTEENTRY aPaletteEntries[256];
thePalette->GetEntries(0, 0, 256, aPaletteEntries);
for(int y=0; y<theHeight; y++)
{
uchar *src = (uchar*) srcRow;
DWORD *dst = dstRow;
for(int x=0; x<theWidth; x++)
{
DWORD aPixel = *((DWORD*)(aPaletteEntries+*src++));
*dst++ = (aPixel&0xFF00FF00) | ((aPixel>>16)&0xFF) | ((aPixel<<16)&0xFF0000);
}
dstRow += theImage->GetWidth();
srcRow += theDestPitch;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void CopyImageToTexture(LPDIRECTDRAWSURFACE7 theTexture, MemoryImage *theImage, int offx, int offy, int texWidth, int texHeight, PixelFormat theFormat)
{
if (theTexture==NULL)
return;
DDSURFACEDESC2 aDesc;
aDesc.dwSize = sizeof(aDesc);
if (D3DInterface::CheckDXError(theTexture->Lock(NULL,&aDesc,DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_WRITEONLY,NULL),"Lock Texture"))
return;
int aWidth = min(texWidth,(theImage->GetWidth()-offx));
int aHeight = min(texHeight,(theImage->GetHeight()-offy));
bool rightPad = aWidth<texWidth;
bool bottomPad = aHeight<texHeight;
// if(aWidth < texWidth || aHeight < texHeight)
// memset(aDesc.lpSurface, 0, aDesc.lPitch*aDesc.dwHeight);
if(aWidth>0 && aHeight>0)
{
switch (theFormat)
{
case PixelFormat_A8R8G8B8: CopyImageToTexture8888(aDesc.lpSurface, aDesc.lPitch, theImage, offx, offy, aWidth, aHeight, rightPad); break;
case PixelFormat_A4R4G4B4: CopyImageToTexture4444(aDesc.lpSurface, aDesc.lPitch, theImage, offx, offy, aWidth, aHeight, rightPad); break;
case PixelFormat_R5G6B5: CopyImageToTexture565(aDesc.lpSurface, aDesc.lPitch, theImage, offx, offy, aWidth, aHeight, rightPad); break;
case PixelFormat_Palette8: CopyImageToTexturePalette8(aDesc.lpSurface, aDesc.lPitch, theImage, offx, offy, aWidth, aHeight, rightPad); break;
}
if (bottomPad)
{
uchar *dstrow = ((uchar*)aDesc.lpSurface)+aDesc.lPitch*aHeight;
memcpy(dstrow,dstrow-aDesc.lPitch,aDesc.lPitch);
}
}
D3DInterface::CheckDXError(theTexture->Unlock(NULL),"Texture Unlock");
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static int GetClosestPowerOf2Above(int theNum)
{
int aPower2 = 1;
while (aPower2 < theNum)
aPower2<<=1;
return aPower2;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static bool IsPowerOf2(int theNum)
{
int aNumBits = 0;
while (theNum>0)
{
aNumBits += theNum&1;
theNum >>= 1;
}
return aNumBits==1;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void GetBestTextureDimensions(int &theWidth, int &theHeight, bool isEdge, bool usePow2, DWORD theImageFlags)
{
// theImageFlags = D3DImageFlag_MinimizeNumSubdivisions;
if (theImageFlags & D3DImageFlag_Use64By64Subdivisions)
{
theWidth = theHeight = 64;
return;
}
static int aGoodTextureSize[MAX_TEXTURE_SIZE];
static bool haveInited = false;
if (!haveInited)
{
haveInited = true;
int i;
int aPow2 = 1;
for (i=0; i<MAX_TEXTURE_SIZE; i++)
{
if (i > aPow2)
aPow2 <<= 1;
int aGoodValue = aPow2;
if ((aGoodValue - i ) > 64)
{
aGoodValue >>= 1;
while (true)
{
int aLeftOver = i % aGoodValue;
if (aLeftOver<64 || IsPowerOf2(aLeftOver))
break;
aGoodValue >>= 1;
}
}
aGoodTextureSize[i] = aGoodValue;
}
}
int aWidth = theWidth;
int aHeight = theHeight;
if (usePow2)
{
if (isEdge || (theImageFlags & D3DImageFlag_MinimizeNumSubdivisions))
{
aWidth = aWidth >= gMaxTextureWidth ? gMaxTextureWidth : GetClosestPowerOf2Above(aWidth);
aHeight = aHeight >= gMaxTextureHeight ? gMaxTextureHeight : GetClosestPowerOf2Above(aHeight);
}
else
{
aWidth = aWidth >= gMaxTextureWidth ? gMaxTextureWidth : aGoodTextureSize[aWidth];
aHeight = aHeight >= gMaxTextureHeight ? gMaxTextureHeight : aGoodTextureSize[aHeight];
}
}
if (aWidth < gMinTextureWidth)
aWidth = gMinTextureWidth;
if (aHeight < gMinTextureHeight)
aHeight = gMinTextureHeight;
if (aWidth > aHeight)
{
while (aWidth > gMaxTextureAspectRatio*aHeight)
aHeight <<= 1;
}
else if (aHeight > aWidth)
{
while (aHeight > gMaxTextureAspectRatio*aWidth)
aWidth <<= 1;
}
theWidth = aWidth;
theHeight = aHeight;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
TextureData::TextureData()
{
mWidth = 0;
mHeight = 0;
mTexVecWidth = 0;
mTexVecHeight = 0;
mBitsChangedCount = 0;
mTexMemSize = 0;
mTexPieceWidth = 64;
mTexPieceHeight = 64;
mPalette = NULL;
mPixelFormat = PixelFormat_Unknown;
mImageFlags = 0;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
TextureData::~TextureData()
{
ReleaseTextures();
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void TextureData::ReleaseTextures()
{
for(int i=0; i<(int)mTextures.size(); i++)
{
LPDIRECTDRAWSURFACE7 aSurface = mTextures[i].mTexture;
if (aSurface!=NULL)
aSurface->Release();
}
mTextures.clear();
mTexMemSize = 0;
if (mPalette!=NULL)
{
mPalette->Release();
mPalette = NULL;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void TextureData::CreateTextureDimensions(MemoryImage *theImage)
{
int aWidth = theImage->GetWidth();
int aHeight = theImage->GetHeight();
int i;
/**/
// Calculate inner piece sizes
mTexPieceWidth = aWidth;
mTexPieceHeight = aHeight;
bool usePow2 = true; //gTextureSizeMustBePow2 || mPixelFormat==PixelFormat_Palette8;
GetBestTextureDimensions(mTexPieceWidth, mTexPieceHeight,false,usePow2,mImageFlags);
// Calculate right boundary piece sizes
int aRightWidth = aWidth%mTexPieceWidth;
int aRightHeight = mTexPieceHeight;
if (aRightWidth > 0)
GetBestTextureDimensions(aRightWidth, aRightHeight,true,usePow2,mImageFlags);
else
aRightWidth = mTexPieceWidth;
// Calculate bottom boundary piece sizes
int aBottomWidth = mTexPieceWidth;
int aBottomHeight = aHeight%mTexPieceHeight;
if (aBottomHeight > 0)
GetBestTextureDimensions(aBottomWidth, aBottomHeight,true,usePow2,mImageFlags);
else
aBottomHeight = mTexPieceHeight;
// Calculate corner piece size
int aCornerWidth = aRightWidth;
int aCornerHeight = aBottomHeight;
GetBestTextureDimensions(aCornerWidth, aCornerHeight,true,usePow2,mImageFlags);
/**/
// mTexPieceWidth = 64;
// mTexPieceHeight = 64;
// Allocate texture array
mTexVecWidth = (aWidth + mTexPieceWidth - 1)/mTexPieceWidth;
mTexVecHeight = (aHeight + mTexPieceHeight - 1)/mTexPieceHeight;
mTextures.resize(mTexVecWidth*mTexVecHeight);
// Assign inner pieces
for(i=0; i<(int)mTextures.size(); i++)
{
TextureDataPiece &aPiece = mTextures[i];
aPiece.mTexture = NULL;
aPiece.mWidth = mTexPieceWidth;
aPiece.mHeight = mTexPieceHeight;
}
// Assign right pieces
/**/
for(i=mTexVecWidth-1; i<(int)mTextures.size(); i+=mTexVecWidth)
{
TextureDataPiece &aPiece = mTextures[i];
aPiece.mWidth = aRightWidth;
aPiece.mHeight = aRightHeight;
}
// Assign bottom pieces
for(i=mTexVecWidth*(mTexVecHeight-1); i<(int)mTextures.size(); i++)
{
TextureDataPiece &aPiece = mTextures[i];
aPiece.mWidth = aBottomWidth;
aPiece.mHeight = aBottomHeight;
}
// Assign corner piece
mTextures.back().mWidth = aCornerWidth;
mTextures.back().mHeight = aCornerHeight;
/**/
mMaxTotalU = aWidth/(float)mTexPieceWidth;
mMaxTotalV = aHeight/(float)mTexPieceHeight;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void TextureData::CreateTextures(MemoryImage *theImage, LPDIRECT3DDEVICE7 theDevice, LPDIRECTDRAW7 theDraw)
{
theImage->DeleteSWBuffers(); // don't need these buffers for 3d drawing
// Choose appropriate pixel format
PixelFormat aFormat = PixelFormat_A8R8G8B8;
//theImage->mD3DFlags = D3DImageFlag_UseA4R4G4B4;
theImage->CommitBits();
if (!theImage->mHasAlpha && !theImage->mHasTrans && (gSupportedPixelFormats & PixelFormat_R5G6B5))
{
if (!(theImage->mD3DFlags & D3DImageFlag_UseA8R8G8B8))
aFormat = PixelFormat_R5G6B5;
}
LPDIRECTDRAWPALETTE aDDPalette = NULL;
if (theImage->mColorIndices != NULL && (gSupportedPixelFormats & PixelFormat_Palette8))
{
PALETTEENTRY aPalette[256];
for (int i=0; i<256; i++)
{
DWORD aPixel = theImage->mColorTable[i];
*(DWORD*)(aPalette+i) = (aPixel&0xFF00FF00) | ((aPixel>>16)&0xFF) | ((aPixel<<16)&0xFF0000);
}
HRESULT aResult = theDraw->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALPHA | DDPCAPS_ALLOW256,aPalette, &aDDPalette, NULL);
if (SUCCEEDED(aResult))
aFormat = PixelFormat_Palette8;
else
{
std::string anError = GetDirectXErrorString(aResult);
gSupportedPixelFormats &= ~PixelFormat_Palette8;
}
}
if ((theImage->mD3DFlags & D3DImageFlag_UseA4R4G4B4) && aFormat==PixelFormat_A8R8G8B8 && (gSupportedPixelFormats & PixelFormat_A4R4G4B4))
aFormat = PixelFormat_A4R4G4B4;
if (aFormat==PixelFormat_A8R8G8B8 && !(gSupportedPixelFormats & PixelFormat_A8R8G8B8))
aFormat = PixelFormat_A4R4G4B4;
// Release texture if image size has changed
bool createTextures = false;
if (mWidth!=theImage->mWidth || mHeight!=theImage->mHeight || aFormat!=mPixelFormat || theImage->mD3DFlags!=mImageFlags)
{
ReleaseTextures();
mPixelFormat = aFormat;
mImageFlags = theImage->mD3DFlags;
CreateTextureDimensions(theImage);
createTextures = true;
}
mPalette = aDDPalette;
int i,x,y;
int aHeight = theImage->GetHeight();
int aWidth = theImage->GetWidth();
if (mPalette!=NULL)
mTexMemSize += 256*4;
int aFormatSize = 4;
if (aFormat==PixelFormat_Palette8)
aFormatSize = 1;
else if (aFormat==PixelFormat_R5G6B5)
aFormatSize = 2;
else if (aFormat==PixelFormat_A4R4G4B4)
aFormatSize = 2;
i=0;
for(y=0; y<aHeight; y+=mTexPieceHeight)
{
for(x=0; x<aWidth; x+=mTexPieceWidth, i++)
{
TextureDataPiece &aPiece = mTextures[i];
if (createTextures)
{
aPiece.mTexture = CreateTextureSurface(theDevice, theDraw, aPiece.mWidth, aPiece.mHeight, aFormat);
if (aPiece.mTexture==NULL) // create texture failure
{
mPixelFormat = PixelFormat_Unknown;
return;
}
if (mPalette!=NULL)
aPiece.mTexture->SetPalette(mPalette);
mTexMemSize += aPiece.mWidth*aPiece.mHeight*aFormatSize;
}
CopyImageToTexture(aPiece.mTexture,theImage,x,y,aPiece.mWidth,aPiece.mHeight,aFormat);
}
}
mWidth = theImage->mWidth;
mHeight = theImage->mHeight;
mBitsChangedCount = theImage->mBitsChangedCount;
mPixelFormat = aFormat;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void TextureData::CheckCreateTextures(MemoryImage *theImage, LPDIRECT3DDEVICE7 theDevice, LPDIRECTDRAW7 theDraw)
{
if(mPixelFormat==PixelFormat_Unknown || theImage->mWidth != mWidth || theImage->mHeight != mHeight || theImage->mBitsChangedCount != mBitsChangedCount || theImage->mD3DFlags != mImageFlags)
CreateTextures(theImage, theDevice, theDraw);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LPDIRECTDRAWSURFACE7 TextureData::GetTexture(int x, int y, int &width, int &height, float &u1, float &v1, float &u2, float &v2)
{
int tx = x/mTexPieceWidth;
int ty = y/mTexPieceHeight;
TextureDataPiece &aPiece = mTextures[ty*mTexVecWidth + tx];
int left = x%mTexPieceWidth;
int top = y%mTexPieceHeight;
int right = left+width;
int bottom = top+height;
if(right > aPiece.mWidth)
right = aPiece.mWidth;
if(bottom > aPiece.mHeight)
bottom = aPiece.mHeight;
width = right-left;
height = bottom-top;
u1 = (float)left/aPiece.mWidth;
v1 = (float)top/aPiece.mHeight;
u2 = (float)right/aPiece.mWidth;
v2 = (float)bottom/aPiece.mHeight;
return aPiece.mTexture;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LPDIRECTDRAWSURFACE7 TextureData::GetTextureF(float x, float y, float &width, float &height, float &u1, float &v1, float &u2, float &v2)
{
int tx = x/mTexPieceWidth;
int ty = y/mTexPieceHeight;
TextureDataPiece &aPiece = mTextures[ty*mTexVecWidth + tx];
float left = x - tx*mTexPieceWidth;
float top = y - ty*mTexPieceHeight;
float right = left+width;
float bottom = top+height;
if(right > aPiece.mWidth)
right = aPiece.mWidth;
if(bottom > aPiece.mHeight)
bottom = aPiece.mHeight;
width = right-left;
height = bottom-top;
u1 = (float)left/aPiece.mWidth;
v1 = (float)top/aPiece.mHeight;
u2 = (float)right/aPiece.mWidth;
v2 = (float)bottom/aPiece.mHeight;
return aPiece.mTexture;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void SetLinearFilter(LPDIRECT3DDEVICE7 theDevice, bool linear)
{
if (gLinearFilter != linear)
{
D3DTEXTUREMAGFILTER aFilter = linear ? D3DTFG_LINEAR : D3DTFG_POINT;
const char *aDebugContext = linear ? "SetTextureStageState LINEAR" : "SetTextureStageState Point";
D3DInterface::CheckDXError(theDevice->SetTextureStageState(0,D3DTSS_MINFILTER, aFilter),aDebugContext);
D3DInterface::CheckDXError(theDevice->SetTextureStageState(0,D3DTSS_MAGFILTER, aFilter),aDebugContext);
D3DInterface::CheckDXError(theDevice->SetTextureStageState(0,D3DTSS_MIPFILTER, aFilter),aDebugContext);
gLinearFilter = linear;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void TextureData::Blt(LPDIRECT3DDEVICE7 theDevice, float theX, float theY, const Rect& theSrcRect, const Color& theColor)
{
int srcLeft = theSrcRect.mX;
int srcTop = theSrcRect.mY;
int srcRight = srcLeft + theSrcRect.mWidth;
int srcBottom = srcTop + theSrcRect.mHeight;
int srcX, srcY;
float dstX, dstY;
int aWidth,aHeight;
float u1,v1,u2,v2;
srcY = srcTop;
dstY = theY;
DWORD aColor = RGBA_MAKE(theColor.mRed, theColor.mGreen, theColor.mBlue, theColor.mAlpha);
if ((srcLeft >= srcRight) || (srcTop >= srcBottom))
return;
while(srcY < srcBottom)
{
srcX = srcLeft;
dstX = theX;
while(srcX < srcRight)
{
aWidth = srcRight-srcX;
aHeight = srcBottom-srcY;
LPDIRECTDRAWSURFACE7 aTexture = GetTexture(srcX, srcY, aWidth, aHeight, u1, v1, u2, v2);
float x = dstX - 0.5f;
float y = dstY - 0.5f;
D3DTLVERTEX aVertex[4] =
{
{ x, y, 0, 1, aColor, 0, u1, v1 },
{ x, y+aHeight, 0, 1, aColor, 0, u1, v2 },
{ x+aWidth, y, 0, 1, aColor, 0, u2, v1 },
{ x+aWidth, y+aHeight, 0, 1, aColor, 0, u2, v2 }
};
D3DInterface::CheckDXError(theDevice->SetTexture(0, aTexture),"SetTexture gTexture");
D3DInterface::CheckDXError(theDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, gVertexType, aVertex, 4, 0),"DrawPrimitive (Tri) 1");
srcX += aWidth;
dstX += aWidth;
}
srcY += aHeight;
dstY += aHeight;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//typedef std::vector<D3DTLVERTEX> VertexList;
struct VertexList
{
enum { MAX_STACK_VERTS = 100 };
D3DTLVERTEX mStackVerts[MAX_STACK_VERTS];
D3DTLVERTEX *mVerts;
int mSize;
int mCapacity;
typedef int size_type;
VertexList() : mSize(0), mCapacity(MAX_STACK_VERTS), mVerts(mStackVerts) { }
VertexList(const VertexList &theList) : mSize(theList.mSize), mCapacity(MAX_STACK_VERTS), mVerts(mStackVerts)
{
reserve(mSize);
memcpy(mVerts,theList.mVerts,mSize*sizeof(mVerts[0]));
}
~VertexList()
{
if (mVerts != mStackVerts)
delete mVerts;
}
void reserve(int theCapacity)
{
if (mCapacity < theCapacity)
{
mCapacity = theCapacity;
D3DTLVERTEX *aNewList = new D3DTLVERTEX[theCapacity];
memcpy(aNewList,mVerts,mSize*sizeof(mVerts[0]));
if (mVerts != mStackVerts)
delete mVerts;
mVerts = aNewList;
}
}
void push_back(const D3DTLVERTEX &theVert)
{
if (mSize==mCapacity)
reserve(mCapacity*2);
mVerts[mSize++] = theVert;
}
void operator=(const VertexList &theList)
{
reserve(theList.mSize);
mSize = theList.mSize;
memcpy(mVerts,theList.mVerts,mSize*sizeof(mVerts[0]));
}
D3DTLVERTEX& operator[](int thePos)
{
return mVerts[thePos];
}
int size() { return mSize; }
void clear() { mSize = 0; }
};
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static inline float GetCoord(const D3DTLVERTEX &theVertex, int theCoord)
{
switch (theCoord)
{
case 0: return theVertex.sx;
case 1: return theVertex.sy;
case 2: return theVertex.sz;
case 3: return theVertex.tu;
case 4: return theVertex.tv;
default: return 0;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static inline D3DTLVERTEX Interpolate(const D3DTLVERTEX &v1, const D3DTLVERTEX &v2, float t)
{
D3DTLVERTEX aVertex = v1;
aVertex.sx = v1.sx + t*(v2.sx-v1.sx);
aVertex.sy = v1.sy + t*(v2.sy-v1.sy);
aVertex.tu = v1.tu + t*(v2.tu-v1.tu);
aVertex.tv = v1.tv + t*(v2.tv-v1.tv);
if (v1.color!=v2.color)
{
int r = RGBA_GETRED(v1.color) + t*(RGBA_GETRED(v2.color) - RGBA_GETRED(v1.color));
int g = RGBA_GETGREEN(v1.color) + t*(RGBA_GETGREEN(v2.color) - RGBA_GETGREEN(v1.color));
int b = RGBA_GETBLUE(v1.color) + t*(RGBA_GETBLUE(v2.color) - RGBA_GETBLUE(v1.color));
int a = RGBA_GETALPHA(v1.color) + t*(RGBA_GETALPHA(v2.color) - RGBA_GETALPHA(v1.color));
aVertex.color = RGBA_MAKE(r,g,b,a);
}
return aVertex;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template<class Pred>
struct PointClipper
{
Pred mPred;
void ClipPoint(int n, float clipVal, const D3DTLVERTEX &v1, const D3DTLVERTEX &v2, VertexList &out);
void ClipPoints(int n, float clipVal, VertexList &in, VertexList &out);
};
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template<class Pred>
void PointClipper<Pred>::ClipPoint(int n, float clipVal, const D3DTLVERTEX &v1, const D3DTLVERTEX &v2, VertexList &out)
{
if (!mPred(GetCoord(v1,n), clipVal))
{
if (!mPred(GetCoord(v2,n), clipVal)) // both inside
out.push_back(v2);
else // inside -> outside
{
float t = (clipVal - GetCoord(v1,n))/(GetCoord(v2,n)-GetCoord(v1,n));
out.push_back(Interpolate(v1,v2,t));
}
}
else
{
if (!mPred(GetCoord(v2,n), clipVal)) // outside -> inside
{
float t = (clipVal - GetCoord(v1, n))/(GetCoord(v2,n)-GetCoord(v1,n));
out.push_back(Interpolate(v1,v2,t));
out.push_back(v2);
}
// else // outside -> outside
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template<class Pred>
void PointClipper<Pred>::ClipPoints(int n, float clipVal, VertexList &in, VertexList &out)
{
if(in.size()<2)
return;
ClipPoint(n,clipVal,in[in.size()-1],in[0],out);
for(VertexList::size_type i=0; i<in.size()-1; i++)
ClipPoint(n,clipVal,in[i],in[i+1],out);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void DrawPolyClipped(LPDIRECT3DDEVICE7 theDevice, const Rect *theClipRect, const VertexList &theList)
{
VertexList l1, l2;
l1 = theList;
int left = theClipRect->mX;
int right = left + theClipRect->mWidth;
int top = theClipRect->mY;
int bottom = top + theClipRect->mHeight;
VertexList *in = &l1, *out = &l2;
PointClipper<std::less<float> > aLessClipper;
PointClipper<std::greater_equal<float> > aGreaterClipper;
aLessClipper.ClipPoints(0,left,*in,*out); std::swap(in,out); out->clear();
aLessClipper.ClipPoints(1,top,*in,*out); std::swap(in,out); out->clear();
aGreaterClipper.ClipPoints(0,right,*in,*out); std::swap(in,out); out->clear();
aGreaterClipper.ClipPoints(1,bottom,*in,*out);
VertexList &aList = *out;
if (aList.size() >= 3)
D3DInterface::CheckDXError(theDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, gVertexType, &aList[0], aList.size(), 0),"DrawPrimitive (Tri) 2");
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void DoPolyTextureClip(VertexList &theList)
{
VertexList l2;
float left = 0;
float right = 1;
float top = 0;
float bottom = 1;
VertexList *in = &theList, *out = &l2;
PointClipper<std::less<float> > aLessClipper;
PointClipper<std::greater_equal<float> > aGreaterClipper;
aLessClipper.ClipPoints(3,left,*in,*out); std::swap(in,out); out->clear();
aLessClipper.ClipPoints(4,top,*in,*out); std::swap(in,out); out->clear();
aGreaterClipper.ClipPoints(3,right,*in,*out); std::swap(in,out); out->clear();
aGreaterClipper.ClipPoints(4,bottom,*in,*out);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void TextureData::BltTransformed(LPDIRECT3DDEVICE7 theDevice, const SexyMatrix3 &theTrans, const Rect& theSrcRect, const Color& theColor, const Rect *theClipRect, float theX, float theY, bool center)
{
int srcLeft = theSrcRect.mX;
int srcTop = theSrcRect.mY;
int srcRight = srcLeft + theSrcRect.mWidth;
int srcBottom = srcTop + theSrcRect.mHeight;
int srcX, srcY;
float dstX, dstY;
int aWidth;
int aHeight;
float u1,v1,u2,v2;
float startx = 0, starty = 0;
float pixelcorrect = 0.5f;
if (center)
{
startx = -theSrcRect.mWidth/2.0f;
starty = -theSrcRect.mHeight/2.0f;
pixelcorrect = 0.0f;
}
srcY = srcTop;
dstY = starty;
DWORD aColor = RGBA_MAKE(theColor.mRed, theColor.mGreen, theColor.mBlue, theColor.mAlpha);
if ((srcLeft >= srcRight) || (srcTop >= srcBottom))
return;
while(srcY < srcBottom)
{
srcX = srcLeft;
dstX = startx;
while(srcX < srcRight)
{
aWidth = srcRight-srcX;
aHeight = srcBottom-srcY;
LPDIRECTDRAWSURFACE7 aTexture = GetTexture(srcX, srcY, aWidth, aHeight, u1, v1, u2, v2);
float x = dstX; // - 0.5f;
float y = dstY; // - 0.5f;
SexyVector2 p[4] = { SexyVector2(x, y), SexyVector2(x,y+aHeight), SexyVector2(x+aWidth, y) , SexyVector2(x+aWidth, y+aHeight) };
SexyVector2 tp[4];
int i;
for (i=0; i<4; i++)
{
tp[i] = theTrans*p[i];
tp[i].x -= pixelcorrect - theX;
tp[i].y -= pixelcorrect - theY;
}
bool clipped = false;
if (theClipRect != NULL)
{
int left = theClipRect->mX;
int right = left + theClipRect->mWidth;
int top = theClipRect->mY;
int bottom = top + theClipRect->mHeight;
for (i=0; i<4; i++)
{
if (tp[i].x<left || tp[i].x>=right || tp[i].y<top || tp[i].y>=bottom)
{
clipped = true;
break;
}
}
}
D3DTLVERTEX aVertex[4] =
{
{ tp[0].x, tp[0].y, 0, 1, aColor, 0, u1, v1 },
{ tp[1].x, tp[1].y, 0, 1, aColor, 0, u1, v2 },
{ tp[2].x, tp[2].y, 0, 1, aColor, 0, u2, v1 },
{ tp[3].x, tp[3].y, 0, 1, aColor, 0, u2, v2 }
};
D3DInterface::CheckDXError(theDevice->SetTexture(0, aTexture),"SetTexture gTexture");
if (!clipped)
D3DInterface::CheckDXError(theDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, gVertexType, aVertex, 4, 0),"DrawPrimitive (Tri) 3");
else
{
VertexList aList;
aList.push_back(aVertex[0]);
aList.push_back(aVertex[1]);
aList.push_back(aVertex[3]);
aList.push_back(aVertex[2]);
DrawPolyClipped(theDevice, theClipRect, aList);
// DrawPolyClipped(theDevice, theClipRect, aVertex+1, 3);
}
// D3DInterface::CheckDXError(theDevice->SetTexture(0, NULL),"SetTexture NULL");
srcX += aWidth;
dstX += aWidth;
}
srcY += aHeight;
dstY += aHeight;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#define GetColorFromTriVertex(theVertex, theColor) (theVertex.color?theVertex.color:theColor)
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void TextureData::BltTriangles(LPDIRECT3DDEVICE7 theDevice, const TriVertex theVertices[][3], int theNumTriangles, DWORD theColor, float tx, float ty)
{
if ((mMaxTotalU <= 1.0) && (mMaxTotalV <= 1.0))
{
D3DInterface::CheckDXError(theDevice->SetTexture(0, mTextures[0].mTexture),"SetTexture gTexture");
D3DTLVERTEX aVertexCache[100][3];
int aVertexCacheNum = 0;
for (int aTriangleNum = 0; aTriangleNum < theNumTriangles; aTriangleNum++)
{
TriVertex* aTriVerts = (TriVertex*) theVertices[aTriangleNum];
D3DTLVERTEX* aD3DVertex = (D3DTLVERTEX*) aVertexCache[aVertexCacheNum++];
aD3DVertex[0].sx = aTriVerts[0].x + tx;
aD3DVertex[0].sy = aTriVerts[0].y + ty;
aD3DVertex[0].sz = 0;
aD3DVertex[0].rhw = 1;
aD3DVertex[0].color = GetColorFromTriVertex(aTriVerts[0],theColor);
aD3DVertex[0].specular = 0;
aD3DVertex[0].tu = aTriVerts[0].u * mMaxTotalU;
aD3DVertex[0].tv = aTriVerts[0].v * mMaxTotalV;
aD3DVertex[1].sx = aTriVerts[1].x + tx;
aD3DVertex[1].sy = aTriVerts[1].y + ty;
aD3DVertex[1].sz = 0;
aD3DVertex[1].rhw = 1;
aD3DVertex[1].color = GetColorFromTriVertex(aTriVerts[1],theColor);
aD3DVertex[1].specular = 0;
aD3DVertex[1].tu = aTriVerts[1].u * mMaxTotalU;
aD3DVertex[1].tv = aTriVerts[1].v * mMaxTotalV;
aD3DVertex[2].sx = aTriVerts[2].x + tx;
aD3DVertex[2].sy = aTriVerts[2].y + ty;
aD3DVertex[2].sz = 0;
aD3DVertex[2].rhw = 1;
aD3DVertex[2].color = GetColorFromTriVertex(aTriVerts[2],theColor);
aD3DVertex[2].specular = 0;
aD3DVertex[2].tu = aTriVerts[2].u * mMaxTotalU;
aD3DVertex[2].tv = aTriVerts[2].v * mMaxTotalV;
if ((aVertexCacheNum == 100) || (aTriangleNum == theNumTriangles - 1))
{
// Flush the triangles now
D3DInterface::CheckDXError(theDevice->DrawPrimitive(D3DPT_TRIANGLELIST, gVertexType, aVertexCache, aVertexCacheNum*3, 0),"DrawPrimitive (TriList)");
aVertexCacheNum = 0;
}
}
}
else
{
for (int aTriangleNum = 0; aTriangleNum < theNumTriangles; aTriangleNum++)
{
TriVertex* aTriVerts = (TriVertex*) theVertices[aTriangleNum];
D3DTLVERTEX aVertex[3] =
{
{ aTriVerts[0].x + tx, aTriVerts[0].y + ty, 0, 1, GetColorFromTriVertex(aTriVerts[0],theColor), 0, aTriVerts[0].u*mMaxTotalU, aTriVerts[0].v*mMaxTotalV },
{ aTriVerts[1].x + tx, aTriVerts[1].y + ty, 0, 1, GetColorFromTriVertex(aTriVerts[1],theColor), 0, aTriVerts[1].u*mMaxTotalU, aTriVerts[1].v*mMaxTotalV },
{ aTriVerts[2].x + tx, aTriVerts[2].y + ty, 0, 1, GetColorFromTriVertex(aTriVerts[2],theColor), 0, aTriVerts[2].u*mMaxTotalU, aTriVerts[2].v*mMaxTotalV }
};
float aMinU = mMaxTotalU, aMinV = mMaxTotalV;
float aMaxU = 0, aMaxV = 0;
int i,j,k;
for (i=0; i<3; i++)
{
if(aVertex[i].tu < aMinU)
aMinU = aVertex[i].tu;
if(aVertex[i].tv < aMinV)
aMinV = aVertex[i].tv;
if(aVertex[i].tu > aMaxU)
aMaxU = aVertex[i].tu;
if(aVertex[i].tv > aMaxV)
aMaxV = aVertex[i].tv;
}
VertexList aMasterList;
aMasterList.push_back(aVertex[0]);
aMasterList.push_back(aVertex[1]);
aMasterList.push_back(aVertex[2]);
VertexList aList;
int aLeft = floorf(aMinU);
int aTop = floorf(aMinV);
int aRight = ceilf(aMaxU);
int aBottom = ceilf(aMaxV);
if (aLeft < 0)
aLeft = 0;
if (aTop < 0)
aTop = 0;
if (aRight > mTexVecWidth)
aRight = mTexVecWidth;
if (aBottom > mTexVecHeight)
aBottom = mTexVecHeight;
TextureDataPiece &aStandardPiece = mTextures[0];
for (i=aTop; i<aBottom; i++)
{
for (j=aLeft; j<aRight; j++)
{
TextureDataPiece &aPiece = mTextures[i*mTexVecWidth + j];
VertexList aList = aMasterList;
for(k=0; k<3; k++)
{
aList[k].tu -= j;
aList[k].tv -= i;
if (i==mTexVecHeight-1)
aList[k].tv *= (float)aStandardPiece.mHeight / aPiece.mHeight;
if (j==mTexVecWidth-1)
aList[k].tu *= (float)aStandardPiece.mWidth / aPiece.mWidth;
}
DoPolyTextureClip(aList);
if (aList.size() >= 3)
{
D3DInterface::CheckDXError(theDevice->SetTexture(0, aPiece.mTexture),"SetTexture gTexture");
D3DInterface::CheckDXError(theDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, gVertexType, &aList[0], aList.size(), 0),"DrawPrimitive (Tri) 4");
/* CheckDXError(theDevice->SetTexture(0, NULL),"SetTexture NULL");
theDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_WIREFRAME);
CheckDXError(theDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, gVertexType, &aList[0], aList.size(), D3DDP_WAIT),"DrawPrimitive (Tri)");
theDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID);*/
}
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool D3DInterface::CreateImageTexture(MemoryImage *theImage)
{
bool wantPurge = false;
if(theImage->mD3DData==NULL)
{
theImage->mD3DData = new TextureData();
// The actual purging was deferred
wantPurge = theImage->mPurgeBits;
AutoCrit aCrit(gSexyAppBase->mDDInterface->mCritSect); // Make images thread safe
mImageSet.insert(theImage);
}
TextureData *aData = (TextureData*)theImage->mD3DData;
aData->CheckCreateTextures(theImage, mD3DDevice, mDD);
if (wantPurge)
theImage->PurgeBits();
return aData->mPixelFormat != PixelFormat_Unknown;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool D3DInterface::RecoverBits(MemoryImage* theImage)
{
if (theImage->mD3DData == NULL)
return false;
TextureData* aData = (TextureData*) theImage->mD3DData;
if (aData->mBitsChangedCount != theImage->mBitsChangedCount) // bits have changed since texture was created
return false;
for (int aPieceRow = 0; aPieceRow < aData->mTexVecHeight; aPieceRow++)
{
for (int aPieceCol = 0; aPieceCol < aData->mTexVecWidth; aPieceCol++)
{
TextureDataPiece* aPiece = &aData->mTextures[aPieceRow*aData->mTexVecWidth + aPieceCol];
DDSURFACEDESC2 aDesc;
aDesc.dwSize = sizeof(aDesc);
if (D3DInterface::CheckDXError(aPiece->mTexture->Lock(NULL,&aDesc,DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_READONLY,NULL),"Lock Texture"))
return false;
int offx = aPieceCol*aData->mTexPieceWidth;
int offy = aPieceRow*aData->mTexPieceHeight;
int aWidth = min(theImage->mWidth-offx, aPiece->mWidth);
int aHeight = min(theImage->mHeight-offy, aPiece->mHeight);
switch (aData->mPixelFormat)
{
case PixelFormat_A8R8G8B8: CopyTexture8888ToImage(aDesc.lpSurface, aDesc.lPitch, theImage, offx, offy, aWidth, aHeight); break;
case PixelFormat_A4R4G4B4: CopyTexture4444ToImage(aDesc.lpSurface, aDesc.lPitch, theImage, offx, offy, aWidth, aHeight); break;
case PixelFormat_R5G6B5: CopyTexture565ToImage(aDesc.lpSurface, aDesc.lPitch, theImage, offx, offy, aWidth, aHeight); break;
case PixelFormat_Palette8: CopyTexturePalette8ToImage(aDesc.lpSurface, aDesc.lPitch, theImage, offx, offy, aWidth, aHeight, aData->mPalette); break;
}
D3DInterface::CheckDXError(aPiece->mTexture->Unlock(NULL),"Texture Unlock");
}
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::SetCurTexture(MemoryImage *theImage)
{
if (theImage==NULL)
{
mD3DDevice->SetTexture(0,NULL);
return;
}
if (!CreateImageTexture(theImage))
return;
TextureData *aData = (TextureData*)theImage->mD3DData;
mD3DDevice->SetTexture(0,aData->mTextures[0].mTexture);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::PushTransform(const SexyMatrix3 &theTransform, bool concatenate)
{
if (mTransformStack.empty() || !concatenate)
mTransformStack.push_back(theTransform);
else
{
SexyMatrix3 &aTrans = mTransformStack.back();
mTransformStack.push_back(theTransform*aTrans);
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::PopTransform()
{
if (!mTransformStack.empty())
mTransformStack.pop_back();
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::RemoveMemoryImage(MemoryImage *theImage)
{
if (theImage->mD3DData != NULL)
{
delete (TextureData*)theImage->mD3DData;
theImage->mD3DData = NULL;
AutoCrit aCrit(gSexyAppBase->mDDInterface->mCritSect); // Make images thread safe
mImageSet.erase(theImage);
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::Cleanup()
{
Flush();
ImageSet::iterator anItr;
for(anItr = mImageSet.begin(); anItr != mImageSet.end(); ++anItr)
{
MemoryImage *anImage = *anItr;
delete (TextureData*)anImage->mD3DData;
anImage->mD3DData = NULL;
}
mImageSet.clear();
if (mD3DDevice != NULL)
{
mD3DDevice->Release();
mD3DDevice = NULL;
}
if (mD3D != NULL)
{
mD3D->Release();
mD3D = NULL;
}
if (mDDSDrawSurface != NULL)
{
mDDSDrawSurface->Release();
mDDSDrawSurface = NULL;
}
if (mZBuffer != NULL)
{
mZBuffer->Release();
mZBuffer = NULL;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::SetupDrawMode(int theDrawMode, const Color &theColor, Image *theImage)
{
if (theDrawMode == Graphics::DRAWMODE_NORMAL)
{
/* if (theImage != NULL)
{
MemoryImage *anImage = (MemoryImage*)theImage;
mD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, (anImage->mHasAlpha || anImage->mHasTrans || theColor.mAlpha<255)?TRUE:FALSE);
}
else
mD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, theColor.mAlpha<255?TRUE:FALSE);
*/
mD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
mD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
}
else // Additive
{
// mD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
// theColor.mRed = theColor.mRed * theColor.mAlpha / 255;
// theColor.mGreen = theColor.mGreen * theColor.mAlpha / 255;
// theColor.mBlue = theColor.mBlue * theColor.mAlpha / 255;
// mD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE);
mD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
mD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE);
}
// mD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::Blt(Image* theImage, float theX, float theY, const Rect& theSrcRect, const Color& theColor, int theDrawMode, bool linearFilter)
{
if (!mTransformStack.empty())
{
BltClipF(theImage,theX,theY,theSrcRect,NULL,theColor,theDrawMode);
return;
}
if (!PreDraw())
return;
MemoryImage* aSrcMemoryImage = (MemoryImage*) theImage;
if (!CreateImageTexture(aSrcMemoryImage))
return;
SetupDrawMode(theDrawMode, theColor, theImage);
TextureData *aData = (TextureData*)aSrcMemoryImage->mD3DData;
SetLinearFilter(mD3DDevice, linearFilter);
aData->Blt(mD3DDevice,theX,theY,theSrcRect,theColor);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::BltMirror(Image* theImage, float theX, float theY, const Rect& theSrcRect, const Color& theColor, int theDrawMode, bool linearFilter)
{
SexyTransform2D aTransform;
aTransform.Translate(-theSrcRect.mWidth,0);
aTransform.Scale(-1, 1);
aTransform.Translate(theX, theY);
BltTransformed(theImage,NULL,theColor,theDrawMode,theSrcRect,aTransform,linearFilter);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::BltClipF(Image* theImage, float theX, float theY, const Rect& theSrcRect, const Rect *theClipRect, const Color& theColor, int theDrawMode)
{
SexyTransform2D aTransform;
aTransform.Translate(theX, theY);
BltTransformed(theImage,theClipRect,theColor,theDrawMode,theSrcRect,aTransform,true);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::StretchBlt(Image* theImage, const Rect& theDestRect, const Rect& theSrcRect, const Rect* theClipRect, const Color &theColor, int theDrawMode, bool fastStretch, bool mirror)
{
float xScale = (float)theDestRect.mWidth / theSrcRect.mWidth;
float yScale = (float)theDestRect.mHeight / theSrcRect.mHeight;
SexyTransform2D aTransform;
if (mirror)
{
aTransform.Translate(-theSrcRect.mWidth,0);
aTransform.Scale(-xScale, yScale);
}
else
aTransform.Scale(xScale, yScale);
aTransform.Translate(theDestRect.mX, theDestRect.mY);
BltTransformed(theImage,theClipRect,theColor,theDrawMode,theSrcRect,aTransform,!fastStretch);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::BltRotated(Image* theImage, float theX, float theY, const Rect* theClipRect, const Color& theColor, int theDrawMode, double theRot, float theRotCenterX, float theRotCenterY, const Rect &theSrcRect)
{
SexyTransform2D aTransform;
aTransform.Translate(-theRotCenterX, -theRotCenterY);
aTransform.RotateRad(theRot);
aTransform.Translate(theX+theRotCenterX,theY+theRotCenterY);
BltTransformed(theImage,theClipRect,theColor,theDrawMode,theSrcRect,aTransform,true);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::BltTransformed(Image* theImage, const Rect* theClipRect, const Color& theColor, int theDrawMode, const Rect &theSrcRect, const SexyMatrix3 &theTransform, bool linearFilter, float theX, float theY, bool center)
{
if (!PreDraw())
return;
MemoryImage* aSrcMemoryImage = (MemoryImage*) theImage;
if (!CreateImageTexture(aSrcMemoryImage))
return;
SetupDrawMode(theDrawMode, theColor, theImage);
TextureData *aData = (TextureData*)aSrcMemoryImage->mD3DData;
if (!mTransformStack.empty())
{
SetLinearFilter(mD3DDevice, true); // force linear filtering in the case of a global transform
if (theX!=0 || theY!=0)
{
SexyTransform2D aTransform;
if (center)
aTransform.Translate(-theSrcRect.mWidth/2.0f,-theSrcRect.mHeight/2.0f);
aTransform = theTransform * aTransform;
aTransform.Translate(theX,theY);
aTransform = mTransformStack.back() * aTransform;
aData->BltTransformed(mD3DDevice, aTransform, theSrcRect, theColor, theClipRect);
}
else
{
SexyTransform2D aTransform = mTransformStack.back()*theTransform;
aData->BltTransformed(mD3DDevice, aTransform, theSrcRect, theColor, theClipRect, theX, theY, center);
}
}
else
{
SetLinearFilter(mD3DDevice, linearFilter);
aData->BltTransformed(mD3DDevice, theTransform, theSrcRect, theColor, theClipRect, theX, theY, center);
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::DrawLine(double theStartX, double theStartY, double theEndX, double theEndY, const Color& theColor, int theDrawMode)
{
if (!PreDraw())
return;
SetupDrawMode(theDrawMode, theColor, NULL);
float x1, y1, x2, y2;
DWORD aColor = RGBA_MAKE(theColor.mRed, theColor.mGreen, theColor.mBlue, theColor.mAlpha);
if (!mTransformStack.empty())
{
SexyVector2 p1(theStartX,theStartY);
SexyVector2 p2(theEndX,theEndY);
p1 = mTransformStack.back()*p1;
p2 = mTransformStack.back()*p2;
x1 = p1.x;
y1 = p1.y;
x2 = p2.x;
y2 = p2.y;
}
else
{
x1 = theStartX;
y1 = theStartY;
x2 = theEndX;
y2 = theEndY;
}
D3DTLVERTEX aVertex[3] =
{
{ x1, y1, 0, 1, aColor, 0, 0, 0 },
{ x2, y2, 0, 1, aColor, 0, 0, 0 },
{ x2+0.5f, y2+0.5f, 0, 1, aColor, 0, 0, 0 }
};
D3DInterface::CheckDXError(mD3DDevice->SetTexture(0, NULL),"SetTexture NULL");
D3DInterface::CheckDXError(mD3DDevice->DrawPrimitive(D3DPT_LINESTRIP, gVertexType, aVertex, 3, 0),"DrawPrimitive (Line)");
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::FillRect(const Rect& theRect, const Color& theColor, int theDrawMode)
{
if (!PreDraw())
return;
SetupDrawMode(theDrawMode, theColor, NULL);
DWORD aColor = RGBA_MAKE(theColor.mRed, theColor.mGreen, theColor.mBlue, theColor.mAlpha);
float x = theRect.mX - 0.5f;
float y = theRect.mY - 0.5f;
float aWidth = theRect.mWidth;
float aHeight = theRect.mHeight;
D3DTLVERTEX aVertex[4] =
{
{ x, y, 0, 1, aColor, 0, 0, 0 },
{ x, y+aHeight, 0, 1, aColor, 0, 0, 0 },
{ x+aWidth, y, 0, 1, aColor, 0, 0, 0 },
{ x+aWidth, y+aHeight, 0, 1, aColor, 0, 0, 0 }
};
if (!mTransformStack.empty())
{
SexyVector2 p[4] = { SexyVector2(x, y), SexyVector2(x,y+aHeight), SexyVector2(x+aWidth, y) , SexyVector2(x+aWidth, y+aHeight) };
int i;
for (i=0; i<4; i++)
{
p[i] = mTransformStack.back()*p[i];
p[i].x -= 0.5f;
p[i].y -= 0.5f;
aVertex[i].sx = p[i].x;
aVertex[i].sy = p[i].y;
}
}
CheckDXError(mD3DDevice->SetTexture(0, NULL),"SetTexture NULL");
CheckDXError(mD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, gVertexType, aVertex, 4, 0),"DrawPrimitive (Rect)");
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::DrawTriangle(const TriVertex &p1, const TriVertex &p2, const TriVertex &p3, const Color &theColor, int theDrawMode)
{
if (!PreDraw())
return;
SetupDrawMode(theDrawMode, theColor, NULL);
DWORD aColor = RGBA_MAKE(theColor.mRed, theColor.mGreen, theColor.mBlue, theColor.mAlpha);
D3DTLVERTEX aVertex[3] =
{
{ p1.x, p1.y, 0, 1, GetColorFromTriVertex(p1, aColor), 0, 0, 0 },
{ p2.x, p2.y, 0, 1, GetColorFromTriVertex(p2, aColor), 0, 0, 0 },
{ p3.x, p3.y, 0, 1, GetColorFromTriVertex(p3, aColor), 0, 0, 0 }
};
CheckDXError(mD3DDevice->SetTexture(0, NULL),"SetTexture NULL");
CheckDXError(mD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, gVertexType, aVertex, 3, 0),"DrawPrimitive (Tri) 5");
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::FillPoly(const Point theVertices[], int theNumVertices, const Rect *theClipRect, const Color &theColor, int theDrawMode, int tx, int ty)
{
if (theNumVertices<3)
return;
if (!PreDraw())
return;
SetupDrawMode(theDrawMode, theColor, NULL);
DWORD aColor = RGBA_MAKE(theColor.mRed, theColor.mGreen, theColor.mBlue, theColor.mAlpha);
CheckDXError(mD3DDevice->SetTexture(0, NULL),"SetTexture NULL");
VertexList aList;
for (int i=0; i<theNumVertices; i++)
{
D3DTLVERTEX vert = { theVertices[i].mX + tx, theVertices[i].mY + ty, 0, 1, aColor, 0, 0, 0 };
if (!mTransformStack.empty())
{
SexyVector2 v(vert.sx,vert.sy);
v = mTransformStack.back()*v;
vert.sx = v.x;
vert.sy = v.y;
}
aList.push_back(vert);
}
if (theClipRect != NULL)
DrawPolyClipped(mD3DDevice,theClipRect,aList);
else
D3DInterface::CheckDXError(mD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, gVertexType, &aList[0], aList.size(), 0),"DrawPrimitive (FillPoly)");
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::DrawTriangleTex(const TriVertex &p1, const TriVertex &p2, const TriVertex &p3, const Color &theColor, int theDrawMode, Image *theTexture, bool blend)
{
TriVertex aVertices[1][3] = {{p1, p2, p3}};
DrawTrianglesTex(aVertices,1,theColor,theDrawMode,theTexture,blend);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::DrawTrianglesTex(const TriVertex theVertices[][3], int theNumTriangles, const Color &theColor, int theDrawMode, Image *theTexture, float tx, float ty, bool blend)
{
if (!PreDraw())
return;
MemoryImage* aSrcMemoryImage = (MemoryImage*)theTexture;
if (!CreateImageTexture(aSrcMemoryImage))
return;
SetupDrawMode(theDrawMode, theColor, theTexture);
DWORD aColor = RGBA_MAKE(theColor.mRed, theColor.mGreen, theColor.mBlue, theColor.mAlpha);
TextureData *aData = (TextureData*)aSrcMemoryImage->mD3DData;
SetLinearFilter(mD3DDevice, blend);
aData->BltTriangles(mD3DDevice, theVertices, theNumTriangles, aColor, tx, ty);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::DrawTrianglesTexStrip(const TriVertex theVertices[], int theNumTriangles, const Color &theColor, int theDrawMode, Image *theTexture, float tx, float ty, bool blend)
{
TriVertex aList[100][3];
int aTriNum = 0;
while (aTriNum < theNumTriangles)
{
int aMaxTriangles = min(100,theNumTriangles - aTriNum);
for (int i=0; i<aMaxTriangles; i++)
{
aList[i][0] = theVertices[aTriNum];
aList[i][1] = theVertices[aTriNum+1];
aList[i][2] = theVertices[aTriNum+2];
aTriNum++;
}
DrawTrianglesTex(aList,aMaxTriangles,theColor,theDrawMode,theTexture, tx, ty, blend);
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void D3DInterface::Flush()
{
if (mSceneBegun)
{
mD3DDevice->EndScene();
mSceneBegun = false;
mErrorString.erase();
}
}