Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1061 lines
34 KiB

/*==========================================================================;
*
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
*
* File: texture.c
* Content: Direct3DTexture interface
*@@BEGIN_MSINTERNAL
*
* $Id$
*
* History:
* Date By Reason
* ==== == ======
* 07/12/95 stevela Merged Colin's changes.
* 10/12/95 stevela Removed AGGREGATE_D3D
* 17/04/96 colinmc Bug 12185: Debug output too aggresive
* 30/04/96 stevela Bug 18898: Wrong error returned on invalid GetHandle
*@@END_MSINTERNAL
*
***************************************************************************/
#include "pch.cpp"
#pragma hdrstop
/*
* Create an api for the Direct3DTexture object
*/
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DTexture"
/*
* Routines to associate textures with the D3DDevice.
*
* Note that the texture block structures support both the Texture/Texture2
* interface and the Texture3 interface (the block struct has
* pointers to both and one of the pointers must be NULL). This
* means that the 'hook' call for each must null out the pointer
* for the other, and the GetTextureHandle must not return a valid
* handle for the 'other' texture interface (return NULL).
*
* The D3DI_RemoveTextureBlock is the only call made to cleanup
* when devices go away. In this case, it is called for both
* Texture(2) and Texture3, so it checks the pointers and calls
* the Texture3 version if appropriate.
*/
LPD3DI_TEXTUREBLOCK hookTextureToDevice(LPDIRECT3DDEVICEI lpDevI,
LPDIRECT3DTEXTUREI lpD3DText)
{
LPD3DI_TEXTUREBLOCK nBlock;
if (D3DMalloc((void**)&nBlock, sizeof(D3DI_TEXTUREBLOCK)) != D3D_OK)
{
D3D_ERR("failed to allocate space for texture block");
return NULL;
}
nBlock->lpDevI = lpDevI;
nBlock->lpD3DTextureI = lpD3DText;
nBlock->hTex = 0; // initialized to be zero
LIST_INSERT_ROOT(&lpD3DText->blocks, nBlock, list);
LIST_INSERT_ROOT(&lpDevI->texBlocks, nBlock, devList);
return nBlock;
}
void D3DI_RemoveTextureHandle(LPD3DI_TEXTUREBLOCK lpBlock)
{
/* check if this block refers to a Texture/Texture2 - this
* needs to handle both texture types for device cleanup
*/
if (lpBlock->hTex)
{
// block refers to a Texture/Texture2
LPD3DI_MATERIALBLOCK mat;
// Remove the texture from any materials which reference it.
for (mat = LIST_FIRST(&lpBlock->lpDevI->matBlocks);
mat; mat = LIST_NEXT(mat,devList)) {
if (mat->lpD3DMaterialI->dmMaterial.hTexture == lpBlock->hTex) {
D3DMATERIAL m = mat->lpD3DMaterialI->dmMaterial;
LPDIRECT3DMATERIAL lpMat =
(LPDIRECT3DMATERIAL) mat->lpD3DMaterialI;
m.hTexture = 0L;
lpMat->SetMaterial(&m);
}
}
D3DHAL_TextureDestroy(lpBlock);
}
}
LPD3DI_TEXTUREBLOCK D3DI_FindTextureBlock(LPDIRECT3DTEXTUREI lpTex,
LPDIRECT3DDEVICEI lpDev)
{
LPD3DI_TEXTUREBLOCK tBlock;
tBlock = LIST_FIRST(&lpTex->blocks);
while (tBlock) {
// return match for Texture(2) only (not Texture3)
if (tBlock->lpDevI == lpDev) {
return tBlock;
}
tBlock = LIST_NEXT(tBlock,list);
}
return NULL;
}
HRESULT D3DAPI DIRECT3DTEXTUREI::Initialize(LPDIRECT3DDEVICE lpD3D, LPDIRECTDRAWSURFACE lpDDS)
{
return DDERR_ALREADYINITIALIZED;
}
/*
* Create a texture.
*
* NOTE: Radical modifications to support the aggregatable texture
* interface (so textures can be queried off DirectDraw surfaces):
*
* 1) This call is no longer a member of the Direct3D device interface.
* It is now an API function exported from the Direct3D DLL. Its
* a hidden API function - only DirectDraw will ever invoke it.
*
* 2) This call no longer establishes the realtionship between a
* texture and a device. That is performed by the GetHandle()
* member of the Direct3DTexture interface.
*
* 3) This call is, in effect, the class factory for Direct3DTexture
* objects. This function will be invoked to create the aggregated
* texture object hanging off the DirectDraw surface.
*
* NOTE: So the Direct3DTexture knows which DirectDraw surface is
* supplying its bits this function is passed an interface pointer
* for that DirectDraw surface. I suspect this blows a nice big
* hole in the COM model as the DirectDraw surface is also the
* owning interface of the texture and I don't think aggregated
* objects should know about thier owning interfaces. However, to
* make this thing work this is what we have to do.
*
* EXTRA BIG NOTE: Because of the above don't take a reference to
* the DirectDraw surface passed in. If you do you will get a circular
* reference and the bloody thing will never die. When aggregated
* the texture interface's lifetime is entirely defined by the
* lifetime of its owning interface (the DirectDraw surface) so the
* DirectDraw surface can never go away before the texture.
*/
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DCreateTexture"
HRESULT D3DAPI Direct3DCreateTexture(REFIID riid,
LPDIRECTDRAWSURFACE lpDDS,
LPUNKNOWN* lplpD3DText,
IUnknown* pUnkOuter)
{
LPDDRAWI_DDRAWSURFACE_LCL lpLcl;
LPDDPIXELFORMAT lpPF;
LPDIRECT3DTEXTUREI lpText;
LPDIRECTDRAWPALETTE lpDDPal;
HRESULT ddrval;
DWORD dwFlags;
*lplpD3DText = NULL;
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
// Release in the destructor
/* No need to validate params as they are passed to us by DirectDraw */
if ((!IsEqualIID(riid, IID_IDirect3DTexture)) &&
(!IsEqualIID(riid, IID_IDirect3DTexture2))) {
/*
* Not an error worth reporting by debug messages as this is
* almost certainly just DirectDraw probing us with an
* unknown IID.
*/
return (E_NOINTERFACE);
}
lpText = static_cast<LPDIRECT3DTEXTUREI>(new DIRECT3DTEXTUREI(pUnkOuter));
if (!lpText) {
D3D_ERR("failed to allocate space for texture object");
return (DDERR_OUTOFMEMORY);
}
// QI lpDDS for lpDDS4 interface
ddrval = lpDDS->QueryInterface(IID_IDirectDrawSurface4, (LPVOID*)&lpText->lpDDS);
if(FAILED(ddrval))
{
D3D_ERR("QI for IID_IDirectDrawSurface4 failed");
delete lpText;
return ddrval;
}
memcpy(&lpText->DDSInt4,lpText->lpDDS,sizeof(DDRAWI_DDRAWSURFACE_INT));
lpText->lpDDS->Release();
lpLcl = ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl;
if (DDSCAPS2_TEXTUREMANAGE & lpLcl->lpSurfMore->ddsCapsEx.dwCaps2)
{
lpText->lpDDSSys=(LPDIRECTDRAWSURFACE4)&lpText->DDSInt4;
lpText->lpDDSSys1Tex=lpDDS; //save it for create texture handle to driver
lpText->lpDDS=NULL;
lpText->lpDDS1Tex=NULL;
// Next, we need to loop thru and set pointers to the dirty
// bit in the DDraw surfaces
DDSCAPS2 ddscaps;
LPDIRECTDRAWSURFACE4 lpDDSTmp, lpDDS = lpText->lpDDSSys;
do
{
((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpSurfMore->lpbDirty = &(lpText->bDirty);
memset(&ddscaps, 0, sizeof(ddscaps));
ddscaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
ddrval = lpDDS->GetAttachedSurface(&ddscaps, &lpDDSTmp);
if(lpDDS != lpText->lpDDSSys)
lpDDS->Release();
lpDDS = lpDDSTmp;
if(ddrval != DD_OK && ddrval != DDERR_NOTFOUND)
{
D3D_ERR("GetAttachedSurface for obtaining mipmaps failed");
delete lpText;
return ddrval;
}
}
while(ddrval == DD_OK);
}
else
{
lpText->lpDDSSys=NULL;
lpText->lpDDSSys1Tex=NULL;
lpText->lpDDS=(LPDIRECTDRAWSURFACE4)&lpText->DDSInt4;
lpText->lpDDS1Tex=lpDDS; //save it for create texture handle to driver
}
lpText->lpTMBucket=NULL;
lpText->LogTexSize=0;
lpText->bDirty = TRUE;
/*
* Are we palettized?
*/
if (lpLcl->dwFlags & DDRAWISURF_HASPIXELFORMAT)
lpPF = &lpLcl->lpGbl->ddpfSurface;
else
lpPF = &lpLcl->lpGbl->lpDD->vmiData.ddpfDisplay;
if ( (lpPF->dwFlags & DDPF_PALETTEINDEXED1) ||
(lpPF->dwFlags & DDPF_PALETTEINDEXED2) ||
(lpPF->dwFlags & DDPF_PALETTEINDEXED4) ||
(lpPF->dwFlags & DDPF_PALETTEINDEXED8) )
{
ddrval = lpDDS->GetPalette(&lpDDPal);
if (ddrval != DD_OK) {
if (ddrval != DDERR_NOPALETTEATTACHED) {
delete lpText;
D3D_ERR("No palette in a palettized texture");
return ddrval;
}
D3D_INFO(3, "Texture is not palettized");
lpText->bIsPalettized = false;
} else {
lpText->bIsPalettized = true;
lpDDPal->Release();
D3D_INFO(3, "Texture is palettized");
}
}
/*
* Note, we return the IUnknown rather than the texture
* interface. So if you want to do anything real with
* this baby you must query for the texture interface.
*/
*lplpD3DText = static_cast<LPUNKNOWN>(&(lpText->mTexUnk));
return (D3D_OK);
}
DIRECT3DTEXTUREI::DIRECT3DTEXTUREI(LPUNKNOWN pUnkOuter)
{
/*
* setup the object
*
* NOTE: Device and handle established when GetHandle() is called
*/
mTexUnk.refCnt = 1;
LIST_INITIALIZE(&blocks);
mTexUnk.pTexI=this;
/*
* Are we really being aggregated?
*/
if (pUnkOuter != NULL)
{
/*
* Yup - we are being aggregated. Store the supplied
* IUnknown so we can punt to that.
* NOTE: We explicitly DO NOT AddRef here.
*/
lpOwningIUnknown = pUnkOuter;
}
else
{
/*
* Nope - but we pretend we are anyway by storing our
* own IUnknown as the parent IUnknown. This makes the
* code much neater.
*/
lpOwningIUnknown = static_cast<LPUNKNOWN>(&(this->mTexUnk));
}
// Not currently in use
bInUse = FALSE;
}
/*
* GetHandle
*
* NOTE: Now establishes relationship betwewn texture and device
* (which used to be done by CreateTexture) and generates the
* texture handle.
*/
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DTexture::GetHandle"
HRESULT D3DAPI DIRECT3DTEXTUREI::GetHandle(LPDIRECT3DDEVICE lpD3DDevice,
LPD3DTEXTUREHANDLE lphTex)
{
LPDIRECT3DDEVICEI lpDev;
LPD3DI_TEXTUREBLOCK lptBlock;
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
// Release in the destructor
/*
* validate parms
*/
TRY
{
if (!VALID_DIRECT3DTEXTURE2_PTR(this)) {
D3D_ERR( "Invalid Direct3DTexture pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALID_DIRECT3DDEVICE_PTR(lpD3DDevice)) {
D3D_ERR( "Invalid Direct3DDevice pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALID_D3DTEXTUREHANDLE_PTR(lphTex)) {
D3D_ERR( "Invalid D3DTEXTUREHANDLE pointer" );
return DDERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
D3D_ERR( "Exception encountered validating parameters" );
return DDERR_INVALIDPARAMS;
}
if (lpDDSSys)
{
D3D_ERR( "Handle is not available since the texture is managed" );
return DDERR_INVALIDOBJECT; //managed texture has no handle
}
lpDev = static_cast<LPDIRECT3DDEVICEI>(lpD3DDevice);
lptBlock = D3DI_FindTextureBlock(this, lpDev);
*lphTex=0;
if (NULL == lptBlock) {
/*
* NOTE: We used to do this in CreateTexture. Perhaps the service
* name should be changed (as the texture is now already created
* when this function is invoked).
*
* Indicate to driver that source is a DirectDraw surface, so it
* can Lock() when required.
*/
lptBlock = hookTextureToDevice(lpDev, this);
if ( NULL == lptBlock) {
D3D_ERR("failed to associate texture with device");
return DDERR_OUTOFMEMORY;
}
}
if (!lptBlock->hTex)
{
HRESULT ret;
ret = D3DHAL_TextureCreate(lpDev, &lptBlock->hTex, lpDDS1Tex);
if (ret != D3D_OK)
{
return ret;
}
D3D_INFO(6,"lpTexI=%08lx lptBlock=%08lx hTex=%08lx",this,lptBlock,lptBlock->hTex);
}
*lphTex=lptBlock->hTex;
DDASSERT(lptBlock->hTex);
return D3D_OK;
}
HRESULT D3DAPI DIRECT3DTEXTUREI::GetHandle(LPDIRECT3DDEVICE2 lpD3DDevice,
LPD3DTEXTUREHANDLE lphTex)
{
LPDIRECT3DDEVICEI lpDev;
LPD3DI_TEXTUREBLOCK lptBlock;
HRESULT ret;
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
// Release in the destructor
/*
* validate parms
*/
TRY
{
if (!VALID_DIRECT3DTEXTURE2_PTR(this)) {
D3D_ERR( "Invalid Direct3DTexture2 pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALID_DIRECT3DDEVICE2_PTR(lpD3DDevice)) {
D3D_ERR( "Invalid Direct3DDevice2 pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALID_D3DTEXTUREHANDLE_PTR(lphTex)) {
D3D_ERR( "Invalid D3DTEXTUREHANDLE pointer" );
return DDERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
D3D_ERR( "Exception encountered validating parameters" );
return DDERR_INVALIDPARAMS;
}
if (lpDDSSys)
{
D3D_ERR( "Handle is not available since texture is managed" );
return DDERR_INVALIDOBJECT; //managed texture has no handle
}
lpDev = static_cast<LPDIRECT3DDEVICEI>(lpD3DDevice);
lptBlock = D3DI_FindTextureBlock(this, lpDev);
/*
* Do cap verification if we've not used this device before.
*/
*lphTex=0;
if (NULL == lptBlock) {
ret=VerifyTextureCaps(lpDev, (LPDDRAWI_DDRAWSURFACE_INT)lpDDS);
if (ret != D3D_OK)
{
return ret;
}
/*
* Put this device in the list of those owned by the
* Direct3DDevice object
*/
lptBlock = hookTextureToDevice(lpDev, this);
if ( NULL == lptBlock) {
D3D_ERR("failed to associate texture with device");
return DDERR_OUTOFMEMORY;
}
}
if (!lptBlock->hTex)
{
ret = D3DHAL_TextureCreate(lpDev, &lptBlock->hTex, lpDDS1Tex);
if (ret != D3D_OK)
{
return ret;
}
D3D_INFO(6,"lpTexI=%08lx lptBlock=%08lx hTex=%08lx",this,lptBlock,lptBlock->hTex);
}
*lphTex=lptBlock->hTex;
DDASSERT(lptBlock->hTex);
return D3D_OK;
}
#undef DPF_MODNAME
#define DPF_MODNAME "GetTextureDDIHandle"
HRESULT
GetTextureDDIHandle(LPDIRECT3DTEXTUREI lpTexI,
LPDIRECT3DDEVICEI lpDevI,
LPD3DI_TEXTUREBLOCK* lplpBlock)
{
#ifdef __DD_OPT_SURFACE
LPDDRAWI_DDRAWSURFACE_LCL pSurf_lcl = NULL;
#endif //__DD_OPT_SURFACE
HRESULT ret;
LPD3DI_TEXTUREBLOCK lpBlock=*lplpBlock; //in case has the pointer
#ifdef __DD_OPT_SURFACE
// If the surface is Empty, return 0 handle
if (lpTexI->lpDDS)
{
pSurf_lcl = ((LPDDRAWI_DDRAWSURFACE_INT)lpTexI->lpDDS)->lpLcl;
}
else
{
pSurf_lcl = ((LPDDRAWI_DDRAWSURFACE_INT)lpTexI->lpDDSSys)->lpLcl;
}
DDASSERT (pSurf_lcl);
if (pSurf_lcl->dwFlags & DDRAWISURF_EMPTYSURFACE)
{
D3D_WARN(1, "Cannot get DDI handle to an empty surface, call load first");
return D3DERR_OPTTEX_CANNOTCOPY;
}
#endif //__DD_OPT_SURFACE
DDASSERT(lpTexI && lpDevI);
/*
* Find out if we've used this device before.
*/
if (!lpBlock)
{
lpBlock = D3DI_FindTextureBlock(lpTexI, lpDevI);
if (!lpBlock)
{
/*
* Put this device in the list of those owned by the
* Direct3DDevice object
*/
lpBlock=hookTextureToDevice(lpDevI, lpTexI);
if (!lpBlock)
{
D3D_ERR("failed to associate texture with device");
return DDERR_OUTOFMEMORY;
}
}
*lplpBlock = lpBlock;
}
if (!lpBlock->hTex)
{
LPDIRECTDRAWSURFACE lpDDS1Temp;
if (!lpTexI->lpDDS)
{
if (lpDevI->dwFEFlags & D3DFE_REALHAL)
{
// We need to make sure that we don't evict any mapped textures
DWORD dwStage;
for (dwStage=0;dwStage < lpDevI->dwMaxTextureBlendStages; dwStage++)
if(lpDevI->lpD3DMappedTexI[dwStage])
lpDevI->lpD3DMappedTexI[dwStage]->bInUse = TRUE;
ret=lpDevI->lpDirect3DI->lpTextureManager->allocNode(lpBlock);
for (dwStage=0;dwStage < lpDevI->dwMaxTextureBlendStages; dwStage++)
if(lpDevI->lpD3DMappedTexI[dwStage])
lpDevI->lpD3DMappedTexI[dwStage]->bInUse = FALSE;
if (D3D_OK != ret)
{
D3D_ERR("Failed to create video memory surface");
return ret;
}
if (!(lpDevI->lpD3DHALGlobalDriverData->hwCaps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR))
lpDevI->lpDirect3DI->lpTextureManager->TimeStamp(lpTexI->lpTMBucket);
if (lpBlock->hTex) return D3D_OK; //this means Texmanager reused a texture handle
// QI lpDDS4 for lpDDS interface
if (DD_OK != (ret=lpTexI->lpDDS->QueryInterface(IID_IDirectDrawSurface, (LPVOID*)&lpDDS1Temp)))
{
D3D_ERR("QI IID_IDirectDrawSurface failed");
lpTexI->lpTMBucket->lpD3DTexI=NULL; //clean up
lpTexI->lpTMBucket=NULL;
lpTexI->lpDDS->Release();
lpTexI->lpDDS=NULL;
return ret;
}
lpTexI->lpDDS1Tex = lpDDS1Temp;
}
else
{
lpDDS1Temp = lpTexI->lpDDSSys1Tex;
}
}
else
lpDDS1Temp = lpTexI->lpDDS1Tex;
DDASSERT(NULL != lpDDS1Temp);
{
CLockD3DST lockObject(lpDevI, DPF_MODNAME, REMIND(""));
if (D3D_OK != (ret=D3DHAL_TextureCreate(lpDevI, &lpBlock->hTex, lpDDS1Temp)))
return ret;
}
}
else
if (lpTexI->lpTMBucket && !(lpDevI->lpD3DHALGlobalDriverData->hwCaps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR))
lpDevI->lpDirect3DI->lpTextureManager->TimeStamp(lpTexI->lpTMBucket);
DDASSERT(lpBlock->hTex);
return D3D_OK;
}
/*
* Load
*/
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DTexture::Load"
#define HEL_BLT_ALPAHPIXELS_BROKEN
HRESULT D3DAPI DIRECT3DTEXTUREI::Load(LPDIRECT3DTEXTURE lpD3DSrc)
{
LPDIRECT3DTEXTUREI this_src;
HRESULT ddrval;
LPDIRECTDRAWSURFACE4 lpDDSSrc, lpDDSDst;
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
// Release in the destructor
/*
* validate parms
*/
TRY
{
if (!VALID_DIRECT3DTEXTURE_PTR(this)) {
D3D_ERR( "Invalid Direct3DTexture pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALID_DIRECT3DTEXTURE_PTR(lpD3DSrc)) {
D3D_ERR( "Invalid Direct3DTexture pointer" );
return DDERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
D3D_ERR( "Exception encountered validating parameters" );
return DDERR_INVALIDPARAMS;
}
this_src = static_cast<LPDIRECT3DTEXTUREI>(lpD3DSrc);
lpDDSSrc = this_src->lpDDSSys;
if (!lpDDSSrc)
lpDDSSrc = this_src->lpDDS;
lpDDSDst = lpDDSSys;
if (!lpDDSDst)
lpDDSDst = lpDDS;
ddrval = CopySurface(lpDDSDst, lpDDSSrc, NULL);
return ddrval;
}
HRESULT D3DAPI DIRECT3DTEXTUREI::Load(LPDIRECT3DTEXTURE2 lpD3DSrc)
{
LPDIRECT3DTEXTUREI this_src;
HRESULT ddrval;
LPDIRECTDRAWSURFACE4 lpDDSSrc, lpDDSDst;
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
// Release in the destructor
/*
* validate parms
*/
TRY
{
this_src = static_cast<LPDIRECT3DTEXTUREI>(lpD3DSrc);
if (!VALID_DIRECT3DTEXTURE2_PTR(this)) {
D3D_ERR( "Invalid Direct3DTexture pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALID_DIRECT3DTEXTURE2_PTR(this_src)) {
D3D_ERR( "Invalid Direct3DTexture pointer" );
return DDERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
D3D_ERR( "Exception encountered validating parameters" );
return DDERR_INVALIDPARAMS;
}
lpDDSSrc = this_src->lpDDSSys;
if (!lpDDSSrc)
lpDDSSrc = this_src->lpDDS;
lpDDSDst = lpDDSSys;
if (!lpDDSDst)
lpDDSDst = lpDDS;
ddrval = CopySurface(lpDDSDst, lpDDSSrc, NULL);
return ddrval;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CopySurface"
HRESULT CopySurface(LPDIRECTDRAWSURFACE4 lpDDSDst,
LPDIRECTDRAWSURFACE4 lpDDSSrc,
LPDIRECTDRAWCLIPPER lpClipper)
{
DDSURFACEDESC2 ddsd;
#ifdef __DD_OPT_SURFACE
DDSURFACEDESC2 ddsdSrc;
BOOL bDstIsOptimized, bSrcIsOptimized;
LPDIRECTDRAWOPTSURFACE pOptSurfSrc = NULL;
LPDIRECTDRAWOPTSURFACE pOptSurfDst = NULL;
#endif //__DD_OPT_SURFACE
HRESULT ddrval=DD_OK;
PALETTEENTRY ppe[256];
LPDIRECTDRAWPALETTE lpDDPalSrc, lpDDPalDst;
int psize;
DDCOLORKEY ckey;
if (!lpDDSSrc || !lpDDSDst) return DD_OK;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddrval = lpDDSDst->GetSurfaceDesc(&ddsd);
#ifdef __DD_OPT_SURFACE
memset(&ddsdSrc, 0, sizeof(ddsdSrc));
ddsdSrc.dwSize = sizeof(ddsdSrc);
ddrval = lpDDSSrc->GetSurfaceDesc(&ddsdSrc);
if (bDstIsOptimized = (ddsd.ddsCaps.dwCaps & DDSCAPS_OPTIMIZED))
{
// Fetch the OptSurface Interface
ddrval = lpDDSDst->QueryInterface (IID_IDirectDrawOptSurface,
(LPVOID *)&pOptSurfDst);
if (ddrval != DD_OK)
{
D3D_ERR( "QI failed for Opt Surfaces" );
goto exit_copy_surf;
}
}
if (bSrcIsOptimized = (ddsdSrc.ddsCaps.dwCaps & DDSCAPS_OPTIMIZED))
{
// Fetch the OptSurface Interface
ddrval = lpDDSDst->QueryInterface (IID_IDirectDrawOptSurface,
(LPVOID *)&pOptSurfSrc);
if (ddrval != DD_OK)
{
D3D_ERR( "QI failed for Opt Surfaces" );
goto exit_copy_surf;
}
}
// Cases:
// Dst=Opt Src=Opt : Copy the surface
// Dst=Opt Src=UnOpt: Optimize the surface
// Dst=UnOpt Src=Opt : UnOptimize and load
// Dst=UnOpt Src=UnOpt: Normal operation
//
if (bDstIsOptimized && bSrcIsOptimized)
{
// Copy the surface
ddrval = pOptSurfSrc->CopyOptimizedSurf (pOptSurfSrc);
if (ddrval != DD_OK)
{
D3D_ERR ("CopyOptimizedSurf failed");
}
goto exit_copy_surf;
}
else if (bDstIsOptimized && !bSrcIsOptimized)
{
LPDIRECTDRAWSURFACE4 pDDS4 = NULL;
// Optimize the surface
ddrval = lpDDSDst->QueryInterface (IID_IDirectDrawSurface4,
(LPVOID *)&pOptSurfSrc);
if (ddrval != DD_OK)
{
D3D_ERR( "QI failed for IID_IDirectDrawSurface4" );
goto exit_copy_surf;
}
ddrval = pOptSurfSrc->LoadUnoptimizedSurf (pDDS4);
if (ddrval != DD_OK)
{
D3D_ERR ("CopyOptimizedSurf failed");
}
pDDS4->Release();
goto exit_copy_surf;
}
else if (!bDstIsOptimized && bSrcIsOptimized)
{
LPDIRECTDRAWOPTSURFACE pDDS4 = NULL;
// ATTENTION: Unoptimize the surface ??
D3D_ERR ("CopyOptimizedSurf failed");
ddrval = D3DERR_OPTTEX_CANNOTCOPY;
goto exit_copy_surf;
}
#endif //__DD_OPT_SURFACE
if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
psize = 256;
} else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) {
psize = 16;
} else {
psize = 0;
}
if (psize) {
ddrval = lpDDSSrc->GetPalette(&lpDDPalSrc);
if (ddrval != DD_OK) {
if (ddrval != DDERR_NOPALETTEATTACHED) {
D3D_ERR("Failed to get palette");
return ddrval;
}
} else {
ddrval = lpDDPalSrc->GetEntries(0, 0, psize, ppe);
if (ddrval != DD_OK) {
D3D_ERR("Failed to get palette entries");
lpDDPalSrc->Release();
return ddrval;
}
lpDDPalSrc->Release();
ddrval = lpDDSDst->GetPalette(&lpDDPalDst);
if (ddrval != DD_OK) {
D3D_ERR("Failed to get palette");
return ddrval;
}
ddrval = lpDDPalDst->SetEntries(0, 0, psize, ppe);
if (ddrval != DD_OK) {
D3D_ERR("Failed to set palette entries");
lpDDPalDst->Release();
return ddrval;
}
lpDDPalDst->Release();
}
}
lpDDSSrc->AddRef();
lpDDSDst->AddRef();
do {
DDSCAPS2 ddscaps;
LPDIRECTDRAWSURFACE4 lpDDSTmp;
LPREGIONLIST lpRegionList = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSSrc)->lpLcl->lpSurfMore->lpRegionList;
if(lpClipper)
{
if(lpRegionList)
{
if(lpRegionList->rdh.nCount &&
lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST)
{
if(lpClipper->SetClipList((LPRGNDATA)lpRegionList, 0) != DD_OK)
{
D3D_ERR("Failed to set clip list");
}
if(lpDDSDst->SetClipper(lpClipper) != DD_OK)
{
D3D_ERR("Failed to detach the clipper");
}
}
}
}
ddrval = lpDDSDst->Blt(NULL, lpDDSSrc,
NULL, DDBLT_WAIT, NULL);
if(lpClipper)
{
if(lpRegionList)
{
if(lpRegionList->rdh.nCount)
{
if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST)
{
if(lpDDSDst->SetClipper(NULL) != DD_OK)
{
D3D_ERR("Failed to detach the clipper");
}
}
lpRegionList->rdh.nCount = 0;
lpRegionList->rdh.nRgnSize = 0;
lpRegionList->rdh.rcBound.left = LONG_MAX;
lpRegionList->rdh.rcBound.right = 0;
lpRegionList->rdh.rcBound.top = LONG_MAX;
lpRegionList->rdh.rcBound.bottom = 0;
}
}
}
if (ddrval == E_NOTIMPL && (psize == 16 || psize == 4 || psize == 2) ) {
DDSURFACEDESC2 ddsd_s, ddsd_d;
LPBYTE psrc, pdst;
DWORD i;
DWORD dwBytesPerLine;
memset(&ddsd_s, 0, sizeof ddsd_s);
memset(&ddsd_d, 0, sizeof ddsd_d);
ddsd_s.dwSize = ddsd_d.dwSize = sizeof(ddsd_s);
if ((ddrval = lpDDSSrc->Lock(NULL, &ddsd_s, DDLOCK_WAIT, NULL)) != DD_OK) {
lpDDSSrc->Release();
lpDDSDst->Release();
D3D_ERR("Failed to lock src surface");
return ddrval;
}
if ((ddrval = lpDDSDst->Lock(NULL, &ddsd_d, DDLOCK_WAIT, NULL)) != DD_OK) {
lpDDSSrc->Unlock(NULL);
lpDDSSrc->Release();
lpDDSDst->Release();
D3D_ERR("Failed to lock dst surface");
return ddrval;
}
switch (psize)
{
case 16: dwBytesPerLine = (ddsd.dwWidth + 1) / 2; break;
case 4: dwBytesPerLine = (ddsd.dwWidth + 3) / 4; break;
case 2: dwBytesPerLine = (ddsd.dwWidth + 7) / 8; break;
}
psrc = (LPBYTE)ddsd_s.lpSurface;
pdst = (LPBYTE)ddsd_d.lpSurface;
for (i = 0; i < ddsd_s.dwHeight; i++) {
memcpy( pdst, psrc, dwBytesPerLine );
psrc += ddsd_s.lPitch;
pdst += ddsd_d.lPitch;
}
lpDDSSrc->Unlock(NULL);
lpDDSDst->Unlock(NULL);
lpDDSSrc->Release(); //Offset the AddRefs before
lpDDSDst->Release();
return D3D_OK;
}
else if (ddrval != DD_OK)
{
lpDDSSrc->Release(); //Offset the AddRefs before
lpDDSDst->Release();
D3D_ERR("Blt failure");
return ddrval;
}
/* Copy color keys */
ddrval = lpDDSSrc->GetColorKey(DDCKEY_DESTBLT, &ckey);
if (DD_OK == ddrval)
lpDDSDst->SetColorKey(DDCKEY_DESTBLT, &ckey);
ddrval = lpDDSSrc->GetColorKey(DDCKEY_SRCBLT, &ckey);
if (DD_OK == ddrval)
lpDDSDst->SetColorKey(DDCKEY_SRCBLT, &ckey);
memset(&ddscaps, 0, sizeof(ddscaps));
ddscaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
ddrval = lpDDSSrc->GetAttachedSurface(&ddscaps, &lpDDSTmp);
lpDDSSrc->Release();
lpDDSSrc = lpDDSTmp;
if (ddrval == DDERR_NOTFOUND) {
// no more surfaces in the chain
lpDDSDst->Release();
break;
} else if (ddrval != DD_OK) {
lpDDSDst->Release();
D3D_ERR("GetAttachedSurface failed with something other than DDERR_NOTFOUND.");
return ddrval;
}
memset(&ddscaps, 0, sizeof(ddscaps));
ddscaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
ddrval = lpDDSDst->GetAttachedSurface(&ddscaps, &lpDDSTmp);
lpDDSDst->Release();
lpDDSDst = lpDDSTmp;
if (ddrval == DDERR_NOTFOUND) {
lpDDSSrc->Release();
D3D_ERR("Destination texture has fewer attached mipmap surfaces than source.");
return ddrval;
} else if (ddrval != DD_OK) {
lpDDSSrc->Release();
D3D_ERR("GetAttachedSurface failed with something other than DDERR_NOTFOUND.");
return ddrval;
}
} while (1);
return D3D_OK;
#ifdef __DD_OPT_SURFACE
exit_copy_surf:
// Job done, release any optimized surface interfaces
if (pOptSurfSrc)
{
pOptSurfSrc->Release();
pOptSurfSrc = NULL;
}
if (pOptSurfDst)
{
pOptSurfDst->Release();
pOptSurfDst = NULL;
}
return ddrval;
#endif //__DD_OPT_SURFACE
}
/*
* Unload
*/
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DTexture::Unload"
HRESULT D3DAPI DIRECT3DTEXTUREI::Unload()
{
HRESULT ret = D3D_OK;
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
// Release in the destructor
/*
* validate parms
*/
TRY
{
if (!VALID_DIRECT3DTEXTURE_PTR(this)) {
D3D_ERR( "Invalid Direct3DTexture pointer" );
return DDERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
D3D_ERR( "Exception encountered validating parameters" );
return DDERR_INVALIDPARAMS;
}
return (ret);
}
/*
* PaletteChanged
*/
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DTexture::PaletteChanged"
HRESULT D3DAPI DIRECT3DTEXTUREI::PaletteChanged(DWORD dwStart, DWORD dwCount)
{
HRESULT ret = D3D_OK;
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
// Release in the destructor
/*
* validate parms
*/
TRY
{
if (!VALID_DIRECT3DTEXTURE_PTR(this)) {
D3D_ERR( "Invalid Direct3DTexture pointer" );
return DDERR_INVALIDOBJECT;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
D3D_ERR( "Exception encountered validating parameters" );
return DDERR_INVALIDPARAMS;
}
// if haven't mapped to a device yet, can ignore this call, since will
// be creating the ramp palette from scratch anyway.
LPD3DI_TEXTUREBLOCK tBlock = LIST_FIRST(&this->blocks);
while (tBlock) {
if (tBlock->hTex)
{
if(tBlock->lpDevI->pfnRampService!=NULL)
{
ret = CallRampService(tBlock->lpDevI, RAMP_SERVICE_PALETTE_CHANGED,tBlock->hTex,0);
}
}
tBlock=LIST_NEXT(tBlock,list);
}
return (ret);
}