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.
3360 lines
106 KiB
3360 lines
106 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1994-1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: ddsprite.c
|
|
* Content: DirectDraw Surface support for sprite display lists:
|
|
* SetSpriteDisplayList
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 03-nov-97 jvanaken Original version
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "ddrawpr.h"
|
|
|
|
// function from ddraw module ddclip.c
|
|
extern HRESULT InternalGetClipList(LPDIRECTDRAWCLIPPER,
|
|
LPRECT,
|
|
LPRGNDATA,
|
|
LPDWORD,
|
|
LPDDRAWI_DIRECTDRAW_GBL);
|
|
|
|
#define _DDHAL_SetSpriteDisplayList NULL
|
|
|
|
/*
|
|
* Masks for distinguishing driver's blit caps from driver's overlay caps.
|
|
*/
|
|
#define DDFXCAPS_BLTBITS \
|
|
(DDFXCAPS_BLTALPHA|DDFXCAPS_BLTFILTER|DDFXCAPS_BLTTRANSFORM)
|
|
|
|
#define DDFXCAPS_OVERLAYBITS \
|
|
(DDFXCAPS_OVERLAYALPHA|DDFXCAPS_OVERLAYFILTER|DDFXCAPS_OVERLAYTRANSFORM)
|
|
|
|
#define DDCKEYCAPS_BLTBITS (DDCKEYCAPS_SRCBLT|DDCKEYCAPS_DESTBLT)
|
|
|
|
#define DDCKEYCAPS_OVERLAYBITS (DDCKEYCAPS_SRCOVERLAY|DDCKEYCAPS_DESTOVERLAY)
|
|
|
|
#define DDALPHACAPS_BLTBITS \
|
|
(DDALPHACAPS_BLTSATURATE|DDALPHACAPS_BLTPREMULT| \
|
|
DDALPHACAPS_BLTNONPREMULT|DDALPHACAPS_BLTRGBASCALE1F| \
|
|
DDALPHACAPS_BLTRGBASCALE2F|DDALPHACAPS_BLTRGBASCALE4F)
|
|
|
|
#define DDALPHACAPS_OVERLAYBITS \
|
|
(DDALPHACAPS_OVERLAYSATURATE|DDALPHACAPS_OVERLAYPREMULT| \
|
|
DDALPHACAPS_OVERLAYNONPREMULT|DDALPHACAPS_OVERLAYRGBASCALE1F| \
|
|
DDALPHACAPS_OVERLAYRGBASCALE2F|DDALPHACAPS_OVERLAYRGBASCALE4F)
|
|
|
|
#define DDFILTCAPS_BLTBITS \
|
|
(DDFILTCAPS_BLTBILINEARFILTER|DDFILTCAPS_BLTBLURFILTER| \
|
|
DDFILTCAPS_BLTFLATFILTER)
|
|
|
|
#define DDFILTCAPS_OVERLAYBITS \
|
|
(DDFILTCAPS_OVERLAYBILINEARFILTER|DDFILTCAPS_OVERLAYBLURFILTER| \
|
|
DDFILTCAPS_OVERLAYFLATFILTER)
|
|
|
|
#define DDTFRMCAPS_BLTBITS (DDTFRMCAPS_BLTAFFINETRANSFORM)
|
|
|
|
#define DDTFRMCAPS_OVERLAYBITS (DDTFRMCAPS_OVERLAYAFFINETRANSFORM)
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "SetSpriteDisplayList"
|
|
|
|
/*
|
|
* Driver capabilities for handling current sprite
|
|
*/
|
|
typedef struct
|
|
{
|
|
// caps for hardware driver
|
|
//DWORD dwCaps;
|
|
DWORD dwCKeyCaps;
|
|
DWORD dwFXCaps;
|
|
DWORD dwAlphaCaps;
|
|
DWORD dwFilterCaps;
|
|
DWORD dwTransformCaps;
|
|
|
|
// caps for HEL
|
|
//DWORD dwHELCaps;
|
|
DWORD dwHELCKeyCaps;
|
|
DWORD dwHELFXCaps;
|
|
DWORD dwHELAlphaCaps;
|
|
DWORD dwHELFilterCaps;
|
|
DWORD dwHELTransformCaps;
|
|
|
|
// surface caps
|
|
DWORD dwDestSurfCaps;
|
|
DWORD dwSrcSurfCaps;
|
|
|
|
// minification limit
|
|
DWORD dwMinifyLimit;
|
|
DWORD dwHELMinifyLimit;
|
|
|
|
BOOL bNoHAL; // TRUE disqualifies hardware driver
|
|
BOOL bNoHEL; // TRUE disqualifies HEL
|
|
|
|
// TRUE=overlay sprite, FALSE=blitted sprite
|
|
BOOL bOverlay;
|
|
|
|
} SPRITE_CAPS, *LPSPRITE_CAPS;
|
|
|
|
|
|
/*
|
|
* The master sprite display list consists of some number of sublists.
|
|
* Each sublist contains all the overlay sprites that are displayed
|
|
* within a particular window. Only the first member of the variable-
|
|
* size sprite[] array appears explicitly in the structure definition
|
|
* below, but dwSize takes into account the ENTIRE sprite[] array.
|
|
* The pRgn member points to the dynamically allocated buffer that
|
|
* contains the clipping region.
|
|
*/
|
|
typedef struct _SPRITESUBLIST
|
|
{
|
|
DWORD dwSize; // size of this sublist (in bytes)
|
|
LPDIRECTDRAWSURFACE pPrimary; // primary surface
|
|
LPDIRECTDRAWCLIPPER pClipper; // clipper for window (NULL = full screen)
|
|
DWORD dwProcessId; // process ID (in case pClipper is NULL)
|
|
LPRGNDATA pRgn; // pointer to clipping region data
|
|
DWORD dwCount; // number of sprites in sublist
|
|
DDSPRITEI sprite[1]; // array of sprites (first member)
|
|
} SPRITESUBLIST, *LPSPRITESUBLIST;
|
|
|
|
/*
|
|
* Buffer used to hold temporary sprite display list passed to driver.
|
|
* Only the first member of the variable-size pSprites[] array appears
|
|
* explicitly in the structure definition below, but the dwSize value
|
|
* takes into account the ENTIRE pSprite[] array.
|
|
*/
|
|
typedef struct _BUFFER
|
|
{
|
|
DWORD dwSize; // size of this buffer (in bytes)
|
|
DDHAL_SETSPRITEDISPLAYLISTDATA HalData; // HAL data for sprite display list
|
|
LPDDSPRITEI pSprite[1]; // array of pointers to sprites
|
|
} BUFFER, *LPBUFFER;
|
|
|
|
/*
|
|
* Master sprite display list -- Contains copies of the overlay-sprite
|
|
* display lists for all windows that currently display overlay sprites.
|
|
* Only the first member of the variable-size spriteSubList[] array
|
|
* appears explicitly in the structure definition below. Each sublist
|
|
* contains all the overlay sprites displayed within a particular window.
|
|
*/
|
|
#define MAXNUMSPRITESUBLISTS (16)
|
|
|
|
typedef struct _MASTERSPRITELIST
|
|
{
|
|
//DWORD dwSize; // size of master list (in bytes)
|
|
LPDDRAWI_DIRECTDRAW_GBL pdrv; // global DDraw object
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl; // primary surface (local object)
|
|
RECT rcPrimary; // rectangle = entire primary surface
|
|
DWORD dwFlags; // latest caller's DDSSDL_WAIT flag
|
|
#ifdef WIN95
|
|
DWORD dwModeCreatedIn; // valid only in this video mode
|
|
#else
|
|
DISPLAYMODEINFO dmiCreated; // valid only in this video mode
|
|
#endif
|
|
LPBUFFER pBuffer; // buffer storage
|
|
DWORD dwNumSubLists; // number of sprite sublists
|
|
LPSPRITESUBLIST pSubList[MAXNUMSPRITESUBLISTS]; // array of sublists (fixed size)
|
|
} MASTERSPRITELIST, *LPMASTERSPRITELIST;
|
|
|
|
|
|
/*
|
|
* Return the dwFlags member from the DDPIXELFORMAT structure
|
|
* that describes the specified surface's pixel format.
|
|
*/
|
|
static DWORD getPixelFormatFlags(LPDDRAWI_DDRAWSURFACE_LCL surf_lcl)
|
|
{
|
|
LPDDPIXELFORMAT pDDPF;
|
|
|
|
if (surf_lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT)
|
|
{
|
|
// surface contains explicitly defined pixel format
|
|
pDDPF = &surf_lcl->lpGbl->ddpfSurface;
|
|
}
|
|
else
|
|
{
|
|
// surface's pixel format is implicit -- same as primary's
|
|
pDDPF = &surf_lcl->lpSurfMore->lpDD_lcl->lpGbl->vmiData.ddpfDisplay;
|
|
}
|
|
return pDDPF->dwFlags;
|
|
|
|
} /* getPixelFormatFlags */
|
|
|
|
|
|
/*
|
|
* Initialize SPRITE_CAPS structure according to whether source and
|
|
* dest surfaces are in system or video (local or nonlocal) memory.
|
|
*/
|
|
static void initSpriteCaps(LPSPRITE_CAPS pcaps, LPDDRAWI_DIRECTDRAW_GBL pdrv)
|
|
{
|
|
DDASSERT(pcaps != NULL);
|
|
|
|
if (pcaps->bOverlay)
|
|
{
|
|
// Get minification limits for overlays.
|
|
pcaps->dwMinifyLimit = pdrv->lpddMoreCaps->dwOverlayAffineMinifyLimit;
|
|
pcaps->dwHELMinifyLimit = pdrv->lpddHELMoreCaps->dwOverlayAffineMinifyLimit;
|
|
}
|
|
else
|
|
{
|
|
// Get minification limits for blits.
|
|
pcaps->dwMinifyLimit = pdrv->lpddMoreCaps->dwBltAffineMinifyLimit;
|
|
pcaps->dwHELMinifyLimit = pdrv->lpddHELMoreCaps->dwBltAffineMinifyLimit;
|
|
}
|
|
|
|
if (pcaps->dwSrcSurfCaps & DDSCAPS_NONLOCALVIDMEM &&
|
|
pdrv->ddCaps.dwCaps2 & DDCAPS2_NONLOCALVIDMEMCAPS)
|
|
{
|
|
/*
|
|
* A driver that specifies nonlocal video-memory caps that differ
|
|
* from its local video-memory caps is automatically disqualified
|
|
* because the currently specified nonlocal vidmem caps do not
|
|
* include alpha, filter, or transform caps. Should we fix this?
|
|
*/
|
|
pcaps->bNoHAL = TRUE;
|
|
}
|
|
|
|
if ((pcaps->dwSrcSurfCaps | pcaps->dwDestSurfCaps) & DDSCAPS_SYSTEMMEMORY &&
|
|
!(pdrv->ddCaps.dwCaps & DDCAPS_CANBLTSYSMEM))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // H/W driver can't blit to/from system memory
|
|
}
|
|
|
|
if (pcaps->dwSrcSurfCaps & pcaps->dwDestSurfCaps & DDSCAPS_VIDEOMEMORY)
|
|
{
|
|
//pcaps->dwCaps = pdrv->ddCaps.dwCaps;
|
|
pcaps->dwCKeyCaps = pdrv->ddCaps.dwCKeyCaps;
|
|
pcaps->dwFXCaps = pdrv->ddCaps.dwFXCaps;
|
|
if (pdrv->lpddMoreCaps)
|
|
{
|
|
pcaps->dwAlphaCaps = pdrv->lpddMoreCaps->dwAlphaCaps;
|
|
pcaps->dwFilterCaps = pdrv->lpddMoreCaps->dwFilterCaps;
|
|
pcaps->dwTransformCaps = pdrv->lpddMoreCaps->dwTransformCaps;
|
|
}
|
|
|
|
//pcaps->dwHELCaps = pdrv->ddHELCaps.dwCaps;
|
|
pcaps->dwHELCKeyCaps = pdrv->ddHELCaps.dwCKeyCaps;
|
|
pcaps->dwHELFXCaps = pdrv->ddHELCaps.dwFXCaps;
|
|
if (pdrv->lpddHELMoreCaps)
|
|
{
|
|
pcaps->dwHELAlphaCaps = pdrv->lpddHELMoreCaps->dwAlphaCaps;
|
|
pcaps->dwHELFilterCaps = pdrv->lpddHELMoreCaps->dwFilterCaps;
|
|
pcaps->dwHELTransformCaps = pdrv->lpddHELMoreCaps->dwTransformCaps;
|
|
}
|
|
}
|
|
else if (pcaps->dwSrcSurfCaps & DDSCAPS_SYSTEMMEMORY &&
|
|
pcaps->dwDestSurfCaps & DDSCAPS_VIDEOMEMORY)
|
|
{
|
|
//pcaps->dwCaps = pdrv->ddCaps.dwSVBCaps;
|
|
pcaps->dwCKeyCaps = pdrv->ddCaps.dwSVBCKeyCaps;
|
|
pcaps->dwFXCaps = pdrv->ddCaps.dwSVBFXCaps;
|
|
if (pdrv->lpddMoreCaps)
|
|
{
|
|
pcaps->dwAlphaCaps = pdrv->lpddMoreCaps->dwSVBAlphaCaps;
|
|
pcaps->dwFilterCaps = pdrv->lpddMoreCaps->dwSVBFilterCaps;
|
|
pcaps->dwTransformCaps = pdrv->lpddMoreCaps->dwSVBTransformCaps;
|
|
}
|
|
|
|
//pcaps->dwHELCaps = pdrv->ddHELCaps.dwSVBCaps;
|
|
pcaps->dwHELCKeyCaps = pdrv->ddHELCaps.dwSVBCKeyCaps;
|
|
pcaps->dwHELFXCaps = pdrv->ddHELCaps.dwSVBFXCaps;
|
|
if (pdrv->lpddHELMoreCaps)
|
|
{
|
|
pcaps->dwHELAlphaCaps = pdrv->lpddHELMoreCaps->dwSVBAlphaCaps;
|
|
pcaps->dwHELFilterCaps = pdrv->lpddHELMoreCaps->dwSVBFilterCaps;
|
|
pcaps->dwHELTransformCaps = pdrv->lpddHELMoreCaps->dwSVBTransformCaps;
|
|
}
|
|
}
|
|
else if (pcaps->dwSrcSurfCaps & DDSCAPS_VIDEOMEMORY &&
|
|
pcaps->dwDestSurfCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
//pcaps->dwCaps = pdrv->ddCaps.dwVSBCaps;
|
|
pcaps->dwCKeyCaps = pdrv->ddCaps.dwVSBCKeyCaps;
|
|
pcaps->dwFXCaps = pdrv->ddCaps.dwVSBFXCaps;
|
|
if (pdrv->lpddMoreCaps)
|
|
{
|
|
pcaps->dwAlphaCaps = pdrv->lpddMoreCaps->dwVSBAlphaCaps;
|
|
pcaps->dwFilterCaps = pdrv->lpddMoreCaps->dwVSBFilterCaps;
|
|
pcaps->dwTransformCaps = pdrv->lpddMoreCaps->dwVSBTransformCaps;
|
|
}
|
|
|
|
//pcaps->dwHELCaps = pdrv->ddHELCaps.dwVSBCaps;
|
|
pcaps->dwHELCKeyCaps = pdrv->ddHELCaps.dwVSBCKeyCaps;
|
|
pcaps->dwHELFXCaps = pdrv->ddHELCaps.dwVSBFXCaps;
|
|
if (pdrv->lpddHELMoreCaps)
|
|
{
|
|
pcaps->dwHELAlphaCaps = pdrv->lpddHELMoreCaps->dwVSBAlphaCaps;
|
|
pcaps->dwHELFilterCaps = pdrv->lpddHELMoreCaps->dwVSBFilterCaps;
|
|
pcaps->dwHELTransformCaps = pdrv->lpddHELMoreCaps->dwVSBTransformCaps;
|
|
}
|
|
}
|
|
else if (pcaps->dwSrcSurfCaps & pcaps->dwDestSurfCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
//pcaps->dwCaps = pdrv->ddCaps.dwSSBCaps;
|
|
pcaps->dwCKeyCaps = pdrv->ddCaps.dwSSBCKeyCaps;
|
|
pcaps->dwFXCaps = pdrv->ddCaps.dwSSBFXCaps;
|
|
if (pdrv->lpddMoreCaps)
|
|
{
|
|
pcaps->dwAlphaCaps = pdrv->lpddMoreCaps->dwSSBAlphaCaps;
|
|
pcaps->dwFilterCaps = pdrv->lpddMoreCaps->dwSSBFilterCaps;
|
|
pcaps->dwTransformCaps = pdrv->lpddMoreCaps->dwSSBTransformCaps;
|
|
}
|
|
|
|
//pcaps->dwHELCaps = pdrv->ddHELCaps.dwSSBCaps;
|
|
pcaps->dwHELCKeyCaps = pdrv->ddHELCaps.dwSSBCKeyCaps;
|
|
pcaps->dwHELFXCaps = pdrv->ddHELCaps.dwSSBFXCaps;
|
|
if (pdrv->lpddHELMoreCaps)
|
|
{
|
|
pcaps->dwHELAlphaCaps = pdrv->lpddHELMoreCaps->dwSSBAlphaCaps;
|
|
pcaps->dwHELFilterCaps = pdrv->lpddHELMoreCaps->dwSSBFilterCaps;
|
|
pcaps->dwHELTransformCaps = pdrv->lpddHELMoreCaps->dwSSBTransformCaps;
|
|
}
|
|
}
|
|
|
|
if (pcaps->bOverlay)
|
|
{
|
|
// Isolate overlay bits by masking off all blit-related bits.
|
|
//pcaps->dwCaps &= DDCAPS_OVERLAYBITS;
|
|
pcaps->dwCKeyCaps &= DDCKEYCAPS_OVERLAYBITS;
|
|
pcaps->dwFXCaps &= DDFXCAPS_OVERLAYBITS;
|
|
pcaps->dwAlphaCaps &= DDALPHACAPS_OVERLAYBITS;
|
|
pcaps->dwFilterCaps &= DDFILTCAPS_OVERLAYBITS;
|
|
pcaps->dwTransformCaps &= DDTFRMCAPS_OVERLAYBITS;
|
|
|
|
//pcaps->dwHELCaps &= DDCAPS_OVERLAYBITS;
|
|
pcaps->dwHELCKeyCaps &= DDCKEYCAPS_OVERLAYBITS;
|
|
pcaps->dwHELFXCaps &= DDFXCAPS_OVERLAYBITS;
|
|
pcaps->dwHELAlphaCaps &= DDALPHACAPS_OVERLAYBITS;
|
|
pcaps->dwHELFilterCaps &= DDFILTCAPS_OVERLAYBITS;
|
|
pcaps->dwHELTransformCaps &= DDTFRMCAPS_OVERLAYBITS;
|
|
}
|
|
else
|
|
{
|
|
// Isolate blit bits by masking off all overlay-related bits.
|
|
//pcaps->dwCaps &= DDCAPS_BLTBITS;
|
|
pcaps->dwCKeyCaps &= DDCKEYCAPS_BLTBITS;
|
|
pcaps->dwFXCaps &= DDFXCAPS_BLTBITS;
|
|
pcaps->dwAlphaCaps &= DDALPHACAPS_BLTBITS;
|
|
pcaps->dwFilterCaps &= DDFILTCAPS_BLTBITS;
|
|
pcaps->dwTransformCaps &= DDTFRMCAPS_BLTBITS;
|
|
|
|
//pcaps->dwHELCaps &= DDCAPS_BLTBITS;
|
|
pcaps->dwHELCKeyCaps &= DDCKEYCAPS_BLTBITS;
|
|
pcaps->dwHELFXCaps &= DDFXCAPS_BLTBITS;
|
|
pcaps->dwHELAlphaCaps &= DDALPHACAPS_BLTBITS;
|
|
pcaps->dwHELFilterCaps &= DDFILTCAPS_BLTBITS;
|
|
pcaps->dwHELTransformCaps &= DDTFRMCAPS_BLTBITS;
|
|
}
|
|
} /* initSpriteCaps */
|
|
|
|
|
|
/*
|
|
* Verify that affine transform does not exceed driver's minification
|
|
* limit. Arg pdrv is a pointer to the global DirectDraw object. Arg
|
|
* lpDDSpriteFX points to a DDSPRITEFX structure containing 4x4 matrix.
|
|
* Arg overlay is TRUE for overlay sprites, and FALSE for blitted
|
|
* sprites. Arg emulation is TRUE if the overlay is to be emulated.
|
|
* Returns DD_OK if specified affine transform is within limits.
|
|
*/
|
|
static void checkMinification(LPDDSPRITEFX lpDDSpriteFX,
|
|
LPSPRITE_CAPS pcaps)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 2; ++i)
|
|
{
|
|
FLOAT a00, a01, a10, a11, det, amax;
|
|
DWORD minlim;
|
|
|
|
/*
|
|
* Get driver's minification limit.
|
|
*/
|
|
if (i == 0)
|
|
{
|
|
// Get hardware driver's minification limit.
|
|
minlim = pcaps->dwMinifyLimit;
|
|
|
|
if (pcaps->bNoHAL || minlim == 0) // minlim = 0 means no limit
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Get HEL's minification limit.
|
|
minlim = pcaps->dwHELMinifyLimit;
|
|
|
|
if (pcaps->bNoHEL || minlim == 0)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check transformation matrix against driver's minification limit.
|
|
*/
|
|
a00 = lpDDSpriteFX->fTransform[0][0];
|
|
a01 = lpDDSpriteFX->fTransform[0][1];
|
|
a10 = lpDDSpriteFX->fTransform[1][0];
|
|
a11 = lpDDSpriteFX->fTransform[1][1];
|
|
// Calculate determinant of Jacobian.
|
|
det = a00*a11 - a10*a01;
|
|
// Get absolute values of the 4 Jacobian coefficients.
|
|
if (a00 < 0) // could have used fabs() here
|
|
a00 = -a00;
|
|
if (a01 < 0)
|
|
a01 = -a01;
|
|
if (a10 < 0)
|
|
a10 = -a10;
|
|
if (a11 < 0)
|
|
a11 = -a11;
|
|
if (det < 0)
|
|
det = -det;
|
|
// Find biggest coefficient in Jacobian.
|
|
amax = a00;
|
|
if (a01 > amax)
|
|
amax = a01;
|
|
if (a10 > amax)
|
|
amax = a10;
|
|
if (a11 > amax)
|
|
amax = a11;
|
|
// Test the minification level against the driver's limit.
|
|
if (1000*amax >= det*minlim)
|
|
{
|
|
// Affine transform exceeds driver's minification limit.
|
|
if (i == 0)
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
else
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
}
|
|
}
|
|
} /* checkMinification */
|
|
|
|
|
|
/*
|
|
* Validate the DDSPRITE structure. Arg pSprite is a pointer to a
|
|
* DDSPRITE structure. Arg pdrv is a pointer to the dest surface's
|
|
* DirectDraw object. Arg dest_lcl is a pointer to the destination
|
|
* surface. Arg pcaps is a pointer to a structure containing the
|
|
* driver's capabilities. Returns DD_OK if successful.
|
|
*/
|
|
static HRESULT validateSprite(LPDDSPRITE pSprite,
|
|
LPDDRAWI_DIRECTDRAW_GBL pdrv,
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_dest_lcl,
|
|
LPSPRITE_CAPS pcaps,
|
|
DWORD dwDDPFDestFlags)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_src_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_src_lcl;
|
|
LPDDRAWI_DDRAWSURFACE_GBL surf_src;
|
|
DWORD dwDDPFSrcFlags;
|
|
LPRECT prSrc;
|
|
LPRECT prDest;
|
|
DWORD dest_width = 0;
|
|
DWORD dest_height = 0;
|
|
DWORD src_width = 0;
|
|
DWORD src_height = 0;
|
|
|
|
DDASSERT(!(pcaps->bNoHAL && pcaps->bNoHEL));
|
|
|
|
/*
|
|
* Validate the DDSPRITE pointer. (A caller that does not use the
|
|
* embedded DDSPRITEFX structure must still alloc space for it.)
|
|
*/
|
|
if (IsBadWritePtr((LPVOID)pSprite, (UINT)sizeof(DDSPRITE)))
|
|
{
|
|
DPF_ERR("Bad pointer to DDSPRITE structure...");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
/*
|
|
* If the caller doesn't use the embedded DDSPRITEFX struct,
|
|
* we'll fill it in ourselves before passing it to the driver.
|
|
*/
|
|
if (!(pSprite->dwFlags & DDSPRITE_DDSPRITEFX))
|
|
{
|
|
if (pSprite->dwFlags & (DDSPRITE_KEYDESTOVERRIDE | DDSPRITE_KEYSRCOVERRIDE))
|
|
{
|
|
DPF_ERR("Illegal to set color-key override if DDSPRITEFX is invalid");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
pSprite->ddSpriteFX.dwSize = sizeof(DDSPRITEFX);
|
|
pSprite->ddSpriteFX.dwDDFX = 0;
|
|
pSprite->dwFlags |= DDSPRITE_DDSPRITEFX;
|
|
}
|
|
|
|
/*
|
|
* Validate the source surface for the sprite.
|
|
*/
|
|
surf_src_int = (LPDDRAWI_DDRAWSURFACE_INT)pSprite->lpDDSSrc;
|
|
|
|
if (!VALID_DIRECTDRAWSURFACE_PTR(surf_src_int))
|
|
{
|
|
DPF_ERR("Invalid source surface pointer...");
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
surf_src_lcl = surf_src_int->lpLcl;
|
|
surf_src = surf_src_lcl->lpGbl;
|
|
|
|
if (SURFACE_LOST(surf_src_lcl))
|
|
{
|
|
DPF_ERR("Lost source surface...");
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
|
|
/*
|
|
* We cannot use source and destination surfaces that were
|
|
* created with different DirectDraw objects.
|
|
*/
|
|
if (surf_src->lpDD != pdrv
|
|
&& surf_src->lpDD->dwFlags & DDRAWI_DISPLAYDRV &&
|
|
pdrv->dwFlags & DDRAWI_DISPLAYDRV)
|
|
{
|
|
DPF_ERR("Source and dest surfaces must have same DirectDraw device...");
|
|
LEAVE_BOTH();
|
|
return DDERR_DEVICEDOESNTOWNSURFACE;
|
|
}
|
|
|
|
/*
|
|
* Validate destination rectangle.
|
|
*/
|
|
prDest = &pSprite->rcDest;
|
|
|
|
if (pSprite->dwFlags & DDSPRITE_RECTDEST)
|
|
{
|
|
// Validate destination rectangle specified in rcDest member.
|
|
dest_height = prDest->bottom - prDest->top;
|
|
dest_width = prDest->right - prDest->left;
|
|
if ((int)dest_height <= 0 || (int)dest_width <= 0)
|
|
{
|
|
DPF_ERR("Invalid destination rectangle...");
|
|
return DDERR_INVALIDRECT;
|
|
}
|
|
if (pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_AFFINETRANSFORM)
|
|
{
|
|
DPF_ERR("Illegal to specify both dest rect and affine transform...");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
else if (!(pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_AFFINETRANSFORM))
|
|
{
|
|
/*
|
|
* The implicit destination is the entire dest surface. Substitute
|
|
* an explicit destination rectangle that covers the dest surface.
|
|
*/
|
|
MAKE_SURF_RECT(surf_dest_lcl->lpGbl, surf_dest_lcl, pSprite->rcDest);
|
|
pSprite->dwFlags |= DDSPRITE_RECTDEST;
|
|
}
|
|
|
|
/*
|
|
* Validate source rectangle.
|
|
*/
|
|
prSrc = &pSprite->rcSrc;
|
|
|
|
if (pSprite->dwFlags & DDSPRITE_RECTSRC)
|
|
{
|
|
// Validate source rectangle specified in rcSrc member.
|
|
src_height = prSrc->bottom - prSrc->top;
|
|
src_width = prSrc->right - prSrc->left;
|
|
if (((int)src_height <= 0) || ((int)src_width <= 0) ||
|
|
((int)prSrc->top < 0) || ((int)prSrc->left < 0) ||
|
|
((DWORD) prSrc->bottom > (DWORD) surf_src->wHeight) ||
|
|
((DWORD) prSrc->right > (DWORD) surf_src->wWidth))
|
|
{
|
|
DPF_ERR("Invalid source rectangle...");
|
|
return DDERR_INVALIDRECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The implicit source rect is the entire dest surface. Substitute
|
|
* an explicit source rectangle that covers the source surface.
|
|
*/
|
|
MAKE_SURF_RECT(surf_src, surf_src_lcl, pSprite->rcSrc);
|
|
pSprite->dwFlags |= DDSPRITE_RECTSRC;
|
|
}
|
|
|
|
/*
|
|
* Validate memory alignment of source and dest rectangles.
|
|
*/
|
|
if (pdrv->ddCaps.dwCaps & (DDCAPS_ALIGNBOUNDARYDEST | DDCAPS_ALIGNSIZEDEST |
|
|
DDCAPS_ALIGNBOUNDARYSRC | DDCAPS_ALIGNSIZESRC))
|
|
{
|
|
if (pdrv->ddCaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST &&
|
|
(prDest->left % pdrv->ddCaps.dwAlignBoundaryDest) != 0)
|
|
{
|
|
DPF_ERR("Destination left misaligned...");
|
|
return DDERR_XALIGN;
|
|
}
|
|
if (pdrv->ddCaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC &&
|
|
(prSrc->left % pdrv->ddCaps.dwAlignBoundarySrc) != 0)
|
|
{
|
|
DPF_ERR("Source left misaligned...");
|
|
return DDERR_XALIGN;
|
|
}
|
|
|
|
if (pdrv->ddCaps.dwCaps & DDCAPS_ALIGNSIZEDEST &&
|
|
(dest_width % pdrv->ddCaps.dwAlignSizeDest) != 0)
|
|
{
|
|
DPF_ERR("Destination width misaligned...");
|
|
return DDERR_XALIGN;
|
|
}
|
|
|
|
if (pdrv->ddCaps.dwCaps & DDCAPS_ALIGNSIZESRC &&
|
|
(src_width % pdrv->ddCaps.dwAlignSizeSrc) != 0)
|
|
{
|
|
DPF_ERR("Source width misaligned...");
|
|
return DDERR_XALIGN;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Are the source surface's caps the same as those of the previous sprite?
|
|
*/
|
|
if ((surf_src_lcl->ddsCaps.dwCaps ^ pcaps->dwSrcSurfCaps) &
|
|
(DDSCAPS_SYSTEMMEMORY | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM))
|
|
{
|
|
/*
|
|
* This source surface's memory type differs from that of the
|
|
* previous source surface, so we need to get a new set of caps.
|
|
*/
|
|
pcaps->dwSrcSurfCaps = surf_src_lcl->ddsCaps.dwCaps;
|
|
initSpriteCaps(pcaps, pdrv);
|
|
}
|
|
|
|
/*
|
|
* Get pixel-format flags for source surface.
|
|
*/
|
|
dwDDPFSrcFlags = getPixelFormatFlags(surf_src_lcl);
|
|
|
|
/*
|
|
* If the source surface is palette-indexed, make sure a palette
|
|
* is attached to it.
|
|
*/
|
|
if (dwDDPFSrcFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 |
|
|
DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8) &&
|
|
(surf_src_lcl->lpDDPalette == NULL ||
|
|
surf_src_lcl->lpDDPalette->lpLcl->lpGbl->lpColorTable == NULL))
|
|
{
|
|
DPF_ERR( "No palette associated with palette-indexed surface..." );
|
|
LEAVE_BOTH();
|
|
return DDERR_NOPALETTEATTACHED;
|
|
}
|
|
|
|
/*
|
|
* Is any color keying required for this sprite?
|
|
*/
|
|
if (pSprite->dwFlags & (DDSPRITE_KEYSRC | DDSPRITE_KEYSRCOVERRIDE |
|
|
DDSPRITE_KEYDEST | DDSPRITE_KEYDESTOVERRIDE))
|
|
{
|
|
/*
|
|
* Validate source color-key flag.
|
|
*/
|
|
if (pSprite->dwFlags & (DDSPRITE_KEYSRC | DDSPRITE_KEYSRCOVERRIDE))
|
|
{
|
|
if (!(pcaps->dwCKeyCaps & (DDCKEYCAPS_SRCBLT | DDCKEYCAPS_SRCOVERLAY)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELCKeyCaps & (DDCKEYCAPS_SRCBLT | DDCKEYCAPS_SRCOVERLAY)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
if (dwDDPFSrcFlags & DDPF_ALPHAPIXELS)
|
|
{
|
|
DPF_ERR("KEYSRC* illegal with source alpha channel...");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (pSprite->dwFlags & DDSPRITE_KEYSRC)
|
|
{
|
|
if (!(!pcaps->bOverlay && surf_src_lcl->dwFlags & DDRAWISURF_HASCKEYSRCBLT ||
|
|
pcaps->bOverlay && surf_src_lcl->dwFlags & DDRAWISURF_HASCKEYSRCOVERLAY))
|
|
{
|
|
DPF_ERR("KEYSRC specified, but no color key...");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (pSprite->dwFlags & DDSPRITE_KEYSRCOVERRIDE)
|
|
{
|
|
DPF_ERR("Illegal to specify both KEYSRC and KEYSRCOVERRIDE...");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
// Copy color key value from surface into DDSPRITEFX struct.
|
|
pSprite->ddSpriteFX.ddckSrcColorkey = (pcaps->bOverlay) ?
|
|
surf_src_lcl->ddckCKSrcOverlay :
|
|
surf_src_lcl->ddckCKSrcBlt;
|
|
// Turn off KEYSRC, turn on KEYSRCOVERRIDE.
|
|
pSprite->dwFlags ^= DDSPRITE_KEYSRC | DDSPRITE_KEYSRCOVERRIDE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Validate destination color-key flag.
|
|
*/
|
|
if (pSprite->dwFlags & (DDSPRITE_KEYDEST | DDSPRITE_KEYDESTOVERRIDE))
|
|
{
|
|
if (!(pcaps->dwCKeyCaps & (DDCKEYCAPS_DESTBLT | DDCKEYCAPS_DESTOVERLAY)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELCKeyCaps & (DDCKEYCAPS_DESTBLT | DDCKEYCAPS_DESTOVERLAY)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
if (dwDDPFDestFlags & DDPF_ALPHAPIXELS)
|
|
{
|
|
DPF_ERR("KEYDEST* illegal with dest alpha channel...");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (pSprite->dwFlags & DDSPRITE_KEYDEST)
|
|
{
|
|
if (!(!pcaps->bOverlay && surf_dest_lcl->dwFlags & DDRAWISURF_HASCKEYDESTBLT ||
|
|
pcaps->bOverlay && surf_dest_lcl->dwFlags & DDRAWISURF_HASCKEYDESTOVERLAY))
|
|
{
|
|
DPF_ERR("KEYDEST specified, but no color key...");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (pSprite->dwFlags & DDSPRITE_KEYDESTOVERRIDE)
|
|
{
|
|
DPF_ERR("Illegal to specify both KEYDEST and KEYDESTOVERRIDE...");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
// Copy color key value from surface into DDSPRITEFX struct.
|
|
pSprite->ddSpriteFX.ddckDestColorkey = (pcaps->bOverlay) ?
|
|
surf_src_lcl->ddckCKDestOverlay :
|
|
surf_src_lcl->ddckCKDestBlt;
|
|
// Turn off KEYDEST, turn on KEYDESTOVERRIDE.
|
|
pSprite->dwFlags ^= DDSPRITE_KEYDEST | DDSPRITE_KEYDESTOVERRIDE;
|
|
}
|
|
}
|
|
|
|
if (pcaps->bNoHAL && pcaps->bNoHEL)
|
|
{
|
|
DPF_ERR("No driver support for specified color-key operation");
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Assume hardware unable to handle sprite in system memory.
|
|
* (Will this assumption remain true for future hardware?)
|
|
*/
|
|
if (pcaps->bOverlay)
|
|
{
|
|
if (pcaps->dwSrcSurfCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
pcaps->bNoHAL = TRUE; // can't use hardware
|
|
|
|
if (pcaps->bNoHEL) // but can we still emulate?
|
|
{
|
|
// Nope, we can't emulate either, so fail the call.
|
|
DPF_ERR("Driver can't handle sprite in system memory");
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We do not allow blits or overlays with an optimized surface.
|
|
*/
|
|
if (pcaps->dwSrcSurfCaps & DDSCAPS_OPTIMIZED)
|
|
{
|
|
DPF_ERR("Can't do blits or overlays with optimized surfaces...") ;
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
/*
|
|
* Validate dwSize field in embedded DDSPRITEFX structure.
|
|
*/
|
|
if (pSprite->ddSpriteFX.dwSize != sizeof(DDSPRITEFX))
|
|
{
|
|
DPF_ERR("Invalid dwSize value in DDSPRITEFX structure...");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
/*
|
|
* If the RGBA scaling factors are effectively disabled by all being
|
|
* set to 255 (all ones), just clear the RGBASCALING flag.
|
|
*/
|
|
if (pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_RGBASCALING &&
|
|
*(LPDWORD)&pSprite->ddSpriteFX.ddrgbaScaleFactors == ~0UL)
|
|
{
|
|
pSprite->ddSpriteFX.dwDDFX &= ~DDSPRITEFX_RGBASCALING;
|
|
}
|
|
|
|
/*
|
|
* Is any kind of alpha blending required for this sprite?
|
|
*/
|
|
if (dwDDPFSrcFlags & DDPF_ALPHAPIXELS ||
|
|
!(pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_DEGRADERGBASCALING) &&
|
|
pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_RGBASCALING)
|
|
{
|
|
/*
|
|
* Yes, this sprite requires some form of alpha blending.
|
|
* Does the driver support any kind of alpha blending at all?
|
|
*/
|
|
if (!(pcaps->dwFXCaps & (DDFXCAPS_BLTALPHA | DDFXCAPS_OVERLAYALPHA)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELFXCaps & (DDFXCAPS_BLTALPHA | DDFXCAPS_OVERLAYALPHA)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
|
|
if (pcaps->bNoHAL && pcaps->bNoHEL)
|
|
{
|
|
DPF_ERR("Driver can't do any kind of alpha blending at all...");
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
|
|
/*
|
|
* Does source surface have an alpha channel?
|
|
*/
|
|
if (dwDDPFSrcFlags & DDPF_ALPHAPIXELS)
|
|
{
|
|
/*
|
|
* Can the driver handle this surface's alpha-channel format?
|
|
*/
|
|
if (dwDDPFSrcFlags & DDPF_ALPHAPREMULT)
|
|
{
|
|
// The source is in premultiplied-alpha format.
|
|
if (!(pcaps->dwAlphaCaps & (DDALPHACAPS_BLTPREMULT |
|
|
DDALPHACAPS_OVERLAYPREMULT)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELAlphaCaps & (DDALPHACAPS_BLTPREMULT |
|
|
DDALPHACAPS_OVERLAYPREMULT)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The source is in NON-premultiplied-alpha format.
|
|
if (!(pcaps->dwAlphaCaps & (DDALPHACAPS_BLTNONPREMULT |
|
|
DDALPHACAPS_OVERLAYNONPREMULT)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELAlphaCaps & (DDALPHACAPS_BLTNONPREMULT |
|
|
DDALPHACAPS_OVERLAYNONPREMULT)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
}
|
|
if (pcaps->bNoHAL && pcaps->bNoHEL)
|
|
{
|
|
DPF_ERR("Driver can't handle alpha channel in source surface...");
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Does the destination surface have an alpha channel?
|
|
*/
|
|
if (dwDDPFDestFlags & DDPF_ALPHAPIXELS)
|
|
{
|
|
/*
|
|
* Verify that destination surface has a premultiplied-
|
|
* alpha pixel format. Non-premultiplied alpha won't do.
|
|
*/
|
|
if (!(dwDDPFDestFlags & DDPF_ALPHAPREMULT))
|
|
{
|
|
DPF_ERR("Illegal to use non-premultiplied alpha in dest surface...");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
/*
|
|
* Can the driver handle this surface's alpha-channel format?
|
|
*/
|
|
if (!(pcaps->dwAlphaCaps & (DDALPHACAPS_BLTPREMULT |
|
|
DDALPHACAPS_OVERLAYPREMULT)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELAlphaCaps & (DDALPHACAPS_BLTPREMULT |
|
|
DDALPHACAPS_OVERLAYPREMULT)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
if (pcaps->bNoHAL && pcaps->bNoHEL)
|
|
{
|
|
DPF_ERR("Driver can't handle alpha channel in dest surface...");
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Are the RGBA scaling factors enabled for this sprite?
|
|
*/
|
|
if (!(pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_DEGRADERGBASCALING) &&
|
|
*(LPDWORD)&pSprite->ddSpriteFX.ddrgbaScaleFactors != ~0UL)
|
|
{
|
|
DDRGBA val = pSprite->ddSpriteFX.ddrgbaScaleFactors;
|
|
|
|
/*
|
|
* Yes, RGBA scaling is enabled. Does driver support it?
|
|
*/
|
|
if (!(pcaps->dwAlphaCaps & (DDALPHACAPS_BLTRGBASCALE1F | DDALPHACAPS_OVERLAYRGBASCALE1F |
|
|
DDALPHACAPS_BLTRGBASCALE2F | DDALPHACAPS_OVERLAYRGBASCALE2F |
|
|
DDALPHACAPS_BLTRGBASCALE4F | DDALPHACAPS_OVERLAYRGBASCALE4F)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELAlphaCaps & (DDALPHACAPS_BLTRGBASCALE1F | DDALPHACAPS_OVERLAYRGBASCALE1F |
|
|
DDALPHACAPS_BLTRGBASCALE2F | DDALPHACAPS_OVERLAYRGBASCALE2F |
|
|
DDALPHACAPS_BLTRGBASCALE4F | DDALPHACAPS_OVERLAYRGBASCALE4F)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
if (pcaps->bNoHAL && pcaps->bNoHEL)
|
|
{
|
|
DPF_ERR("Driver can't do any kind of RGBA scaling at all...");
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
|
|
if (val.red > val.alpha || val.green > val.alpha || val.blue > val.alpha)
|
|
{
|
|
|
|
if (!(pcaps->dwAlphaCaps & (DDALPHACAPS_BLTSATURATE |
|
|
DDALPHACAPS_OVERLAYSATURATE)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELAlphaCaps & (DDALPHACAPS_BLTSATURATE |
|
|
DDALPHACAPS_OVERLAYSATURATE)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
}
|
|
if (val.red != val.green || val.red != val.blue)
|
|
{
|
|
if (!(pcaps->dwAlphaCaps & (DDALPHACAPS_BLTRGBASCALE4F |
|
|
DDALPHACAPS_OVERLAYRGBASCALE4F)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELAlphaCaps & (DDALPHACAPS_BLTRGBASCALE4F |
|
|
DDALPHACAPS_OVERLAYRGBASCALE4F)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
} else if (*(LPDWORD)&val != val.alpha*0x01010101UL)
|
|
{
|
|
if (!(pcaps->dwAlphaCaps & (DDALPHACAPS_BLTRGBASCALE2F |
|
|
DDALPHACAPS_OVERLAYRGBASCALE2F)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELAlphaCaps & (DDALPHACAPS_BLTRGBASCALE2F |
|
|
DDALPHACAPS_OVERLAYRGBASCALE2F)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
}
|
|
if (pcaps->bNoHAL && pcaps->bNoHEL)
|
|
{
|
|
DPF_ERR("Driver can't handle specified RGBA scaling factors...");
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Is any kind of filtering required for this sprite?
|
|
*/
|
|
if (!(pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_DEGRADEFILTER) &&
|
|
pSprite->ddSpriteFX.dwDDFX & (DDSPRITEFX_BILINEARFILTER |
|
|
DDSPRITEFX_BLURFILTER |
|
|
DDSPRITEFX_FLATFILTER))
|
|
{
|
|
/*
|
|
* The bilinear-, blur-, and flat-filtering options are mutually
|
|
* exclusive. Make sure only one of these flags is set.
|
|
*/
|
|
DWORD fflags = pSprite->ddSpriteFX.dwDDFX & (DDSPRITEFX_BILINEARFILTER |
|
|
DDSPRITEFX_BLURFILTER |
|
|
DDSPRITEFX_FLATFILTER);
|
|
if (fflags & (fflags - 1))
|
|
{
|
|
DPF_ERR("Two mutually exclusive filtering options were both specified");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
/*
|
|
* Yes, this sprite requires some form of filtering.
|
|
* Does the driver support any kind of filtering at all?
|
|
*/
|
|
if (!(pcaps->dwFXCaps & (DDFXCAPS_BLTFILTER | DDFXCAPS_OVERLAYFILTER)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELFXCaps & (DDFXCAPS_BLTFILTER | DDFXCAPS_OVERLAYFILTER)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
|
|
if (pcaps->bNoHAL && pcaps->bNoHEL)
|
|
{
|
|
DPF_ERR("Driver can't do any kind of filtering at all");
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
|
|
if (pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_BILINEARFILTER)
|
|
{
|
|
if (!(pcaps->dwFilterCaps & (DDFILTCAPS_BLTBILINEARFILTER |
|
|
DDFILTCAPS_OVERLAYBILINEARFILTER)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELFilterCaps & (DDFILTCAPS_BLTBILINEARFILTER |
|
|
DDFILTCAPS_OVERLAYBILINEARFILTER)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
}
|
|
if (pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_BLURFILTER)
|
|
{
|
|
if (!(pcaps->dwFilterCaps & (DDFILTCAPS_BLTBLURFILTER |
|
|
DDFILTCAPS_OVERLAYBLURFILTER)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELFilterCaps & (DDFILTCAPS_BLTBLURFILTER |
|
|
DDFILTCAPS_OVERLAYBLURFILTER)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
}
|
|
if (pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_FLATFILTER)
|
|
{
|
|
if (!(pcaps->dwFilterCaps & (DDFILTCAPS_BLTFLATFILTER |
|
|
DDFILTCAPS_OVERLAYFLATFILTER)))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!(pcaps->dwHELFilterCaps & (DDFILTCAPS_BLTFLATFILTER |
|
|
DDFILTCAPS_OVERLAYFLATFILTER)))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
}
|
|
if (pcaps->bNoHAL && pcaps->bNoHEL)
|
|
{
|
|
DPF_ERR("Driver can't do specified filtering operation...");
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Can the driver handle the specified affine transformation?
|
|
*/
|
|
if (pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_AFFINETRANSFORM)
|
|
{
|
|
/*
|
|
* Can the driver do any affine transformations at all?
|
|
*/
|
|
if (!pcaps->bNoHAL &&
|
|
(!(pcaps->dwFXCaps & (DDFXCAPS_BLTTRANSFORM | DDFXCAPS_OVERLAYTRANSFORM)) ||
|
|
!(pcaps->dwTransformCaps & (DDTFRMCAPS_BLTAFFINETRANSFORM |
|
|
DDTFRMCAPS_OVERLAYAFFINETRANSFORM))))
|
|
{
|
|
pcaps->bNoHAL = TRUE; // disqualify hardware driver
|
|
}
|
|
if (!pcaps->bNoHEL &&
|
|
(!(pcaps->dwHELFXCaps & (DDFXCAPS_BLTTRANSFORM | DDFXCAPS_OVERLAYTRANSFORM)) ||
|
|
!(pcaps->dwHELTransformCaps & (DDTFRMCAPS_BLTAFFINETRANSFORM |
|
|
DDTFRMCAPS_OVERLAYAFFINETRANSFORM))))
|
|
{
|
|
pcaps->bNoHEL = TRUE; // disqualify HEL
|
|
}
|
|
|
|
if (pcaps->bNoHAL && pcaps->bNoHEL)
|
|
{
|
|
DPF_ERR("Driver can't do any affine transformations...");
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
|
|
/*
|
|
* Check affine transformation against driver's minification limits.
|
|
*/
|
|
checkMinification(&pSprite->ddSpriteFX, pcaps);
|
|
|
|
if (pcaps->bNoHAL && pcaps->bNoHEL)
|
|
{
|
|
DPF_ERR("Affine transform exceeds driver's minification limit...");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If necessary, degrade specified filtering and RGBA-scaling operations
|
|
* to operations that the driver is capable of handling.
|
|
*/
|
|
if (pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_DEGRADEFILTER)
|
|
{
|
|
DWORD caps;
|
|
DWORD ddfx = pSprite->ddSpriteFX.dwDDFX; // sprite FX flags
|
|
|
|
// driver's FX caps
|
|
caps = (pcaps->bNoHAL) ? pcaps->dwHELFXCaps : pcaps->dwFXCaps;
|
|
|
|
if (!(caps && (DDFXCAPS_BLTFILTER | DDFXCAPS_OVERLAYFILTER)))
|
|
{
|
|
// Driver can't do any kind of filtering, so just disable it.
|
|
ddfx &= ~(DDSPRITEFX_BILINEARFILTER | DDSPRITEFX_BLURFILTER |
|
|
DDSPRITEFX_FLATFILTER | DDSPRITEFX_DEGRADEFILTER);
|
|
}
|
|
else
|
|
{
|
|
// Get driver's filter caps.
|
|
caps = (pcaps->bNoHAL) ? pcaps->dwHELFilterCaps : pcaps->dwFilterCaps;
|
|
|
|
// If blur filter is specified, can driver handle it?
|
|
if (ddfx & DDSPRITEFX_BLURFILTER &&
|
|
!(caps & (DDFILTCAPS_BLTBLURFILTER |
|
|
DDFILTCAPS_OVERLAYBLURFILTER)))
|
|
{
|
|
// Degrade blur filter to bilinear filter.
|
|
ddfx &= ~DDSPRITEFX_BLURFILTER;
|
|
ddfx |= DDSPRITEFX_BILINEARFILTER;
|
|
}
|
|
// If flat filter is specified, can driver handle it?
|
|
if (ddfx & DDSPRITEFX_FLATFILTER &&
|
|
!(caps & (DDFILTCAPS_BLTFLATFILTER |
|
|
DDFILTCAPS_OVERLAYFLATFILTER)))
|
|
{
|
|
// Degrade flat filter to bilinear filter.
|
|
ddfx &= ~DDSPRITEFX_FLATFILTER;
|
|
ddfx |= DDSPRITEFX_BILINEARFILTER;
|
|
}
|
|
// If bilinear filter is specified, can driver handle it?
|
|
if (ddfx & DDSPRITEFX_BILINEARFILTER &&
|
|
!(caps & (DDFILTCAPS_BLTBILINEARFILTER |
|
|
DDFILTCAPS_OVERLAYBILINEARFILTER)))
|
|
{
|
|
// Degrade bilinear filtering to no filtering.
|
|
ddfx &= ~DDSPRITEFX_BILINEARFILTER;
|
|
}
|
|
}
|
|
pSprite->ddSpriteFX.dwDDFX = ddfx & ~DDSPRITEFX_DEGRADEFILTER;
|
|
}
|
|
|
|
/*
|
|
* If necessary, degrade specified RGBA scaling factors to values
|
|
* that the driver is capable of handling.
|
|
*/
|
|
if (pSprite->ddSpriteFX.dwDDFX & DDSPRITEFX_DEGRADERGBASCALING &&
|
|
*(LPDWORD)&pSprite->ddSpriteFX.ddrgbaScaleFactors != ~0UL)
|
|
{
|
|
DDRGBA val = pSprite->ddSpriteFX.ddrgbaScaleFactors;
|
|
DWORD caps;
|
|
|
|
// driver's alpha caps
|
|
caps = (pcaps->bNoHAL) ? pcaps->dwHELAlphaCaps : pcaps->dwAlphaCaps;
|
|
|
|
/*
|
|
* We permit the RGB scaling factors to exceed the alpha scaling
|
|
* factor only if the driver can do saturated alpha arithmetic to
|
|
* prevent the destination color components from overflowing.
|
|
*/
|
|
if ((val.red > val.alpha || val.green > val.alpha || val.blue > val.alpha) &&
|
|
!(caps & (DDALPHACAPS_BLTSATURATE | DDALPHACAPS_OVERLAYSATURATE)))
|
|
{
|
|
// Driver can't handle saturated arithmetic during alpha blending.
|
|
if (val.red > val.alpha)
|
|
{
|
|
val.red = val.alpha; // clamp red to alpha value
|
|
}
|
|
if (val.green > val.alpha)
|
|
{
|
|
val.green = val.alpha; // clamp green to alpha value
|
|
}
|
|
if (val.blue > val.alpha)
|
|
{
|
|
val.blue = val.alpha; // clamp blue to alpha value
|
|
}
|
|
}
|
|
/*
|
|
* Can driver perform 1-, 2-, or 4-factor RGBA scaling?
|
|
*/
|
|
if (!(caps & (DDALPHACAPS_BLTRGBASCALE1F | DDALPHACAPS_OVERLAYRGBASCALE1F |
|
|
DDALPHACAPS_BLTRGBASCALE2F | DDALPHACAPS_OVERLAYRGBASCALE2F |
|
|
DDALPHACAPS_BLTRGBASCALE4F | DDALPHACAPS_OVERLAYRGBASCALE4F)))
|
|
{
|
|
// Driver can't do any kind of RGBA scaling at all.
|
|
*(LPDWORD)&val = ~0UL; // disable RGBA scaling altogether
|
|
}
|
|
else if (*(LPDWORD)&val != val.alpha*0x01010101UL &&
|
|
!(caps & (DDALPHACAPS_BLTRGBASCALE2F | DDALPHACAPS_OVERLAYRGBASCALE2F |
|
|
DDALPHACAPS_BLTRGBASCALE4F | DDALPHACAPS_OVERLAYRGBASCALE4F)))
|
|
{
|
|
// Driver can handle only 1-factor RGBA scaling.
|
|
*(LPDWORD)&val = val.alpha*0x01010101UL; // set RGB factors = alpha factor
|
|
}
|
|
else if ((val.red != val.green || val.red != val.blue) &&
|
|
!(caps & (DDALPHACAPS_BLTRGBASCALE4F | DDALPHACAPS_OVERLAYRGBASCALE4F)))
|
|
{
|
|
/*
|
|
* Degrade the specified 4-factor RGBA-scaling operation to a 2-factor
|
|
* RGBA scaling operation that the driver can handle. Set all three
|
|
* color factors to weighted average M of the specified color factors
|
|
* (Mr,Mg,Mb): M = .299*Mr + .587*Mg + .114*Mb
|
|
*/
|
|
DWORD M = 19595UL*val.red + 38470UL*val.green + 7471UL*val.blue;
|
|
|
|
val.red = val.green = val.blue = (BYTE)(M >> 16);
|
|
}
|
|
pSprite->ddSpriteFX.ddrgbaScaleFactors = val;
|
|
pSprite->ddSpriteFX.dwDDFX &= ~DDSPRITEFX_DEGRADERGBASCALING;
|
|
}
|
|
|
|
/*
|
|
* If the embedded DDSPRITEFX structure is unused, clear DDSPRITEFX flag.
|
|
*/
|
|
if (!(pSprite->dwFlags & (DDSPRITE_KEYDESTOVERRIDE | DDSPRITE_KEYSRCOVERRIDE)) &&
|
|
pSprite->ddSpriteFX.dwDDFX == 0)
|
|
{
|
|
pSprite->dwFlags &= ~DDSPRITE_DDSPRITEFX;
|
|
}
|
|
|
|
DDASSERT(!(pcaps->bNoHAL && pcaps->bNoHEL));
|
|
|
|
return DD_OK;
|
|
|
|
} /* validateSprite */
|
|
|
|
|
|
/*
|
|
* Obtain clipping region for a destination surface and its attached
|
|
* clipper. (In the case of overlay sprites in the master sprite
|
|
* list, though, pClipper points to the clipper that WAS attached to
|
|
* the destination surface at the time of the SetSpriteDisplayList
|
|
* call; it may no longer be if an app manages multiple windows.)
|
|
* If pClipper is NULL, just use the whole dest surf as the clip rect.
|
|
* A NULL return value always means DDERR_OUTOFMEMORY.
|
|
*/
|
|
static LPRGNDATA GetRgnData(LPDIRECTDRAWCLIPPER pClipper, LPRECT prcDestSurf,
|
|
LPDDRAWI_DIRECTDRAW_GBL pdrv, LPRGNDATA pRgn)
|
|
{
|
|
DWORD rgnSize;
|
|
|
|
/*
|
|
* How big a buffer will we need to contain the clipping region?
|
|
*/
|
|
if (pClipper == NULL)
|
|
{
|
|
/*
|
|
* The destination surface has (or HAD) no attached clipper,
|
|
* so the effective clip region is a single rectangle the width
|
|
* and height of the primary surface. Calculate the size of
|
|
* the region buffer we'll need.
|
|
*/
|
|
rgnSize = sizeof(RGNDATAHEADER) + sizeof(RECT);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The dest surface has (or HAD) an attached clipper. Get
|
|
* the clip list. This first call to InternalGetClipList
|
|
* just gets the size of the region so we know how much
|
|
* storage to allocate for it.
|
|
*/
|
|
HRESULT ddrval = InternalGetClipList(pClipper,
|
|
prcDestSurf,
|
|
NULL, // we just want rgnSize
|
|
&rgnSize,
|
|
pdrv);
|
|
|
|
DDASSERT(ddrval == DD_OK); // the call above should never fail
|
|
}
|
|
|
|
/*
|
|
* Now we know how big a region buffer we'll need. Did the caller
|
|
* pass in a region buffer? If so, is it the correct size?
|
|
*/
|
|
if (pRgn != NULL)
|
|
{
|
|
/*
|
|
* The caller DID pass in a region buffer. Before using it,
|
|
* let's make sure it's just the right size.
|
|
*/
|
|
DWORD bufSize = pRgn->rdh.dwSize + pRgn->rdh.nRgnSize;
|
|
|
|
if (bufSize != rgnSize)
|
|
{
|
|
// Can't use region buffer passed in by caller.
|
|
pRgn = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now we know whether we'll have to alloc our own region buffer.
|
|
*/
|
|
if (pRgn == NULL)
|
|
{
|
|
/*
|
|
* Yes, we must alloc our own region buffer.
|
|
*/
|
|
pRgn = (LPRGNDATA)MemAlloc(rgnSize);
|
|
if (!pRgn)
|
|
{
|
|
return NULL; // error -- out of memory
|
|
}
|
|
// We'll fill in the following fields in case the caller
|
|
// passes this same buffer to us again later.
|
|
pRgn->rdh.dwSize = sizeof(RGNDATAHEADER);
|
|
pRgn->rdh.nRgnSize = rgnSize - sizeof(RGNDATAHEADER);
|
|
}
|
|
|
|
/*
|
|
* Okay, now we have a region buffer that's the right size.
|
|
* Load the region data into the buffer.
|
|
*/
|
|
if (pClipper == NULL)
|
|
{
|
|
// Set the single clip rect to cover the full dest surface.
|
|
pRgn->rdh.nCount = 1; // a single clip rect
|
|
memcpy((LPRECT)&pRgn->Buffer, prcDestSurf, sizeof(RECT));
|
|
}
|
|
else
|
|
{
|
|
// This call actually retrieves the clip region info.
|
|
HRESULT ddrval = InternalGetClipList(pClipper,
|
|
prcDestSurf,
|
|
pRgn,
|
|
&rgnSize,
|
|
pdrv);
|
|
|
|
DDASSERT(ddrval == DD_OK); // the call above should never fail
|
|
}
|
|
|
|
return (pRgn); // return pointer to region info
|
|
|
|
} /* GetRgnData */
|
|
|
|
|
|
/*
|
|
* Validate the window handle associated with the specified clipper.
|
|
* If the window handle is not valid, return FALSE. Otherwise,
|
|
* return TRUE. Note that this function returns TRUE if either
|
|
* pClipper is null or the associated window handle is null.
|
|
*/
|
|
static BOOL validClipperWindow(LPDIRECTDRAWCLIPPER pClipper)
|
|
{
|
|
if (pClipper != NULL)
|
|
{
|
|
LPDDRAWI_DDRAWCLIPPER_INT pclip_int = (LPDDRAWI_DDRAWCLIPPER_INT)pClipper;
|
|
LPDDRAWI_DDRAWCLIPPER_LCL pclip_lcl = pclip_int->lpLcl;
|
|
LPDDRAWI_DDRAWCLIPPER_GBL pclip = pclip_lcl->lpGbl;
|
|
HWND hWnd = (HWND)pclip->hWnd;
|
|
|
|
if (hWnd != 0 && !IsWindow(hWnd))
|
|
{
|
|
/*
|
|
* This window handle is no longer valid.
|
|
*/
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
} /* validClipperWindow */
|
|
|
|
|
|
/*
|
|
* Helper function for managing sublists within the master sprite
|
|
* list. If any sprites in the specified sublist have source surface
|
|
* pointers that are null, remove those sprites and move the rest of
|
|
* the sprite array downward to eliminate the gaps in the array.
|
|
*/
|
|
static DWORD scrunchSubList(LPSPRITESUBLIST pSubList)
|
|
{
|
|
DWORD i, j;
|
|
// Number of sprites in sublist
|
|
DWORD dwNumSprites = pSubList->dwCount;
|
|
// Pointer to first sprite in array of sprites
|
|
LPDDSPRITEI pSprite = &pSubList->sprite[0];
|
|
|
|
// Find first null surface in sprite array.
|
|
for (i = 0; i < dwNumSprites; ++i)
|
|
{
|
|
if (pSprite[i].lpDDSSrc == NULL) // null surface ptr?
|
|
{
|
|
break; // found first null surface in sprite array
|
|
}
|
|
}
|
|
// Scrunch together remainder of sprite array to fill in gaps.
|
|
for (j = i++; i < dwNumSprites; ++i)
|
|
{
|
|
if (pSprite[i].lpDDSSrc != NULL) // valid surface ptr?
|
|
{
|
|
pSprite[j++] = pSprite[i]; // copy next valid sprite
|
|
}
|
|
}
|
|
// Return number of sprites in scrunched array.
|
|
return (pSubList->dwCount = j);
|
|
|
|
} /* scrunchSubList */
|
|
|
|
|
|
/*
|
|
* Helper function for managing master sprite list. If any of the
|
|
* sublist pointers in the master-sprite-list header are NULL,
|
|
* remove those pointers and move the rest of the sublist-
|
|
* pointer array downward to eliminate the gaps in the array.
|
|
*/
|
|
static DWORD scrunchMasterSpriteList(LPMASTERSPRITELIST pMaster)
|
|
{
|
|
DWORD i, j;
|
|
// Number of sublists in master sprite list
|
|
DWORD dwNumSubLists = pMaster->dwNumSubLists;
|
|
// Pointer to first pointer in array of sublist pointers
|
|
LPSPRITESUBLIST *ppSubList = &pMaster->pSubList[0];
|
|
|
|
// Find first null pointer in sublist-pointer array.
|
|
for (i = 0; i < dwNumSubLists; ++i)
|
|
{
|
|
if (ppSubList[i] == NULL) // null pointer?
|
|
{
|
|
break; // found first null pointer in array
|
|
}
|
|
}
|
|
// Scrunch together remainder of sublist-pointer array to fill in gaps.
|
|
for (j = i++; i < dwNumSubLists; ++i)
|
|
{
|
|
if (ppSubList[i] != NULL) // valid pointer?
|
|
{
|
|
ppSubList[j++] = ppSubList[i]; // copy next valid pointer
|
|
}
|
|
}
|
|
// Return number of sublist pointers in scrunched array.
|
|
return (pMaster->dwNumSubLists = j);
|
|
|
|
} /* scrunchMasterSpriteList */
|
|
|
|
|
|
/*
|
|
* Helper function for managing master sprite list. Mark all surface
|
|
* and clipper objects that are referenced in the master sprite list.
|
|
* When a marked surface or clipper object is released, the master
|
|
* sprite list is immediately updated to eliminate invalid references.
|
|
* The master sprite list contains pointers to surface and clipper
|
|
* interface objects, but marks the surfaces and clippers by setting
|
|
* flags in the local surface and global clipper objects. Because
|
|
* the master sprite list may contain multiple instances of the same
|
|
* surface or clipper object, we mark and unmark all such objects in
|
|
* unison to avoid errors.
|
|
*/
|
|
static void markSpriteObjects(LPMASTERSPRITELIST pMaster)
|
|
{
|
|
DWORD i;
|
|
|
|
if (pMaster == NULL)
|
|
{
|
|
return; // nothing to do -- bye!
|
|
}
|
|
|
|
/*
|
|
* Set the DDRAWISURF/CLIP_INMASTERSPRITELIST flag in each local
|
|
* surface object and global clipper object in the master sprite
|
|
* list. Each iteration marks the objects in one sublist.
|
|
*/
|
|
for (i = 0; i < pMaster->dwNumSubLists; ++i)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl;
|
|
LPDDRAWI_DDRAWCLIPPER_INT pclip_int;
|
|
LPSPRITESUBLIST pSubList = pMaster->pSubList[i];
|
|
LPDDSPRITEI sprite = &pSubList->sprite[0];
|
|
DWORD dwNumSprites = pSubList->dwCount;
|
|
DWORD j;
|
|
|
|
/*
|
|
* Mark the primary surface object associated with this sublist.
|
|
*/
|
|
surf_int = (LPDDRAWI_DDRAWSURFACE_INT)pSubList->pPrimary;
|
|
surf_lcl = surf_int->lpLcl;
|
|
surf_lcl->dwFlags |= DDRAWISURF_INMASTERSPRITELIST;
|
|
|
|
/*
|
|
* If a clipper is associated with this sublist, mark it.
|
|
*/
|
|
pclip_int = (LPDDRAWI_DDRAWCLIPPER_INT)pSubList->pClipper;
|
|
if (pclip_int != NULL)
|
|
{
|
|
LPDDRAWI_DDRAWCLIPPER_LCL pclip_lcl = pclip_int->lpLcl;
|
|
LPDDRAWI_DDRAWCLIPPER_GBL pclip = pclip_lcl->lpGbl;
|
|
|
|
pclip->dwFlags |= DDRAWICLIP_INMASTERSPRITELIST;
|
|
}
|
|
|
|
/*
|
|
* Mark the source surface for each sprite in this sublist.
|
|
*/
|
|
for (j = 0; j < dwNumSprites; ++j)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl;
|
|
LPDDSPRITEI pSprite = &sprite[j];
|
|
|
|
surf_int = (LPDDRAWI_DDRAWSURFACE_INT)pSprite->lpDDSSrc;
|
|
surf_lcl = surf_int->lpLcl;
|
|
surf_lcl->dwFlags |= DDRAWISURF_INMASTERSPRITELIST;
|
|
}
|
|
}
|
|
} /* markSpriteObjects */
|
|
|
|
|
|
/*
|
|
* Helper function for managing master sprite list.
|
|
* Mark all surfaces in the master sprite list as no longer
|
|
* referenced by the master sprite list.
|
|
*/
|
|
static void unmarkSpriteObjects(LPMASTERSPRITELIST pMaster)
|
|
{
|
|
DWORD i;
|
|
|
|
if (pMaster == NULL)
|
|
{
|
|
return; // nothing to do -- bye!
|
|
}
|
|
|
|
/*
|
|
* Clear the DDRAWISURF/CLIP_INMASTERSPRITELIST flag in each local
|
|
* surface object and global clipper object in the master sprite
|
|
* list. Each iteration unmarks the objects in one sublist.
|
|
*/
|
|
for (i = 0; i < pMaster->dwNumSubLists; ++i)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl;
|
|
LPDDRAWI_DDRAWCLIPPER_INT pclip_int;
|
|
LPSPRITESUBLIST pSubList = pMaster->pSubList[i];
|
|
LPDDSPRITEI sprite = &pSubList->sprite[0];
|
|
DWORD dwNumSprites = pSubList->dwCount;
|
|
DWORD j;
|
|
|
|
/*
|
|
* Unmark the primary surface object associated with this sublist.
|
|
*/
|
|
surf_int = (LPDDRAWI_DDRAWSURFACE_INT)pSubList->pPrimary;
|
|
surf_lcl = surf_int->lpLcl;
|
|
surf_lcl->dwFlags &= ~DDRAWISURF_INMASTERSPRITELIST;
|
|
|
|
/*
|
|
* If a clipper is associated with this sublist, unmark it.
|
|
*/
|
|
pclip_int = (LPDDRAWI_DDRAWCLIPPER_INT)pSubList->pClipper;
|
|
if (pclip_int != NULL)
|
|
{
|
|
LPDDRAWI_DDRAWCLIPPER_LCL pclip_lcl = pclip_int->lpLcl;
|
|
LPDDRAWI_DDRAWCLIPPER_GBL pclip = pclip_lcl->lpGbl;
|
|
|
|
pclip->dwFlags &= ~DDRAWICLIP_INMASTERSPRITELIST;
|
|
}
|
|
|
|
/*
|
|
* Mark all of the surfaces referenced in this sublist.
|
|
*/
|
|
for (j = 0; j < dwNumSprites; ++j)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl;
|
|
LPDDSPRITEI pSprite = &sprite[j];
|
|
|
|
surf_int = (LPDDRAWI_DDRAWSURFACE_INT)pSprite->lpDDSSrc;
|
|
surf_lcl = surf_int->lpLcl;
|
|
surf_lcl->dwFlags &= ~DDRAWISURF_INMASTERSPRITELIST;
|
|
}
|
|
}
|
|
} /* unmarkSpriteObjects */
|
|
|
|
|
|
/*
|
|
* Helper function for managing master sprite list. This function
|
|
* frees the master sprite list for the specified DirectDraw object.
|
|
*/
|
|
void FreeMasterSpriteList(LPDDRAWI_DIRECTDRAW_GBL pdrv)
|
|
{
|
|
DWORD i;
|
|
LPMASTERSPRITELIST pMaster = (LPMASTERSPRITELIST)(pdrv->lpMasterSpriteList);
|
|
|
|
if (pMaster == NULL)
|
|
{
|
|
return;
|
|
}
|
|
/*
|
|
* Clear flags in surface and clipper objects that indicate
|
|
* that these objects are referenced in master sprite list.
|
|
*/
|
|
unmarkSpriteObjects(pMaster);
|
|
/*
|
|
* Free all the individual sublists within the master sprite list.
|
|
*/
|
|
for (i = 0; i < pMaster->dwNumSubLists; ++i)
|
|
{
|
|
LPSPRITESUBLIST pSubList = pMaster->pSubList[i];
|
|
|
|
MemFree(pSubList->pRgn); // Free clip region buffer
|
|
MemFree(pSubList); // Free the sublist itself
|
|
}
|
|
MemFree(pMaster->pBuffer); // Free temp display list buffer
|
|
MemFree(pMaster); // Free master sprite list header
|
|
|
|
pdrv->lpMasterSpriteList = NULL;
|
|
|
|
} /* FreeMasterSpriteList */
|
|
|
|
|
|
/*
|
|
* This is a helper function for updateMasterSpriteList(). It builds
|
|
* a temporary display list that contains all the sprites currently in
|
|
* the master sprite display list. This is the display list that we
|
|
* will pass to the driver upon return from updateMasterSpriteList().
|
|
*/
|
|
static DDHAL_SETSPRITEDISPLAYLISTDATA *buildTempDisplayList(
|
|
LPMASTERSPRITELIST pMaster)
|
|
{
|
|
DWORD size;
|
|
LPBUFFER pbuf;
|
|
LPDDSPRITEI *ppSprite;
|
|
DDHAL_SETSPRITEDISPLAYLISTDATA *pHalData;
|
|
DWORD dwNumSubLists = pMaster->dwNumSubLists; // number of sublists
|
|
DWORD dwNumSprites = 0;
|
|
DWORD i;
|
|
|
|
/*
|
|
* Update the clipping region for the sprites within each sublist.
|
|
* In general, each sublist has a different clipping region. If
|
|
* a sublist has a clipper and that clipper has an hWnd, the clip
|
|
* region may have changed since the last time we were called.
|
|
*/
|
|
for (i = 0; i < dwNumSubLists; ++i)
|
|
{
|
|
DWORD j;
|
|
LPRGNDATA pRgn;
|
|
DWORD dwRectCnt;
|
|
LPRECT pRect;
|
|
LPSPRITESUBLIST pSubList = pMaster->pSubList[i];
|
|
LPDDSPRITEI sprite = &(pSubList->sprite[0]);
|
|
DWORD dwCount = pSubList->dwCount; // number of sprites in sublist
|
|
|
|
/*
|
|
* Get clipping region for window this sprite display list is in.
|
|
*/
|
|
pRgn = GetRgnData(pSubList->pClipper, &pMaster->rcPrimary,
|
|
pMaster->pdrv, pSubList->pRgn);
|
|
if (pRgn == NULL)
|
|
{
|
|
return (NULL); // error -- out of memory
|
|
}
|
|
if (pRgn != pSubList->pRgn)
|
|
{
|
|
/*
|
|
* GetRgnData() allocated a new region buffer instead of using
|
|
* the old buffer. We need to free the old buffer ourselves.
|
|
*/
|
|
MemFree(pSubList->pRgn);
|
|
}
|
|
pSubList->pRgn = pRgn; // save ptr to region buffer
|
|
/*
|
|
* All sprites in the sublist share the same clipping region.
|
|
*/
|
|
dwRectCnt = pRgn->rdh.nCount; // number of rects in region
|
|
pRect = (LPRECT)&pRgn->Buffer; // list of clip rects
|
|
|
|
for (j = 0; j < dwCount; ++j)
|
|
{
|
|
sprite[j].dwRectCnt = dwRectCnt;
|
|
sprite[j].lpRect = pRect;
|
|
}
|
|
/*
|
|
* Add the sprites in this sublist to our running tally of
|
|
* the total number of sprites in the master sprite list.
|
|
*/
|
|
dwNumSprites += dwCount;
|
|
}
|
|
|
|
/*
|
|
* If we can, we'll build our temporary sprite display list in the
|
|
* existing buffer (pMaster->pBuffer). But if it doesn't exist or
|
|
* is too big or too small, we'll have to allocate a new buffer.
|
|
*/
|
|
size = sizeof(BUFFER) + (dwNumSprites-1)*sizeof(LPDDSPRITEI);
|
|
pbuf = pMaster->pBuffer; // try to re-use this buffer
|
|
|
|
if (pbuf == NULL || pbuf->dwSize < size ||
|
|
pbuf->dwSize > size + 8*sizeof(LPDDSPRITEI))
|
|
{
|
|
/*
|
|
* We have to allocate a new buffer. First, free the old one.
|
|
*/
|
|
MemFree(pbuf);
|
|
/*
|
|
* We'll alloc a slightly larger buffer than is absolutely
|
|
* necessary so that we'll have room to grow in.
|
|
*/
|
|
size += 4*sizeof(LPDDSPRITEI); // add some padding
|
|
pbuf = (LPBUFFER)MemAlloc(size);
|
|
pMaster->pBuffer = pbuf;
|
|
if (pbuf == NULL)
|
|
{
|
|
return NULL; // error -- out of memory
|
|
}
|
|
pbuf->dwSize = size;
|
|
}
|
|
/*
|
|
* Initialize values in HAL data structure to be passed to driver.
|
|
*/
|
|
pHalData = &(pbuf->HalData);
|
|
pHalData->lpDD = pMaster->pdrv;
|
|
pHalData->lpDDSurface = pMaster->surf_lcl; // primary surface (local object)
|
|
pHalData->lplpDDSprite = &(pbuf->pSprite[0]);
|
|
pHalData->dwCount = dwNumSprites;
|
|
pHalData->dwSize = sizeof(DDSPRITEI);
|
|
pHalData->dwFlags = pMaster->dwFlags;
|
|
pHalData->lpDDTargetSurface = NULL; // can't flip shared surface
|
|
pHalData->dwRectCnt = 0;
|
|
pHalData->lpRect = NULL; // each sprite has its own clip region
|
|
pHalData->ddRVal = 0;
|
|
//pHalData->SetSpriteDisplayList = NULL; // no thunk (32-bit callback)
|
|
/*
|
|
* Load the sprite-pointer array with the pointers to
|
|
* all the sprites contained in the various sublists.
|
|
*/
|
|
ppSprite = &pbuf->pSprite[0];
|
|
|
|
for (i = 0; i < dwNumSubLists; ++i)
|
|
{
|
|
LPSPRITESUBLIST pSubList = pMaster->pSubList[i];
|
|
LPDDSPRITEI sprite = &pSubList->sprite[0];
|
|
DWORD dwCount = pSubList->dwCount; // number of sprites in sublist i
|
|
DWORD j;
|
|
|
|
for (j = 0; j < dwCount; ++j)
|
|
{
|
|
/*
|
|
* Copy address of next sprite into pointer array.
|
|
*/
|
|
*ppSprite++ = &sprite[j];
|
|
}
|
|
}
|
|
return (&pbuf->HalData); // return temp sprite display list
|
|
|
|
} /* buildTempDisplayList */
|
|
|
|
|
|
/*
|
|
* Global function for managing master sprite list. This function
|
|
* is called by CurrentProcessCleanup to remove from the master
|
|
* sprite list all references to a process that is being terminated.
|
|
* The function also checks for lost surfaces in the master sprite
|
|
* list. If any changes are made to the master sprite list, the
|
|
* driver is told to display those changes immediately.
|
|
*/
|
|
void ProcessSpriteCleanup(LPDDRAWI_DIRECTDRAW_GBL pdrv, DWORD pid)
|
|
{
|
|
LPMASTERSPRITELIST pMaster = (LPMASTERSPRITELIST)pdrv->lpMasterSpriteList;
|
|
LPDIRECTDRAWSURFACE pPrimary;
|
|
DWORD dwNumSubLists;
|
|
BOOL bDeleteSubList = FALSE;
|
|
BOOL bChangesMade = FALSE;
|
|
DWORD i;
|
|
|
|
if (pMaster == NULL)
|
|
{
|
|
return; // master sprite list does not exist
|
|
}
|
|
|
|
pPrimary = pMaster->pSubList[0]->pPrimary;
|
|
dwNumSubLists = pMaster->dwNumSubLists;
|
|
|
|
/*
|
|
* Before making changes to the master sprite list, we first
|
|
* unmark all clipper and surface objects in the list. After
|
|
* the changes are completed, we will again mark the objects
|
|
* that are referenced in the revised master sprite list.
|
|
*/
|
|
unmarkSpriteObjects(pMaster);
|
|
|
|
/*
|
|
* Each sublist of the master sprite list contains all the sprites
|
|
* that are to appear within a particular window of a shared primary.
|
|
* Associated with each sublist is the process ID for the window.
|
|
* Compare this process ID with argument pid. If they match,
|
|
* delete the sublist from the master sprite list.
|
|
*/
|
|
for (i = 0; i < dwNumSubLists; ++i)
|
|
{
|
|
LPSPRITESUBLIST pSubList = pMaster->pSubList[i];
|
|
LPDIRECTDRAWSURFACE pPrimary = pSubList->pPrimary;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_int = (LPDDRAWI_DDRAWSURFACE_INT)pPrimary;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl = surf_int->lpLcl;
|
|
|
|
/*
|
|
* Is process associated with this sublist being terminated?
|
|
* (We also check for lost surfaces and delete any we find.)
|
|
*/
|
|
if (pSubList->dwProcessId != pid &&
|
|
validClipperWindow(pSubList->pClipper) &&
|
|
!SURFACE_LOST(surf_lcl))
|
|
{
|
|
DWORD dwNumSprites = pSubList->dwCount;
|
|
LPDDSPRITEI sprite = &pSubList->sprite[0];
|
|
BOOL bDeleteSprite = FALSE;
|
|
DWORD j;
|
|
|
|
/*
|
|
* No, the process for this sublist is NOT being terminated.
|
|
* Check if the source surfaces for any sprites are lost.
|
|
*/
|
|
for (j = 0; j < dwNumSprites; ++j)
|
|
{
|
|
LPDIRECTDRAWSURFACE pSrcSurf = sprite[j].lpDDSSrc;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_src_int = (LPDDRAWI_DDRAWSURFACE_INT)pSrcSurf;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_src_lcl = surf_src_int->lpLcl;
|
|
|
|
if (SURFACE_LOST(surf_src_lcl))
|
|
{
|
|
/*
|
|
* This surface is lost, so delete the reference.
|
|
*/
|
|
sprite[j].lpDDSSrc = NULL; // mark surface as null
|
|
bDeleteSprite = TRUE; // remember sprite array needs fix-up
|
|
}
|
|
}
|
|
/*
|
|
* If the source-surface pointer for any sprite in the sublist
|
|
* was set to null, remove the sprite from the sublist by moving
|
|
* the rest of the sprite array downward to fill the gap.
|
|
*/
|
|
if (bDeleteSprite == TRUE)
|
|
{
|
|
dwNumSprites = scrunchSubList(pSubList);
|
|
bChangesMade = TRUE; // remember change to master sprite list
|
|
}
|
|
if (dwNumSprites != 0)
|
|
{
|
|
/*
|
|
* The sublist still contains sprites, so don't delete it.
|
|
*/
|
|
continue; // go to next sublist
|
|
}
|
|
}
|
|
/*
|
|
* Delete the sublist. The reason is that (1) the process that
|
|
* owns the sublist is being terminated, or (2) the sublist is
|
|
* associated with an invalid window, or (3) the source surface
|
|
* for every sprite in the sublist is a lost surface.
|
|
*/
|
|
MemFree(pSubList->pRgn);
|
|
MemFree(pSubList);
|
|
pMaster->pSubList[i] = NULL; // mark sublist as null
|
|
bDeleteSubList = TRUE; // remember we deleted sublist
|
|
}
|
|
/*
|
|
* If the sublist pointer for any sublist in the master sprite
|
|
* list was set to null, remove the null from the pointer array by
|
|
* moving the rest of the pointer array downward to fill the gap.
|
|
*/
|
|
if (bDeleteSubList)
|
|
{
|
|
dwNumSubLists = scrunchMasterSpriteList(pMaster);
|
|
bChangesMade = TRUE;
|
|
}
|
|
/*
|
|
* If any changes have been made to the master sprite list, tell
|
|
* the driver to make the changes visible on the screen.
|
|
*/
|
|
if (bChangesMade)
|
|
{
|
|
DWORD rc;
|
|
LPDDHAL_SETSPRITEDISPLAYLIST pfn;
|
|
DDHAL_SETSPRITEDISPLAYLISTDATA *pHalData;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_int = (LPDDRAWI_DDRAWSURFACE_INT)pPrimary;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl = surf_int->lpLcl;
|
|
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl = surf_lcl->lpSurfMore->lpDD_lcl;
|
|
|
|
/*
|
|
* Build a temporary display list that contains all the sprites
|
|
* in the revised master sprite list.
|
|
*/
|
|
pMaster->surf_lcl = surf_lcl; // used by buildTempDisplayList
|
|
#if 0
|
|
pMaster->dwFlags = DDSSDL_BLTSPRITES; // debug !!
|
|
#else
|
|
pMaster->dwFlags = DDSSDL_OVERLAYSPRITES; // used by buildTempDisplayList
|
|
#endif
|
|
pHalData = buildTempDisplayList(pMaster);
|
|
/*
|
|
* Pass the temp display list to the driver.
|
|
*/
|
|
#if 0
|
|
pfn = pdrv_lcl->lpDDCB->HELDDMiscellaneous2.SetSpriteDisplayList; // debug !!
|
|
#else
|
|
pfn = pdrv_lcl->lpDDCB->HALDDMiscellaneous2.SetSpriteDisplayList;
|
|
#endif
|
|
DOHALCALL(SetSpriteDisplayList, pfn, *pHalData, rc, 0);
|
|
}
|
|
|
|
if (dwNumSubLists == 0)
|
|
{
|
|
/*
|
|
* We deleted ALL the sublists from the master sprite list,
|
|
* so now we need to delete the master sprite list too.
|
|
*/
|
|
FreeMasterSpriteList(pdrv);
|
|
return;
|
|
}
|
|
markSpriteObjects(pMaster);
|
|
|
|
} /* ProcessSpriteCleanup */
|
|
|
|
|
|
/*
|
|
* Global function for managing master sprite list. This function is
|
|
* called by InternalSurfaceRelease to remove all references in the
|
|
* master sprite list to a surface interface object that is being
|
|
* released. The function also checks for lost surfaces in the
|
|
* master sprite list. If any changes are made to the master sprite
|
|
* list, the driver is told to display those changes immediately.
|
|
*/
|
|
void RemoveSpriteSurface(LPDDRAWI_DIRECTDRAW_GBL pdrv,
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_int)
|
|
{
|
|
LPMASTERSPRITELIST pMaster = (LPMASTERSPRITELIST)pdrv->lpMasterSpriteList;
|
|
LPDIRECTDRAWSURFACE pSurface = (LPDIRECTDRAWSURFACE)surf_int;
|
|
LPDIRECTDRAWSURFACE pPrimary = pMaster->pSubList[0]->pPrimary;
|
|
DWORD dwNumSubLists = pMaster->dwNumSubLists;
|
|
BOOL bDeleteSubList = FALSE;
|
|
BOOL bChangesMade = FALSE;
|
|
DWORD i;
|
|
|
|
DDASSERT(pMaster != NULL); // error -- surface shouldn't be marked!
|
|
|
|
/*
|
|
* Before making changes to the master sprite list, we first
|
|
* unmark all clipper and surface objects in the list. After
|
|
* the changes are completed, we will again mark the objects
|
|
* that are referenced in the revised master sprite list.
|
|
*/
|
|
unmarkSpriteObjects(pMaster);
|
|
|
|
/*
|
|
* Each sublist of the master sprite list contains all the sprites
|
|
* that are to appear within a particular window of a shared primary.
|
|
* Stored with each sublist is the primary surface object for the
|
|
* window, and also the source surface objects for each sprite in the
|
|
* sublist. These surfaces are checked against pSurface and if a
|
|
* match is found, the surface reference is deleted from the sublist.
|
|
*/
|
|
for (i = 0; i < dwNumSubLists; ++i)
|
|
{
|
|
LPSPRITESUBLIST pSubList = pMaster->pSubList[i];
|
|
LPDIRECTDRAWSURFACE pDestSurf = pSubList->pPrimary;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_dest_int = (LPDDRAWI_DDRAWSURFACE_INT)pDestSurf;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_dest_lcl = surf_dest_int->lpLcl;
|
|
|
|
/*
|
|
* If this sublist's primary surface object is being released, delete
|
|
* the sublist. We also check for lost surfaces and delete any we find.
|
|
*/
|
|
if (pDestSurf != pSurface && validClipperWindow(pSubList->pClipper) &&
|
|
!SURFACE_LOST(surf_dest_lcl))
|
|
{
|
|
DWORD dwNumSprites = pSubList->dwCount;
|
|
LPDDSPRITEI sprite = &pSubList->sprite[0];
|
|
BOOL bDeleteSprite = FALSE;
|
|
DWORD j;
|
|
|
|
/*
|
|
* No, the primary surface object for this sublist is NOT
|
|
* being released, but perhaps the source surface for one
|
|
* or more of the sprites in this sublist is being released.
|
|
*/
|
|
for (j = 0; j < dwNumSprites; ++j)
|
|
{
|
|
LPDIRECTDRAWSURFACE pSrcSurf = sprite[j].lpDDSSrc;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_src_int = (LPDDRAWI_DDRAWSURFACE_INT)pSrcSurf;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_src_lcl = surf_src_int->lpLcl;
|
|
|
|
if (pSrcSurf == pSurface || SURFACE_LOST(surf_src_lcl))
|
|
{
|
|
/*
|
|
* This surface either is being released or is lost.
|
|
* In either case, we delete the reference.
|
|
*/
|
|
sprite[j].lpDDSSrc = NULL; // mark surface as null
|
|
bDeleteSprite = TRUE; // remember sprite array needs fix-up
|
|
}
|
|
}
|
|
/*
|
|
* If the source-surface pointer for any sprite in the sublist
|
|
* was set to null, remove the sprite from the sublist by moving
|
|
* the rest of the sprite array downward to fill the gap.
|
|
*/
|
|
if (bDeleteSprite == TRUE)
|
|
{
|
|
dwNumSprites = scrunchSubList(pSubList);
|
|
bChangesMade = TRUE; // remember change to master sprite list
|
|
}
|
|
if (dwNumSprites != 0)
|
|
{
|
|
/*
|
|
* The sublist still contains sprites, so don't delete it.
|
|
*/
|
|
continue; // go to next sublist
|
|
}
|
|
}
|
|
/*
|
|
* Delete the sublist. The reason is that (1) the primary surface
|
|
* object for the sublist is being released, or (2) the sublist is
|
|
* associated with an invalid window, or (3) the source surface
|
|
* for every sprite in the sublist is either being released or is
|
|
* a lost surface.
|
|
*/
|
|
MemFree(pSubList->pRgn);
|
|
MemFree(pSubList);
|
|
pMaster->pSubList[i] = NULL; // mark sublist as null
|
|
bDeleteSubList = TRUE; // remember we deleted sublist
|
|
}
|
|
/*
|
|
* If the sublist pointer for any sublist in the master sprite
|
|
* list was set to null, remove the null from the pointer array by
|
|
* moving the rest of the pointer array downward to fill the gap.
|
|
*/
|
|
if (bDeleteSubList)
|
|
{
|
|
dwNumSubLists = scrunchMasterSpriteList(pMaster);
|
|
bChangesMade = TRUE;
|
|
}
|
|
/*
|
|
* If any changes have been made to the master sprite list, tell
|
|
* the driver to make the changes visible on the screen.
|
|
*/
|
|
if (bChangesMade)
|
|
{
|
|
DWORD rc;
|
|
LPDDHAL_SETSPRITEDISPLAYLIST pfn;
|
|
DDHAL_SETSPRITEDISPLAYLISTDATA *pHalData;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_int = (LPDDRAWI_DDRAWSURFACE_INT)pPrimary;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl = surf_int->lpLcl;
|
|
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl = surf_lcl->lpSurfMore->lpDD_lcl;
|
|
|
|
/*
|
|
* Build a temporary display list that contains all the sprites
|
|
* in the revised master sprite list.
|
|
*/
|
|
pMaster->surf_lcl = surf_lcl; // used by buildTempDisplayList
|
|
#if 0
|
|
pMaster->dwFlags = DDSSDL_BLTSPRITES; // debug !!
|
|
#else
|
|
pMaster->dwFlags = DDSSDL_OVERLAYSPRITES; // used by buildTempDisplayList
|
|
#endif
|
|
pHalData = buildTempDisplayList(pMaster);
|
|
/*
|
|
* Pass the temp display list to the driver.
|
|
*/
|
|
#if 0
|
|
pfn = pdrv_lcl->lpDDCB->HELDDMiscellaneous2.SetSpriteDisplayList; // debug !!
|
|
#else
|
|
pfn = pdrv_lcl->lpDDCB->HALDDMiscellaneous2.SetSpriteDisplayList;
|
|
#endif
|
|
DOHALCALL(SetSpriteDisplayList, pfn, *pHalData, rc, 0);
|
|
}
|
|
|
|
if (dwNumSubLists == 0)
|
|
{
|
|
/*
|
|
* We deleted ALL the sublists from the master sprite list,
|
|
* so now we need to delete the master sprite list too.
|
|
*/
|
|
FreeMasterSpriteList(pdrv);
|
|
return;
|
|
}
|
|
markSpriteObjects(pMaster);
|
|
|
|
} /* RemoveSpriteSurface */
|
|
|
|
|
|
/*
|
|
* Global function for managing master sprite list. This function is
|
|
* called by InternalClipperRelease to remove all references in the
|
|
* master sprite list to a clipper object that is being released.
|
|
* The function also checks for lost surfaces in the master sprite
|
|
* list. If any changes are made to the master sprite list, the
|
|
* driver is told to display those changes immediately.
|
|
*/
|
|
void RemoveSpriteClipper(LPDDRAWI_DIRECTDRAW_GBL pdrv,
|
|
LPDDRAWI_DDRAWCLIPPER_INT pclip_int)
|
|
{
|
|
LPMASTERSPRITELIST pMaster = (LPMASTERSPRITELIST)pdrv->lpMasterSpriteList;
|
|
LPDIRECTDRAWSURFACE pPrimary = pMaster->pSubList[0]->pPrimary;
|
|
LPDIRECTDRAWCLIPPER pClipper = (LPDIRECTDRAWCLIPPER)pclip_int;
|
|
DWORD dwNumSubLists = pMaster->dwNumSubLists;
|
|
BOOL bDeleteSubList = FALSE;
|
|
BOOL bChangesMade = FALSE;
|
|
DWORD i;
|
|
|
|
DDASSERT(pMaster != NULL); // error -- surface shouldn't be marked!
|
|
|
|
/*
|
|
* Before making changes to the master sprite list, we first
|
|
* unmark all clipper and surface objects in the list. After
|
|
* the changes are completed, we will again mark the objects
|
|
* that are referenced in the revised master sprite list.
|
|
*/
|
|
unmarkSpriteObjects(pMaster);
|
|
|
|
/*
|
|
* Each sublist of the master sprite list contains all the sprites
|
|
* that are to appear within a particular window of a shared primary.
|
|
* Each sublist has a clipper (which may be NULL) to specify the
|
|
* window's clip region. Each sublist's clipper pointer is compared
|
|
* with the specified pClipper pointer. If a match is found, the
|
|
* sublist and its clipper are removed from the master sprite list.
|
|
*/
|
|
for (i = 0; i < dwNumSubLists; ++i)
|
|
{
|
|
LPSPRITESUBLIST pSubList = pMaster->pSubList[i];
|
|
LPDIRECTDRAWSURFACE pDestSurf = pSubList->pPrimary;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_dest_int = (LPDDRAWI_DDRAWSURFACE_INT)pDestSurf;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_dest_lcl = surf_dest_int->lpLcl;
|
|
|
|
/*
|
|
* If clipper object for this sublist is being released, delete it.
|
|
* (We also check for lost surfaces and delete any we find.)
|
|
*/
|
|
if (pSubList->pClipper != pClipper &&
|
|
validClipperWindow(pSubList->pClipper) &&
|
|
!SURFACE_LOST(surf_dest_lcl))
|
|
{
|
|
DWORD dwNumSprites = pSubList->dwCount;
|
|
LPDDSPRITEI sprite = &pSubList->sprite[0];
|
|
BOOL bDeleteSprite = FALSE;
|
|
DWORD j;
|
|
|
|
/*
|
|
* No, the clipper for this sublist is NOT being released.
|
|
* Check if the source surfaces for any sprites are lost.
|
|
*/
|
|
for (j = 0; j < dwNumSprites; ++j)
|
|
{
|
|
LPDIRECTDRAWSURFACE pSrcSurf = sprite[j].lpDDSSrc;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_src_int = (LPDDRAWI_DDRAWSURFACE_INT)pSrcSurf;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_src_lcl = surf_src_int->lpLcl;
|
|
|
|
if (SURFACE_LOST(surf_src_lcl))
|
|
{
|
|
/*
|
|
* This surface is lost, so delete the reference.
|
|
*/
|
|
sprite[j].lpDDSSrc = NULL; // mark surface as null
|
|
bDeleteSprite = TRUE; // remember sprite array needs fix-up
|
|
}
|
|
}
|
|
/*
|
|
* If the source-surface pointer for any sprite in the sublist
|
|
* was set to null, remove the sprite from the sublist by moving
|
|
* the rest of the sprite array downward to fill the gap.
|
|
*/
|
|
if (bDeleteSprite == TRUE)
|
|
{
|
|
dwNumSprites = scrunchSubList(pSubList);
|
|
bChangesMade = TRUE; // remember change to master sprite list
|
|
}
|
|
if (dwNumSprites != 0)
|
|
{
|
|
/*
|
|
* The sublist still contains sprites, so don't delete it.
|
|
*/
|
|
continue; // go to next sublist
|
|
}
|
|
}
|
|
/*
|
|
* Delete the sublist. The reason is that (1) the clipper for the
|
|
* sublist is being released, (2) the sublist is associated with an
|
|
* invalid window, or (3) the source surface for every sprite in
|
|
* the sublist is a lost surface.
|
|
*/
|
|
MemFree(pSubList->pRgn);
|
|
MemFree(pSubList);
|
|
pMaster->pSubList[i] = NULL; // mark sublist as null
|
|
bDeleteSubList = TRUE; // remember we deleted sublist
|
|
}
|
|
/*
|
|
* If the sublist pointer for any sublist in the master sprite
|
|
* list was set to null, remove the null from the pointer array by
|
|
* moving the rest of the pointer array downward to fill the gap.
|
|
*/
|
|
if (bDeleteSubList)
|
|
{
|
|
dwNumSubLists = scrunchMasterSpriteList(pMaster);
|
|
bChangesMade = TRUE;
|
|
}
|
|
/*
|
|
* If any changes have been made to the master sprite list, tell
|
|
* the driver to make the changes visible on the screen.
|
|
*/
|
|
if (bChangesMade)
|
|
{
|
|
DWORD rc;
|
|
LPDDHAL_SETSPRITEDISPLAYLIST pfn;
|
|
DDHAL_SETSPRITEDISPLAYLISTDATA *pHalData;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_int = (LPDDRAWI_DDRAWSURFACE_INT)pPrimary;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl = surf_int->lpLcl;
|
|
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl = surf_lcl->lpSurfMore->lpDD_lcl;
|
|
|
|
/*
|
|
* Build a temporary display list that contains all the sprites
|
|
* in the revised master sprite list.
|
|
*/
|
|
pMaster->surf_lcl = surf_lcl; // used by buildTempDisplayList
|
|
#if 0
|
|
pMaster->dwFlags = DDSSDL_BLTSPRITES; // debug !!
|
|
#else
|
|
pMaster->dwFlags = DDSSDL_OVERLAYSPRITES; // used by buildTempDisplayList
|
|
#endif
|
|
pHalData = buildTempDisplayList(pMaster);
|
|
/*
|
|
* Pass the temp display list to the driver.
|
|
*/
|
|
#if 0
|
|
pfn = pdrv_lcl->lpDDCB->HELDDMiscellaneous2.SetSpriteDisplayList; // debug !!
|
|
#else
|
|
pfn = pdrv_lcl->lpDDCB->HALDDMiscellaneous2.SetSpriteDisplayList;
|
|
#endif
|
|
DOHALCALL(SetSpriteDisplayList, pfn, *pHalData, rc, 0);
|
|
}
|
|
|
|
if (dwNumSubLists == 0)
|
|
{
|
|
/*
|
|
* We deleted ALL the sublists from the master sprite list,
|
|
* so now we need to delete the master sprite list too.
|
|
*/
|
|
FreeMasterSpriteList(pdrv);
|
|
return;
|
|
}
|
|
markSpriteObjects(pMaster);
|
|
|
|
} /* RemoveSpriteClipper */
|
|
|
|
|
|
/*
|
|
* Helper function for managing master sprite list. Check each sprite
|
|
* to see if its surface has been lost. Also check each sublist to
|
|
* see if its window still exists. Sprites with lost surfaces are
|
|
* deleted from the master sprite list. Also, sublists with defunct
|
|
* windows are deleted. Before calling this function, call
|
|
* unmarkSpriteObjects().
|
|
*/
|
|
static void removeLostSpriteSurfaces(LPDDRAWI_DIRECTDRAW_GBL pdrv)
|
|
{
|
|
DWORD i;
|
|
DWORD dwNumSubLists;
|
|
LPMASTERSPRITELIST pMaster = pdrv->lpMasterSpriteList;
|
|
BOOL bDeleteSubList = FALSE;
|
|
|
|
if (pMaster == NULL)
|
|
{
|
|
return; // nothing to do -- bye!
|
|
}
|
|
|
|
dwNumSubLists = pMaster->dwNumSubLists;
|
|
DDASSERT(dwNumSubLists != 0);
|
|
|
|
/*
|
|
* Each iteration checks all the sprites in one sublist
|
|
* to see if their source surfaces have been lost.
|
|
*/
|
|
for (i = 0; i < dwNumSubLists; ++i)
|
|
{
|
|
LPSPRITESUBLIST pSubList = pMaster->pSubList[i];
|
|
|
|
/*
|
|
* Verify that clipper for this sublist has a valid window handle.
|
|
*/
|
|
if (validClipperWindow(pSubList->pClipper))
|
|
{
|
|
LPDDSPRITEI sprite = &pSubList->sprite[0];
|
|
DWORD dwNumSprites = pSubList->dwCount;
|
|
BOOL bDeleteSprite = FALSE;
|
|
DWORD j;
|
|
|
|
DDASSERT(dwNumSprites != 0);
|
|
|
|
/*
|
|
* Yes, clipper's window handle is valid. Now check to see if
|
|
* any of the sprites in the sublist have lost source surfaces.
|
|
*/
|
|
for (j = 0; j < dwNumSprites; ++j)
|
|
{
|
|
LPDIRECTDRAWSURFACE pSrcSurf = sprite[j].lpDDSSrc;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_src_int = (LPDDRAWI_DDRAWSURFACE_INT)pSrcSurf;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_src_lcl = surf_src_int->lpLcl;
|
|
|
|
if (SURFACE_LOST(surf_src_lcl)) // is this surface lost?
|
|
{
|
|
sprite[j].lpDDSSrc = NULL; // yes, set surface ptr to null
|
|
bDeleteSprite = TRUE; // remember sublist needs fix-up
|
|
}
|
|
}
|
|
/*
|
|
* If the source-surface pointer for any sprite in the sublist
|
|
* was set to null, remove the sprite from the sublist by moving
|
|
* the rest of the sprite array downward to fill the gap.
|
|
*/
|
|
if (bDeleteSprite == TRUE)
|
|
{
|
|
dwNumSprites = scrunchSubList(pSubList);
|
|
}
|
|
if (dwNumSprites != 0)
|
|
{
|
|
/*
|
|
* The sublist still contains sprites, so don't delete it.
|
|
*/
|
|
continue; // go to next sublist
|
|
}
|
|
}
|
|
/*
|
|
* Delete the sublist. The reason is either that the window
|
|
* handle associated with this sublist's clipper is not valid,
|
|
* or that all the sprites in the sublist have been deleted.
|
|
*/
|
|
MemFree(pSubList->pRgn);
|
|
MemFree(pSubList);
|
|
pMaster->pSubList[i] = NULL; // mark sublist as null
|
|
bDeleteSubList = TRUE; // remember we deleted sublist
|
|
|
|
}
|
|
/*
|
|
* If the sublist pointer for any sublist in the master sprite
|
|
* list was set to null, remove the null from the pointer array by
|
|
* moving the rest of the pointer array downward to fill the gap.
|
|
*/
|
|
if (bDeleteSubList)
|
|
{
|
|
scrunchMasterSpriteList(pMaster);
|
|
|
|
if (pMaster->dwNumSubLists == 0)
|
|
{
|
|
FreeMasterSpriteList(pdrv); // delete master sprite list
|
|
}
|
|
}
|
|
} /* removeLostSpriteSurfaces */
|
|
|
|
|
|
/*
|
|
* This is a helper function for updateMasterSpriteList(). It alloc's
|
|
* a sublist and copies the new sprite display list into the sublist.
|
|
* If pSubList already points to a buffer that is large enough, the new
|
|
* sublist will be created in this buffer. Otherwise, a new buffer
|
|
* will be alloc'd (but the old buffer isn't freed -- that's left up to
|
|
* the caller). Arg pHalData points to the sprite display list from
|
|
* the app. The return value is a pointer to the new sublist.
|
|
*/
|
|
static LPSPRITESUBLIST createSpriteSubList(LPSPRITESUBLIST pSubList,
|
|
DDHAL_SETSPRITEDISPLAYLISTDATA *pHalData,
|
|
LPDIRECTDRAWSURFACE pPrimary)
|
|
{
|
|
LPDDSPRITEI *ppSprite;
|
|
LPDDSPRITEI sprite;
|
|
// pointers to local and global surface objects
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl = pHalData->lpDDSurface;
|
|
LPDDRAWI_DDRAWSURFACE_GBL surf = surf_lcl->lpGbl;
|
|
// number of sprites in new display list:
|
|
DWORD dwNumSprites = pHalData->dwCount;
|
|
// size (in bytes) of new sublist:
|
|
DWORD size = sizeof(SPRITESUBLIST) +
|
|
(dwNumSprites-1)*sizeof(DDSPRITEI);
|
|
|
|
DDASSERT(dwNumSprites != 0);
|
|
|
|
/*
|
|
* If old sublist buffer is null or too small or too big,
|
|
* allocate a new sublist buffer that's the correct size.
|
|
*/
|
|
if (pSubList == NULL || pSubList->dwSize < size ||
|
|
pSubList->dwSize > size + 8*sizeof(DDSPRITEI))
|
|
{
|
|
/*
|
|
* Allocate a new sublist that's just a tad larger than
|
|
* necessary so that we have a little room to grow in.
|
|
*/
|
|
size += 4*sizeof(DDSPRITEI); // add some padding
|
|
pSubList = (LPSPRITESUBLIST)MemAlloc(size);
|
|
if (pSubList == NULL)
|
|
{
|
|
return NULL; // error -- out of memory
|
|
}
|
|
pSubList->dwSize = size; // remember how big buffer is
|
|
}
|
|
/*
|
|
* Initialize sublist buffer.
|
|
*/
|
|
pSubList->pPrimary = pPrimary; // primary surface (interface object)
|
|
pSubList->pClipper = (LPDIRECTDRAWCLIPPER)surf_lcl->lpSurfMore->lpDDIClipper;
|
|
pSubList->dwProcessId = GETCURRPID();
|
|
pSubList->dwCount = dwNumSprites; // number of sprites in sublist
|
|
pSubList->pRgn = NULL;
|
|
/*
|
|
* To keep things simple, the master sprite display list always stores
|
|
* sprites in front-to-back order, regardless of how callers order them.
|
|
* The loop below copies the sprites into a contiguous array of sprites.
|
|
*/
|
|
sprite = &pSubList->sprite[0]; // array of sprites
|
|
ppSprite = pHalData->lplpDDSprite; // array of sprite pointers
|
|
|
|
if (pHalData->dwFlags & DDSSDL_BACKTOFRONT)
|
|
{
|
|
int i, j;
|
|
|
|
// Reverse original back-to-front ordering of sprites.
|
|
for (i = 0, j = (int)dwNumSprites-1; j >= 0; ++i, --j)
|
|
{
|
|
memcpy(&sprite[i], ppSprite[j], sizeof(DDSPRITEI));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
|
|
// Preserve original front-to-back ordering of sprites.
|
|
for (i = 0; i < (int)dwNumSprites; ++i)
|
|
{
|
|
memcpy(&sprite[i], ppSprite[i], sizeof(DDSPRITEI));
|
|
}
|
|
}
|
|
return (pSubList); // return completed sublist
|
|
|
|
} /* createSpriteSubList */
|
|
|
|
|
|
/*
|
|
* This routine adds a new display list to the master sprite display list,
|
|
* which keeps track of all overlay sprites currently displayed on the shared
|
|
* primary. Don't call it if (1) the sprites are blitted or (2) the primary
|
|
* is not shared. The update replaces the display list for the affected
|
|
* window, but leaves the display lists for all other windows unchanged.
|
|
* Arg surf_lcl points to the primary. Input arg **ppHalData is the HAL
|
|
* callback struct that specifies the new display list. If the original
|
|
* sprite display list in **ppHalData can be used in place of a master
|
|
* display list without zapping sprites in other windows. Otherwise, the
|
|
* routine sets *ppHalData to point to a master sprite list that contains
|
|
* the overlay sprites for all windows.
|
|
*/
|
|
static HRESULT updateMasterSpriteList(LPDIRECTDRAWSURFACE pPrimary,
|
|
DDHAL_SETSPRITEDISPLAYLISTDATA **ppHalData)
|
|
{
|
|
DWORD i;
|
|
LPDIRECTDRAWCLIPPER pClipper;
|
|
DDHAL_SETSPRITEDISPLAYLISTDATA *pHalData;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_int = (LPDDRAWI_DDRAWSURFACE_INT)pPrimary;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl = surf_int->lpLcl;
|
|
LPDDRAWI_DDRAWSURFACE_MORE surf_more = surf_lcl->lpSurfMore;
|
|
LPDDRAWI_DIRECTDRAW_GBL pdrv = surf_more->lpDD_lcl->lpGbl;
|
|
DWORD dwProcessId;
|
|
LPMASTERSPRITELIST pMaster;
|
|
LPSPRITESUBLIST pSubList;
|
|
DWORD dwNumSprites = (*ppHalData)->dwCount; // number of sprites in display list
|
|
|
|
/*
|
|
* Get pointer to master sprite list.
|
|
*/
|
|
pMaster = (LPMASTERSPRITELIST)pdrv->lpMasterSpriteList;
|
|
|
|
if (pMaster != NULL)
|
|
{
|
|
/*
|
|
* A master sprite list already exists.
|
|
*/
|
|
#ifdef WIN95
|
|
if (pMaster->dwModeCreatedIn != pdrv->dwModeIndex) // current mode index
|
|
#else
|
|
if (!EQUAL_DISPLAYMODE(pMaster->dmiCreated, pdrv->dmiCurrent))
|
|
#endif
|
|
{
|
|
/*
|
|
* The master sprite list was created in a different video mode
|
|
* and is therefore no longer valid. We rely on the mini-vdd
|
|
* driver remembering to turn off all overlay sprites when a
|
|
* mode change occurs, so they should already be turned off.
|
|
* All we do here is to update our internal data structures.
|
|
*/
|
|
FreeMasterSpriteList(pdrv);
|
|
pMaster = NULL;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Between calls to SetSpriteDisplayList, all surface and clipper
|
|
* objects in the master sprite list are marked so that we will be
|
|
* notified if any of these objects are released, invalidating our
|
|
* references to them. We now unmark all surface/clipper objects
|
|
* in the master sprite list so we can update the references.
|
|
*/
|
|
unmarkSpriteObjects(pMaster);
|
|
/*
|
|
* Remove any references to lost surfaces from master sprite list.
|
|
*/
|
|
removeLostSpriteSurfaces(pdrv); // can delete master sprite list
|
|
/*
|
|
* Just in case the call above deleted the master sprite list...
|
|
*/
|
|
pMaster = (LPMASTERSPRITELIST)pdrv->lpMasterSpriteList;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Has the master sprite list been created yet?
|
|
*/
|
|
if (pMaster == NULL)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_GBL surf = surf_lcl->lpGbl;
|
|
|
|
/*
|
|
* No, the master sprite list has not been created.
|
|
*/
|
|
if (dwNumSprites == 0)
|
|
{
|
|
/*
|
|
* The new display list is empty, so don't bother
|
|
* to create the master sprite list.
|
|
*/
|
|
return (DD_OK); // nothing to do -- bye!
|
|
}
|
|
/*
|
|
* The new display list is not empty, so we will now
|
|
* create the master sprite list and copy the new display
|
|
* list into the initial sublist of the master sprite list.
|
|
*/
|
|
pMaster = (LPMASTERSPRITELIST)MemAlloc(sizeof(MASTERSPRITELIST));
|
|
if (pMaster == NULL)
|
|
{
|
|
return (DDERR_OUTOFMEMORY); // error -- out of memory
|
|
}
|
|
/*
|
|
* Initialize the values in the master list header structure.
|
|
*/
|
|
pMaster->pdrv = pdrv;
|
|
pMaster->surf_lcl = surf_lcl; // primary surface (local object)
|
|
SetRect(&pMaster->rcPrimary, 0, 0, surf->wWidth, surf->wHeight);
|
|
pMaster->dwFlags = (*ppHalData)->dwFlags & (DDSSDL_WAIT |
|
|
#if 0
|
|
DDSSDL_BLTSPRITES); // debug!!
|
|
#else
|
|
DDSSDL_OVERLAYSPRITES);
|
|
#endif
|
|
#ifdef WIN95
|
|
pMaster->dwModeCreatedIn = pdrv->dwModeIndex; // current mode index
|
|
#else
|
|
pMaster->dmiCreated = pdrv->dmiCurrent;
|
|
#endif
|
|
pMaster->pBuffer = NULL;
|
|
/*
|
|
* Copy the new sprite display list into the initial sublist.
|
|
*/
|
|
pMaster->dwNumSubLists = 1;
|
|
pMaster->pSubList[0] = createSpriteSubList(NULL, *ppHalData, pPrimary);
|
|
if (pMaster->pSubList[0] == NULL)
|
|
{
|
|
MemFree(pMaster);
|
|
return (DDERR_OUTOFMEMORY);
|
|
}
|
|
/*
|
|
* Mark all the surface and clipper objects that are
|
|
* referenced in the new master sprite list.
|
|
*/
|
|
markSpriteObjects(pMaster);
|
|
/*
|
|
* We've succeeded in creating a master sprite list. Load the
|
|
* pointer to the master list into the global DirectDraw object.
|
|
*/
|
|
pdrv->lpMasterSpriteList = (LPVOID)pMaster;
|
|
|
|
return (DD_OK); // new master sprite list completed
|
|
}
|
|
/*
|
|
* The master sprite list was created previously. There are
|
|
* three possibilities at this point (#1 is most likely):
|
|
* 1) We're REPLACING a sublist in the master sprite list.
|
|
* In this case, the new display list contains one or
|
|
* more sprites and the pClipper and ProcessId of the new
|
|
* display list will match those stored in a sublist.
|
|
* 2) We're ADDING a new sublist to the master sprite list.
|
|
* In this case, the new display list contains one or
|
|
* more sprites but the pClipper and ProcessId of the
|
|
* new display list don't match those of any sublist.
|
|
* 3) We're DELETING a sublist from the master sprite list.
|
|
* In this case, the new display list is empty (sprite
|
|
* count = 0) and the pClipper and ProcessId of the new
|
|
* display list match those stored with a sublist.
|
|
*/
|
|
pClipper = (LPDIRECTDRAWCLIPPER)(surf_more->lpDDIClipper);
|
|
dwProcessId = GETCURRPID();
|
|
pMaster->surf_lcl = surf_lcl; // primary surface (local object)
|
|
pMaster->dwFlags = (*ppHalData)->dwFlags & (DDSSDL_WAIT |
|
|
#if 0
|
|
DDSSDL_BLTSPRITES); // debug !!
|
|
#else
|
|
DDSSDL_OVERLAYSPRITES);
|
|
#endif
|
|
for (i = 0; i < pMaster->dwNumSubLists; ++i)
|
|
{
|
|
/*
|
|
* Look for a sublist with a pointer to the same clipper object.
|
|
* To handle the case pClipper = NULL, we compare process IDs also.
|
|
*/
|
|
if (pMaster->pSubList[i]->pClipper == pClipper &&
|
|
pMaster->pSubList[i]->dwProcessId == dwProcessId)
|
|
{
|
|
break; // found a sublist with matching pClipper and dwProcessId
|
|
}
|
|
}
|
|
if (i == pMaster->dwNumSubLists)
|
|
{
|
|
/*
|
|
* The pClipper and Process ID of the new display list don't
|
|
* match those of any of the current sublists. This means
|
|
* that a new window has begun displaying overlay sprites.
|
|
*/
|
|
if (dwNumSprites == 0)
|
|
{
|
|
/*
|
|
* The new display list is empty, so don't bother adding
|
|
* a new (empty) sublist to the master sprite list.
|
|
*/
|
|
markSpriteObjects(pMaster);
|
|
return (DD_OK); // nothing to do -- bye!
|
|
}
|
|
/*
|
|
* Add a new sublist to the master sprite list and copy the
|
|
* new display list into the new sublist.
|
|
*/
|
|
pSubList = createSpriteSubList(NULL, *ppHalData, pPrimary);
|
|
if (pSubList == NULL)
|
|
{
|
|
return (DDERR_OUTOFMEMORY); // error -- out of memory
|
|
}
|
|
if (i != MAXNUMSPRITESUBLISTS)
|
|
{
|
|
/*
|
|
* Add the new sublist to the master sprite list.
|
|
*/
|
|
pMaster->dwNumSubLists++;
|
|
pMaster->pSubList[i] = pSubList;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Oops. The master sprite list already contains the maximum
|
|
* number of sublists. I guess I'll just delete one of the
|
|
* other sublists so I can add the new sublist. (If anybody
|
|
* complains loud enough, we can get rid of the fixed limit.)
|
|
*/
|
|
MemFree(pMaster->pSubList[i-1]);
|
|
pMaster->pSubList[i-1] = pSubList;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* We've found an existing sublist that matches the new display list's
|
|
* pClipper and ProcessId (the sublist contains the old display list
|
|
* for the window in which the new display list is to appear).
|
|
*/
|
|
if (dwNumSprites != 0)
|
|
{
|
|
/*
|
|
* Since the new display list is not empty, we will copy it
|
|
* into the sublist that contains the old display list for
|
|
* the same window, overwriting the old display list.
|
|
*/
|
|
pSubList = createSpriteSubList(pMaster->pSubList[i],
|
|
*ppHalData, pPrimary);
|
|
if (pSubList == NULL)
|
|
{
|
|
/*
|
|
* An allocation error has occurred. (Note: The original
|
|
* value of pMaster->pSubList[i] has not been altered.)
|
|
*/
|
|
return (DDERR_OUTOFMEMORY); // error -- out of memory
|
|
}
|
|
if (pSubList != pMaster->pSubList[i])
|
|
{
|
|
/*
|
|
* The createSpriteSubList call had to allocate a new
|
|
* sublist, so now we need to free the old one.
|
|
*/
|
|
MemFree(pMaster->pSubList[i]);
|
|
pMaster->pSubList[i] = pSubList;
|
|
}
|
|
if (pMaster->dwNumSubLists == 1)
|
|
{
|
|
/*
|
|
* Only one window is displaying overlay sprites, so the
|
|
* new display list contains the same sprites as the master
|
|
* sprite list. Don't bother to construct a temp display
|
|
* list to contain all the sprites in the master sprite list.
|
|
*/
|
|
return (DD_OK);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The new display list is empty. In this case, we just delete
|
|
* the sublist containing the old display list for the same window.
|
|
* This will leave a hole in the array of sublist pointers that we
|
|
* fill by moving all the higher members in the array down by one.
|
|
*/
|
|
MemFree(pMaster->pSubList[i]); // free sublist
|
|
if (pMaster->dwNumSubLists == 1)
|
|
{
|
|
/*
|
|
* We have just deleted the only sublist, so the master sprite
|
|
* list is now empty. Free the master sprite list and return.
|
|
*/
|
|
FreeMasterSpriteList(pdrv);
|
|
return (DD_OK);
|
|
}
|
|
// Delete the sublist from the master sprite list.
|
|
pMaster->pSubList[i] = NULL;
|
|
scrunchMasterSpriteList(pMaster);
|
|
}
|
|
}
|
|
/*
|
|
* We have finished updating the master sprite list. Mark all
|
|
* surface and clipper objects referenced in the master sprite list.
|
|
*/
|
|
markSpriteObjects(pMaster);
|
|
/*
|
|
* The final step is to build a temporary display list that
|
|
* contains all the sprites in the master sprite list.
|
|
* The caller can then pass this display list to the driver.
|
|
*/
|
|
pHalData = buildTempDisplayList(pMaster);
|
|
if (!pHalData)
|
|
{
|
|
return (DDERR_OUTOFMEMORY); // error -- out of memory
|
|
}
|
|
*ppHalData = pHalData; // update caller's display-list pointer
|
|
return (DD_OK);
|
|
|
|
} /* updateMasterSpriteList */
|
|
|
|
|
|
/*
|
|
* IDirectDrawSurface4::SetSpriteDisplayList -- API call
|
|
*/
|
|
HRESULT DDAPI DD_Surface_SetSpriteDisplayList(
|
|
LPDIRECTDRAWSURFACE lpDDDestSurface,
|
|
LPDDSPRITE *lplpDDSprite,
|
|
DWORD dwCount,
|
|
DWORD dwSize,
|
|
LPDIRECTDRAWSURFACE lpDDTargetSurface,
|
|
DWORD dwFlags)
|
|
{
|
|
|
|
/*
|
|
* Fixed-size buffer for containing clip region data
|
|
*/
|
|
struct
|
|
{
|
|
RGNDATAHEADER rdh;
|
|
RECT clipRect[6];
|
|
} myRgnBuffer;
|
|
|
|
DWORD rc;
|
|
DDHAL_SETSPRITEDISPLAYLISTDATA ssdld;
|
|
DDHAL_SETSPRITEDISPLAYLISTDATA *pHalData;
|
|
LPDDHAL_SETSPRITEDISPLAYLIST pfn;
|
|
LPDDRAWI_DDRAWSURFACE_INT this_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL this_lcl;
|
|
LPDDRAWI_DDRAWSURFACE_GBL this;
|
|
LPDDRAWI_DDRAWSURFACE_INT targ_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL targ_lcl;
|
|
LPDDRAWI_DDRAWSURFACE_GBL targ;
|
|
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
|
|
LPDDRAWI_DIRECTDRAW_GBL pdrv;
|
|
LPDIRECTDRAWCLIPPER pClipper;
|
|
DWORD dwDDPFDestFlags;
|
|
SPRITE_CAPS caps;
|
|
LPRGNDATA pRgn;
|
|
RECT rcDestSurf;
|
|
DWORD ifirst;
|
|
int i;
|
|
|
|
DDASSERT(sizeof(DDRGBA)==sizeof(DWORD)); // we rely on this
|
|
DDASSERT(sizeof(DDSPRITEI)==sizeof(DDSPRITE)); // and this
|
|
|
|
ENTER_BOTH();
|
|
|
|
DPF(2,A,"ENTERAPI: DD_Surface_SetSpriteDisplayList");
|
|
|
|
/*
|
|
* Validate parameters
|
|
*/
|
|
TRY
|
|
{
|
|
/*
|
|
* Validate destination surface.
|
|
*/
|
|
this_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDDestSurface;
|
|
|
|
if (!VALID_DIRECTDRAWSURFACE_PTR(this_int))
|
|
{
|
|
DPF_ERR("Invalid dest surface");
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
this_lcl = this_int->lpLcl;
|
|
this = this_lcl->lpGbl;
|
|
|
|
/*
|
|
* Check for lost dest surface.
|
|
*/
|
|
if (SURFACE_LOST(this_lcl))
|
|
{
|
|
DPF_ERR("Dest surface lost");
|
|
LEAVE_BOTH();
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
|
|
#if 0
|
|
if (!dwCount)
|
|
{
|
|
lplpDDSprite = NULL; // necessary?
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Perform initial validation of arguments.
|
|
*/
|
|
if (dwCount && !lplpDDSprite || // if count nonzero, is ptr valid?
|
|
dwSize != sizeof(DDSPRITE) || // structure size ok?
|
|
dwFlags & ~DDSSDL_VALID || // any bogus flag bits set?
|
|
dwFlags & DDSSDL_PAGEFLIP && dwFlags & DDSSDL_BLTSPRITES || // no flip if blt
|
|
!(dwFlags & (DDSSDL_OVERLAYSPRITES | DDSSDL_BLTSPRITES)) || // neither flag set?
|
|
!(~dwFlags & (DDSSDL_OVERLAYSPRITES | DDSSDL_BLTSPRITES))) // both flags set?
|
|
{
|
|
DPF_ERR("Invalid arguments") ;
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
/*
|
|
* The dest surface is not allowed to be palette-indexed.
|
|
*/
|
|
dwDDPFDestFlags = getPixelFormatFlags(this_lcl);
|
|
|
|
if (dwDDPFDestFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 |
|
|
DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8))
|
|
{
|
|
DPF_ERR( "Dest surface must not be palette-indexed" );
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDSURFACETYPE;
|
|
}
|
|
|
|
pdrv = this->lpDD;
|
|
pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
|
|
|
|
/*
|
|
* Is device busy?
|
|
*/
|
|
if (*(pdrv->lpwPDeviceFlags) & BUSY)
|
|
{
|
|
DPF(2, "BUSY");
|
|
LEAVE_BOTH();
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
|
|
/*
|
|
* Determine whether the sprites are to be overlayed or blitted.
|
|
*/
|
|
caps.bOverlay = !(dwFlags & DDSSDL_BLTSPRITES);
|
|
|
|
if (caps.bOverlay)
|
|
{
|
|
/*
|
|
* Dest surface for overlay sprite must be primary surface.
|
|
*/
|
|
if (!(this_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE))
|
|
{
|
|
DPF_ERR("Dest is not primary surface");
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS; // not primary surface
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* We do not allow blitting to an optimized surface.
|
|
*/
|
|
if (this_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED)
|
|
{
|
|
DPF_ERR("Can't blt optimized surfaces") ;
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Will this call flip the primary surface?
|
|
*/
|
|
if (!(dwFlags & DDSSDL_PAGEFLIP))
|
|
{
|
|
// no flip
|
|
targ_lcl = NULL;
|
|
}
|
|
else
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_INT next_int;
|
|
LPDDRAWI_DDRAWSURFACE_GBL_MORE targmore;
|
|
|
|
/*
|
|
* Yes, a page flip is requested. Make sure the destination
|
|
* surface is a front buffer and is flippable.
|
|
*/
|
|
if (~this_lcl->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_FLIP))
|
|
{
|
|
DPF_ERR("Dest surface is not flippable");
|
|
LEAVE_BOTH();
|
|
return DDERR_NOTFLIPPABLE;
|
|
}
|
|
if (this->dwUsageCount > 0)
|
|
{
|
|
DPF_ERR("Can't flip locked surface");
|
|
LEAVE_BOTH();
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
if (this_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE &&
|
|
pdrv->lpExclusiveOwner != pdrv_lcl)
|
|
{
|
|
DPF_ERR("Can't flip without exclusive access");
|
|
LEAVE_BOTH();
|
|
return DDERR_NOEXCLUSIVEMODE;
|
|
}
|
|
/*
|
|
* Get backbuffer surface attached to dest surface.
|
|
*/
|
|
next_int = FindAttachedFlip(this_int);
|
|
|
|
if (next_int == NULL)
|
|
{
|
|
DPF_ERR("No backbuffer surface to flip to");
|
|
LEAVE_BOTH();
|
|
return DDERR_NOTFLIPPABLE;
|
|
}
|
|
/*
|
|
* Validate flip override surface, if one is specified.
|
|
*/
|
|
targ_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDTargetSurface;
|
|
|
|
if (targ_int != NULL)
|
|
{
|
|
if (!VALID_DIRECTDRAWSURFACE_PTR(targ_int))
|
|
{
|
|
DPF_ERR("Invalid flip override surface");
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
targ_lcl = targ_int->lpLcl;
|
|
targ = targ_lcl->lpGbl;
|
|
|
|
/*
|
|
* Verify that the flip override surface is part of the destination
|
|
* surface's flipping chain. Note that next_int already points to
|
|
* the first buffer in the flipping chain.
|
|
*/
|
|
while (next_int != this_int && next_int->lpLcl != targ_lcl)
|
|
{
|
|
next_int = FindAttachedFlip(this_int);
|
|
}
|
|
|
|
if (next_int == this_int)
|
|
{
|
|
// failed to find override surface in flipping chain
|
|
DPF_ERR("Flip override surface not part of flipping chain");
|
|
LEAVE_BOTH();
|
|
return DDERR_NOTFLIPPABLE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* No flip override surface is specified so use
|
|
* next backbuffer as target flip surface.
|
|
*/
|
|
targ_int = next_int;
|
|
targ_lcl = targ_int->lpLcl;
|
|
targ = targ_lcl->lpGbl;
|
|
}
|
|
|
|
/*
|
|
* Make sure target flip surface is not lost or busy.
|
|
*/
|
|
if (SURFACE_LOST(targ_lcl))
|
|
{
|
|
DPF_ERR("Can't flip -- backbuffer surface is lost");
|
|
LEAVE_BOTH();
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
|
|
targmore = GET_LPDDRAWSURFACE_GBL_MORE(targ);
|
|
#if 0
|
|
if (targmore->hKernelSurface != 0)
|
|
{
|
|
DPF_ERR("Can't flip -- kernel mode is using surface");
|
|
LEAVE_BOTH();
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
#endif
|
|
/*
|
|
* Make sure front and back buffers are in same memory.
|
|
*/
|
|
if ((this_lcl->ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY |
|
|
DDSCAPS_VIDEOMEMORY)) !=
|
|
(targ_lcl->ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY |
|
|
DDSCAPS_VIDEOMEMORY)))
|
|
{
|
|
DPF_ERR("Can't flip between system/video memory surfaces");
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
} /* page flip */
|
|
|
|
/*
|
|
* Validate display list pointer lplpSpriteDisplayList.
|
|
*/
|
|
if ( IsBadWritePtr((LPVOID)lplpDDSprite,
|
|
(UINT)dwCount*sizeof(LPDDSPRITE)) )
|
|
{
|
|
DPF_ERR("Bad pointer to sprite display list");
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
/*
|
|
* Initialize structure containing caps bits for sprites.
|
|
*/
|
|
memset(&caps, 0, sizeof(SPRITE_CAPS));
|
|
caps.dwDestSurfCaps = this_lcl->ddsCaps.dwCaps; // dest surface caps
|
|
caps.bOverlay = dwFlags & DDSSDL_OVERLAYSPRITES; // TRUE if overlay sprites
|
|
|
|
/*
|
|
* Initialize status variables bNoHEL and bNoHAL. If bNoHEL is
|
|
* TRUE, this disqualifies the HEL from handling the driver call.
|
|
* If bNoHAL is TRUE, this disqualifies the hardware driver.
|
|
*/
|
|
caps.bNoHEL = dwFlags & (DDSSDL_HARDWAREONLY | DDSSDL_OVERLAYSPRITES);
|
|
caps.bNoHAL = FALSE;
|
|
|
|
/*
|
|
* A driver that specifies nonlocal video-memory caps that differ
|
|
* from its local video-memory caps is automatically disqualified
|
|
* because the currently specified nonlocal vidmem caps do not
|
|
* include alpha, filter, or transform caps. Should we fix this?
|
|
*/
|
|
if (caps.dwDestSurfCaps & DDSCAPS_NONLOCALVIDMEM &&
|
|
pdrv->ddCaps.dwCaps2 & DDCAPS2_NONLOCALVIDMEMCAPS)
|
|
{
|
|
caps.bNoHAL = TRUE;
|
|
}
|
|
|
|
/*
|
|
* The assumption here is that the display list can be handled by
|
|
* the display hardware only if the dest surface and all the
|
|
* sprites are in video memory. If one or more surfaces are in
|
|
* system memory, emulation is the only option. We check the
|
|
* dest surface just below. Later, we'll check each sprite in
|
|
* the list. (Will this assumption still be valid in the future?)
|
|
*/
|
|
if (this_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
caps.bNoHAL = TRUE;
|
|
|
|
if (caps.bNoHEL)
|
|
{
|
|
DPF_ERR("Hardware can't show sprites on dest surface in system memory");
|
|
LEAVE_BOTH();
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
DDASSERT(!(caps.bNoHEL && caps.bNoHAL));
|
|
|
|
/*
|
|
* Each iteration of the for-loop below validates the DDSPRITE
|
|
* structure for the next sprite in the display list.
|
|
*/
|
|
for (i = 0; i < (int)dwCount; ++i)
|
|
{
|
|
HRESULT ddrval = validateSprite(lplpDDSprite[i],
|
|
pdrv,
|
|
this_lcl,
|
|
&caps,
|
|
dwDDPFDestFlags);
|
|
|
|
if (ddrval != DD_OK)
|
|
{
|
|
DPF(1, "...failed at sprite display list index = %d", i);
|
|
LEAVE_BOTH();
|
|
return ddrval;
|
|
}
|
|
}
|
|
|
|
DDASSERT(!(caps.bNoHEL && caps.bNoHAL));
|
|
|
|
/*
|
|
* Will the sprites be blitted? If so, they will alter dest surface.
|
|
*/
|
|
if (dwFlags & DDSSDL_BLTSPRITES)
|
|
{
|
|
/*
|
|
* Remove any cached run-length-encoded data for the source surface.
|
|
*/
|
|
if (this_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
extern void FreeRleData(LPDDRAWI_DDRAWSURFACE_LCL); //in fasthel.c
|
|
|
|
FreeRleData(this_lcl);
|
|
}
|
|
|
|
BUMP_SURFACE_STAMP(this);
|
|
}
|
|
}
|
|
EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DPF_ERR("Exception encountered validating parameters");
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
/*
|
|
* Determine clipping region for destination surface.
|
|
*/
|
|
// GetRgnData() call needs clipper and width/height of dest surface.
|
|
pClipper = (LPDIRECTDRAWCLIPPER)this_lcl->lpSurfMore->lpDDIClipper;
|
|
SetRect(&rcDestSurf, 0, 0, this->wWidth, this->wHeight);
|
|
// We'll pass in a region buffer for GetRgnData() to use.
|
|
myRgnBuffer.rdh.dwSize = sizeof(RGNDATAHEADER);
|
|
myRgnBuffer.rdh.nRgnSize = sizeof(myRgnBuffer) - sizeof(RGNDATAHEADER);
|
|
pRgn = GetRgnData(pClipper, &rcDestSurf, pdrv, (LPRGNDATA)&myRgnBuffer);
|
|
if (pRgn == NULL)
|
|
{
|
|
DPF_ERR("Can't alloc memory for clipping region");
|
|
LEAVE_BOTH();
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
|
|
/*
|
|
* Set up the HAL callback data for the sprite display list. This
|
|
* data structure will be passed directly to the driver either if
|
|
* the sprites are blitted or if no other window or clipping region
|
|
* contains overlay sprites. Otherwise, the driver will receive a
|
|
* temporary display list constructed by updateMasterSpriteList()
|
|
* that contains all the overlay sprites in the master sprite list.
|
|
*/
|
|
//ssdld.SetSpriteDisplayList = pfn; // debug aid only -- no thunk
|
|
ssdld.lpDD = pdrv;
|
|
ssdld.lpDDSurface = this_lcl;
|
|
ssdld.lplpDDSprite = (LPDDSPRITEI*)lplpDDSprite;
|
|
ssdld.dwCount = dwCount;
|
|
ssdld.dwSize = dwSize;
|
|
ssdld.dwFlags = dwFlags & ~DDSSDL_WAIT;
|
|
ssdld.dwRectCnt = pRgn->rdh.nCount; // number of clip rects in region
|
|
ssdld.lpRect = (LPRECT)&pRgn->Buffer; // array of clip rects
|
|
ssdld.lpDDTargetSurface = targ_lcl;
|
|
|
|
/*
|
|
* The "master sprite list" keeps track of the overlay sprites in all
|
|
* the windows on a shared primary surface. (It also keeps track of
|
|
* the overlay sprites in all the clip regions of a full-screen app.)
|
|
* The master sprite list keeps a record of the active overlay sprites
|
|
* in each window (or clip region), as identified by its clipper object.
|
|
* Whenever any window updates its overlay sprites, the update is first
|
|
* recorded in the master sprite list. Next, a temporary display list
|
|
* containing all the overlay sprites in the master sprite list is passed
|
|
* to the driver. That way, the driver itself never has to keep track of
|
|
* more than one overlay-sprite display list at a time. The alternative
|
|
* would be for the driver itself to keep track of the overlay sprites
|
|
* for each window. We have chosen to keep the driver code simple by
|
|
* moving this bookkeeping into the DirectDraw runtime.
|
|
*/
|
|
pHalData = &ssdld;
|
|
#if 0
|
|
if (this_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) // debug only !!
|
|
#else
|
|
if (dwFlags & DDSSDL_OVERLAYSPRITES)
|
|
#endif
|
|
{
|
|
/*
|
|
* The new display list specifies overlay sprites, so we
|
|
* need to update the master sprite list.
|
|
*/
|
|
HRESULT ddrval = updateMasterSpriteList(lpDDDestSurface, &pHalData);
|
|
|
|
if (ddrval != DD_OK)
|
|
{
|
|
DPF_ERR( "Failed to update master sprite list" );
|
|
LEAVE_BOTH();
|
|
return ddrval;
|
|
}
|
|
}
|
|
|
|
TRY
|
|
{
|
|
/*
|
|
* Given the choice, we would prefer to use the hardware driver
|
|
* rather than software emulation to process this display list.
|
|
*/
|
|
if (!caps.bNoHAL)
|
|
{
|
|
/*
|
|
* Yes, we can use the hardware. Get pointer to HAL callback.
|
|
*/
|
|
pfn = pdrv_lcl->lpDDCB->HALDDMiscellaneous2.SetSpriteDisplayList;
|
|
|
|
if (!pfn)
|
|
{
|
|
caps.bNoHAL = TRUE; // no hardware driver is available
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Tell the driver to begin processing the sprite display
|
|
* list. We may have to wait if the driver is still busy
|
|
* with a previously requested drawing operation.
|
|
*/
|
|
do
|
|
{
|
|
DOHALCALL_NOWIN16(SetSpriteDisplayList, pfn, *pHalData, rc, 0); // caps.bNoHAL);
|
|
#ifdef WINNT
|
|
DDASSERT(! (rc == DDHAL_DRIVER_HANDLED && pHalData->ddRVal == DDERR_VISRGNCHANGED));
|
|
#endif
|
|
|
|
if (rc != DDHAL_DRIVER_HANDLED || pHalData->ddRVal != DDERR_WASSTILLDRAWING)
|
|
{
|
|
break; // driver's finished for better or worse...
|
|
}
|
|
DPF(4, "Waiting...");
|
|
|
|
} while (dwFlags & DDSSDL_WAIT);
|
|
|
|
if (rc != DDHAL_DRIVER_HANDLED || pHalData->ddRVal == DDERR_UNSUPPORTED)
|
|
{
|
|
caps.bNoHAL = TRUE; // hardware driver couldn't handle callback
|
|
}
|
|
else if (pHalData->ddRVal != DD_OK)
|
|
{
|
|
/*
|
|
* We want to just return with this error code instead
|
|
* of asking the HEL to process the display list.
|
|
*/
|
|
caps.bNoHEL = TRUE; // disqualify HEL routine
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If the hardware was unable to handle the display list, we may
|
|
* have to let the HEL process it for us.
|
|
*/
|
|
if (caps.bNoHAL && !caps.bNoHEL)
|
|
{
|
|
/*
|
|
* Have to use HEL support. Get pointer to HEL emulation routine.
|
|
*/
|
|
pfn = pdrv_lcl->lpDDCB->HELDDMiscellaneous2.SetSpriteDisplayList;
|
|
|
|
DDASSERT(pfn != NULL);
|
|
|
|
DOHALCALL_NOWIN16(SetSpriteDisplayList, pfn, *pHalData, rc, 0); // caps.bNoHAL);
|
|
}
|
|
}
|
|
EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DPF_ERR("Exception encountered during sprite rendering");
|
|
LEAVE_BOTH();
|
|
return DDERR_EXCEPTION;
|
|
}
|
|
|
|
/*
|
|
* If the previous GetRgnData() call had to dynamically alloc
|
|
* a region buffer, we need to remember to free it now.
|
|
*/
|
|
if (pRgn != (LPRGNDATA)&myRgnBuffer)
|
|
{
|
|
MemFree(pRgn);
|
|
}
|
|
|
|
// Was there any driver support at all for this call?
|
|
if (caps.bNoHAL && caps.bNoHEL)
|
|
{
|
|
DPF_ERR("No driver support for this call");
|
|
LEAVE_BOTH();
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
|
|
// Did driver handle callback?
|
|
if (rc != DDHAL_DRIVER_HANDLED)
|
|
{
|
|
DPF_ERR("Driver wouldn't handle callback");
|
|
LEAVE_BOTH();
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
|
|
// Return now if driver handled callback without error.
|
|
if (pHalData->ddRVal == DD_OK || pHalData->ddRVal == DDERR_WASSTILLDRAWING)
|
|
{
|
|
LEAVE_BOTH();
|
|
return pHalData->ddRVal;
|
|
}
|
|
|
|
/*
|
|
* An error prevented the driver from showing all the sprites
|
|
* in the list. Which sprites did get shown?
|
|
*/
|
|
if (pHalData->dwCount == dwCount)
|
|
{
|
|
// None of the sprites got shown
|
|
DPF(1, "Driver failed to show any sprites in display list");
|
|
LEAVE_BOTH();
|
|
return pHalData->ddRVal;
|
|
}
|
|
DPF(1, "Driver failed sprite at disp list index #%d", pHalData->dwCount);
|
|
|
|
DDASSERT(pHalData->dwCount < dwCount);
|
|
|
|
if (pHalData->dwFlags & DDSSDL_BACKTOFRONT)
|
|
{
|
|
// Driver showed sprites from (dwCount-1) down to (pHalData->dwCount+1).
|
|
ifirst = dwCount - 1; // driver started at last sprite in list
|
|
}
|
|
else
|
|
{
|
|
// Driver showed sprites from 0 up to (pHalData->dwCount-1).
|
|
ifirst = 0; // driver started at first sprite in list
|
|
}
|
|
DPF(1, "Driver started with sprite at disp list index #%d", ifirst);
|
|
|
|
LEAVE_BOTH();
|
|
|
|
return pHalData->ddRVal;
|
|
|
|
} /* DD_Surface_SetSpriteDisplayList */
|
|
|