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.
1401 lines
45 KiB
1401 lines
45 KiB
/*==========================================================================;
|
|
*
|
|
* Copyright (C) 1994-1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: ddstream.cpp
|
|
* Content: DirectDraw surface file I/O
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 30-sep-97 jeffno Original implementation
|
|
*
|
|
***************************************************************************/
|
|
|
|
extern "C"
|
|
{
|
|
#include "ddrawpr.h"
|
|
}
|
|
|
|
#include <ImgUtil.H>
|
|
#include "decoder.h"
|
|
|
|
/*
|
|
* This routine takes a source surface freshly loaded from some file, and transfers
|
|
* the bits to some target surface. Palette will be transferred also, if set.
|
|
* dwFlags are as defined for CreateSurfaceFromFile.
|
|
*/
|
|
HRESULT TransferBitsToTarget(
|
|
LPDIRECTDRAWSURFACE lpDDSource,
|
|
LPDIRECTDRAWSURFACE4 lpDDSTarget,
|
|
LPDDSURFACEDESC2 pDDSD,
|
|
DWORD dwFlags)
|
|
{
|
|
HRESULT hr =DD_OK;
|
|
DDSURFACEDESC ddsd;
|
|
RECT rDest;
|
|
LPDIRECTDRAWSURFACE4 lpDDSource4;
|
|
|
|
/*
|
|
* We need to transfer a palette to the target surface if required.
|
|
* Don't do it if the app doesn't want a palette. Don't do it if there's
|
|
* no palette in the working surface.
|
|
*/
|
|
if ( (dwFlags & DDLS_IGNOREPALETTE) == 0)
|
|
{
|
|
LPDIRECTDRAWPALETTE pPal = NULL;
|
|
hr = lpDDSource->GetPalette(&pPal);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
/*
|
|
* If the target surface isn't palettized, this will fail.
|
|
* That's OK.
|
|
*/
|
|
lpDDSTarget->SetPalette((LPDIRECTDRAWPALETTE2)pPal);
|
|
pPal->Release();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we aren't stretching or we're maintaining aspect ratio, then there's the possibility
|
|
* of some of the target surface's pixels not being filled. Fill them with
|
|
* phys color zero.
|
|
* I threw in bilinear as well, because the current definition samples the target
|
|
* even when full stretch.
|
|
*/
|
|
if ( (dwFlags & (DDLS_MAINTAINASPECTRATIO|DDLS_BILINEARFILTER)) || ((dwFlags & DDLS_STRETCHTOFIT)==0) )
|
|
{
|
|
DDBLTFX ddbltfx;
|
|
ddbltfx.dwSize = sizeof(ddbltfx);
|
|
ddbltfx.dwFillColor = 0;
|
|
/*
|
|
* Ignore the error code. The nicest thing is to keep going anyway
|
|
*/
|
|
lpDDSTarget->Blt(NULL,NULL,NULL,DDBLT_COLORFILL,&ddbltfx);
|
|
}
|
|
|
|
/*
|
|
* Note that we always shrink the image to fit if necessary.
|
|
* We never take the smaller subrect of the source when the passed-in
|
|
* size is smaller than the image
|
|
*/
|
|
|
|
/*
|
|
* Set dest rect to the size of the image
|
|
* Calling a v1 surface, so better pass proper size.
|
|
*/
|
|
ddsd.dwSize =sizeof(DDSURFACEDESC);
|
|
hr = lpDDSource->GetSurfaceDesc((LPDDSURFACEDESC)&ddsd);
|
|
DDASSERT(SUCCEEDED(hr));
|
|
SetRect(&rDest,0,0,ddsd.dwWidth,ddsd.dwHeight);
|
|
|
|
if (dwFlags & DDLS_STRETCHTOFIT)
|
|
{
|
|
/*
|
|
* Override the dest rect to the size passed in
|
|
*/
|
|
SetRect(&rDest,0,0,pDDSD->dwWidth,pDDSD->dwHeight);
|
|
if (dwFlags & DDLS_MAINTAINASPECTRATIO)
|
|
{
|
|
/*
|
|
* Back off if necessary to maintain aspect ratio.
|
|
* This calculates the dest width we need to maintain AR
|
|
*/
|
|
DWORD dwProperWidth = ddsd.dwWidth*pDDSD->dwHeight/ddsd.dwHeight;
|
|
if (dwProperWidth > pDDSD->dwWidth)
|
|
{
|
|
SetRect(&rDest,0,0,pDDSD->dwWidth,ddsd.dwHeight*pDDSD->dwWidth/ddsd.dwWidth);
|
|
}
|
|
else if (dwProperWidth < pDDSD->dwWidth)
|
|
{
|
|
SetRect(&rDest,0,0,dwProperWidth,pDDSD->dwHeight);
|
|
}
|
|
}
|
|
|
|
DDASSERT(rDest.right <= (int) pDDSD->dwWidth);
|
|
DDASSERT(rDest.bottom <= (int) pDDSD->dwHeight);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* If we're shrinking, we'll just stretch anyway. The alternative is to take
|
|
* a smaller central subrect of the source image. That seems kinda useless.
|
|
*/
|
|
if (pDDSD)
|
|
{
|
|
if (pDDSD->dwWidth < ddsd.dwWidth)
|
|
{
|
|
rDest.left=0;
|
|
rDest.right = pDDSD->dwWidth;
|
|
}
|
|
if (pDDSD->dwHeight < ddsd.dwHeight)
|
|
{
|
|
rDest.top=0;
|
|
rDest.bottom = pDDSD->dwHeight;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Add space above/below to center the image in the dest
|
|
*/
|
|
if (dwFlags & DDLS_CENTER)
|
|
{
|
|
OffsetRect(&rDest, (pDDSD->dwWidth - rDest.right)/2, (pDDSD->dwHeight - rDest.bottom)/2);
|
|
}
|
|
|
|
hr = lpDDSource->QueryInterface(IID_IDirectDrawSurface4, (void**) &lpDDSource4);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = lpDDSTarget->AlphaBlt(
|
|
&rDest,
|
|
lpDDSource4,
|
|
NULL,
|
|
((dwFlags & DDLS_BILINEARFILTER)?DDABLT_BILINEARFILTER:0)|DDABLT_WAIT,
|
|
NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
/*
|
|
* ATTENTION: Sort of. At the moment, AlphaBlt refuses to blt to a palette-indexed surface.
|
|
* We'll just try blt as a backup
|
|
*/
|
|
hr = lpDDSTarget->Blt(
|
|
&rDest,
|
|
lpDDSource4,
|
|
NULL,
|
|
DDBLT_WAIT,
|
|
NULL);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DPF_ERR("Could not blt from temporary surface to target surface!");
|
|
}
|
|
|
|
lpDDSource4->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CreateOrLoadSurfaceFromStream( LPDIRECTDRAW4 lpDD, IStream *pSource, LPDDSURFACEDESC2 pDDSD, DWORD dwFlags, LPDIRECTDRAWSURFACE4 * ppSurface, IUnknown * pUnkOuter)
|
|
{
|
|
|
|
LPDDRAWI_DIRECTDRAW_INT this_int;
|
|
// validate arguments
|
|
TRY
|
|
{
|
|
if( !VALID_PTR_PTR(ppSurface ) )
|
|
{
|
|
DPF_ERR("You must supply a valid surface pointer");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
*ppSurface = NULL;
|
|
|
|
this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
|
|
if( !VALID_DIRECTDRAW_PTR( this_int ) )
|
|
{
|
|
DPF_ERR("Bad DirectDraw pointer");
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
if( !pSource )
|
|
{
|
|
DPF_ERR("You must supply a valid stream pointer");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
/*
|
|
* Validate flags
|
|
*/
|
|
if (dwFlags & ~DDLS_VALID)
|
|
{
|
|
DPF_ERR("Invalid flags");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if (dwFlags & ~DDLS_VALID)
|
|
{
|
|
DPF_ERR("Invalid flags");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
//ATTENTION: DDLS_MERGEPALETTE isn't implemented. Implement it when the palette 2 interface goes in.
|
|
if ( (dwFlags & (DDLS_IGNOREPALETTE|DDLS_MERGEPALETTE)) == (DDLS_IGNOREPALETTE|DDLS_MERGEPALETTE) )
|
|
{
|
|
DPF_ERR("Can only specify one of DDLS_IGNOREPALETTE or DDLS_MERGEPALETTE");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if ( (dwFlags & DDLS_STRETCHTOFIT) || (dwFlags & DDLS_CENTER) )
|
|
{
|
|
if (!pDDSD)
|
|
{
|
|
DPF_ERR("Can't specify DDLS_STRETCHTOFIT or DDLS_CENTER without a DDSURFACEDESC2 with valid dwWidth and dwHeight");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if ( ( (pDDSD->dwFlags & (DDSD_WIDTH|DDSD_HEIGHT)) == 0) || !pDDSD->dwWidth || !pDDSD->dwHeight )
|
|
{
|
|
DPF_ERR("Can't specify DDLS_STRETCHTOFIT or DDLS_CENTER without a DDSURFACEDESC2 with valid dwWidth and dwHeight");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
|
|
if (! (dwFlags & DDLS_STRETCHTOFIT) )
|
|
{
|
|
if (dwFlags & (DDLS_BILINEARFILTER|DDLS_MAINTAINASPECTRATIO))
|
|
{
|
|
DPF_ERR("DDLS_STRETCHTOFIT required for DDLS_BILINEARFILTER or DDLS_MAINTAINASPECTRATIO");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
|
|
HRESULT hr = DD_OK;
|
|
FILTERINFO ImgInfo;
|
|
CImageDecodeEventSink EventSink;
|
|
|
|
ZeroMemory(&ImgInfo, sizeof(ImgInfo));
|
|
/*
|
|
* Default to device's bit depth
|
|
* This is no longer necessary. We always create a staging surface in the filter's
|
|
* desired format.
|
|
*/
|
|
//ImgInfo._colorMode = this_int->lpLcl->lpGbl->vmiData.ddpfDisplay.dwRGBBitCount;
|
|
|
|
EventSink.Init(&ImgInfo);
|
|
typedef HRESULT (*funcptr)(IStream*, IMapMIMEToCLSID*, IImageDecodeEventSink*);
|
|
funcptr pfnDecodeImage;
|
|
//EventSink->AddRef();
|
|
EventSink.SetDDraw( lpDD );
|
|
|
|
HINSTANCE hLibInst = LoadLibrary( "ImgUtil.dll" );
|
|
if( hLibInst )
|
|
{
|
|
pfnDecodeImage = (funcptr) GetProcAddress(hLibInst, "DecodeImage");
|
|
if( pfnDecodeImage )
|
|
{
|
|
hr = (*pfnDecodeImage)( pSource, NULL, (IImageDecodeEventSink *)&EventSink );
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR( "GetProcAddress failure for DecodeImage in ImgUtil.dll" );
|
|
hr = DDERR_UNSUPPORTED;
|
|
}
|
|
FreeLibrary( hLibInst );
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR( "LoadLibrary failure on ImgUtil.dll" );
|
|
hr = DDERR_UNSUPPORTED;
|
|
}
|
|
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
LPDIRECTDRAWSURFACE lpDDS = EventSink.m_pFilter->m_pDDrawSurface;
|
|
|
|
if (lpDDS)
|
|
{
|
|
DDSURFACEDESC2 ddsd;
|
|
DDSURFACEDESC ddsdWorking;
|
|
|
|
ZeroMemory(&ddsdWorking,sizeof(ddsdWorking));
|
|
ddsdWorking.dwSize = sizeof(ddsdWorking);
|
|
|
|
ZeroMemory(&ddsd,sizeof(ddsd));
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
|
|
/*
|
|
* The decode succeeded, so now marshal the bits into the requested surface type
|
|
*/
|
|
if (pDDSD)
|
|
{
|
|
/*
|
|
* App cares about at least some of the parameters of the target surface.
|
|
* We'll take what they give us and potentially fill in some more.
|
|
*/
|
|
ddsd = *pDDSD;
|
|
}
|
|
|
|
/*
|
|
* We may need some data from the original loaded surface.
|
|
* Ignore the return code. It's better just to carry on.
|
|
*/
|
|
hr = lpDDS->GetSurfaceDesc(&ddsdWorking);
|
|
|
|
if ( (ddsd.dwFlags & (DDSD_WIDTH|DDSD_HEIGHT)) == 0 )
|
|
{
|
|
/*
|
|
* App doesn't care what size the surface is, so we'll setup
|
|
* the size for them.
|
|
*/
|
|
ddsd.dwFlags |= DDSD_WIDTH|DDSD_HEIGHT;
|
|
ddsd.dwWidth = ddsdWorking.dwWidth;
|
|
ddsd.dwHeight = ddsdWorking.dwHeight;
|
|
}
|
|
|
|
if ( (ddsd.dwFlags & DDSD_CAPS) == 0)
|
|
{
|
|
/*
|
|
* App doesn't care about surface caps. We'll give them offscreen plain
|
|
*/
|
|
ddsd.dwFlags |= DDSD_CAPS;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
|
ddsd.ddsCaps.dwCaps2 = 0;
|
|
ddsd.ddsCaps.dwCaps3 = 0;
|
|
ddsd.ddsCaps.dwCaps4 = 0;
|
|
}
|
|
|
|
if ( (ddsd.dwFlags & DDSD_PIXELFORMAT) == 0)
|
|
{
|
|
/*
|
|
* If the app didn't specify a pixel format, then we will return
|
|
* the original pixel format as decoded by the decode filter.
|
|
* This should be a close approximation of the format of the original
|
|
* file. Note that this stipulation could mean that the CreateSurface
|
|
* will dump the surface in sysmem. It's good for our routine to
|
|
* have the same semantics as CreateSurface.
|
|
*/
|
|
ddsd.dwFlags |= DDSD_PIXELFORMAT;
|
|
ddsd.ddpfPixelFormat = ddsdWorking.ddpfPixelFormat;
|
|
}
|
|
|
|
/*
|
|
* Could we avoid creating a target surface and doing the blt altogether?
|
|
* It wouldn't really buy much. If the app didn't specify a memory type, then
|
|
* we probe to see if we can create a vidmem version by calling createsurface.
|
|
* If we get a vidmem back, then we copy the bits and use it. If we get a sysmem
|
|
* back then we could optimize that case by not doing the blt to get the
|
|
* data into the target surface and returning the working surface directly.
|
|
* One tiny disadvantage would be that the target surface would be explicit
|
|
* sysmem, whereas the normal createsurface semantics would make that surface
|
|
* an implicit sysmem surface.
|
|
*/
|
|
|
|
/*
|
|
* We don't do the create surface if a surface is passed in (as denoted
|
|
* by *ppSurface being non-null)
|
|
*/
|
|
if(SUCCEEDED(hr) && (NULL == (*ppSurface)) )
|
|
{
|
|
hr = lpDD->CreateSurface(&ddsd, ppSurface, pUnkOuter);
|
|
}
|
|
|
|
/*
|
|
* Now blt the working surface to whatever the target was supposed to be...
|
|
* Note this routine may transfer a reference to a palette as well.
|
|
*/
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = TransferBitsToTarget(lpDDS, *ppSurface, pDDSD, dwFlags);
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Create surface failed!");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Decode returned a NULL ddraw surface, even tho DecodeImage returned ok
|
|
*/
|
|
hr = DDERR_INVALIDSTREAM;
|
|
}
|
|
}
|
|
|
|
// pEventSink->Release();
|
|
|
|
return hr;
|
|
} /* DD_CreateSurfaceFromFile */
|
|
|
|
extern "C" HRESULT DDAPI DD_CreateSurfaceFromStream(
|
|
LPDIRECTDRAW4 lpDD,
|
|
IStream *pSource,
|
|
LPDDSURFACEDESC2 pDDSD,
|
|
DWORD dwFlags,
|
|
LPDIRECTDRAWSURFACE4 * ppSurface,
|
|
IUnknown * pUnkOuter)
|
|
{
|
|
*ppSurface = 0;
|
|
return CreateOrLoadSurfaceFromStream(lpDD, pSource, pDDSD, dwFlags, ppSurface, pUnkOuter);
|
|
}
|
|
|
|
extern "C" HRESULT DDAPI DD_CreateSurfaceFromFile( LPDIRECTDRAW4 lpDD, BSTR DisplayName, LPDDSURFACEDESC2 pDDSD, DWORD dwFlags, LPDIRECTDRAWSURFACE4 * ppSurface, IUnknown * pUnkOuter)
|
|
{
|
|
lpDD;
|
|
pDDSD;
|
|
pUnkOuter;
|
|
|
|
// validate arguments
|
|
if( !DisplayName || !ppSurface )
|
|
{
|
|
DPF_ERR("You must supply a valid filename and surface pointer");
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (FAILED(CoInitialize(NULL)))
|
|
{
|
|
DPF_ERR("Failed CoInitialize");
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
|
|
IMoniker *pmk;
|
|
IBindCtx *pbctx;
|
|
IStream *pStream;
|
|
HRESULT hr = CreateURLMoniker(NULL, DisplayName, &pmk);
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
hr = CreateBindCtx(0, &pbctx);
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
hr = pmk->BindToStorage(pbctx, NULL, IID_IStream, (void **)&pStream);
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
hr = DD_CreateSurfaceFromStream( lpDD, pStream, pDDSD, dwFlags, ppSurface ,pUnkOuter );
|
|
pStream->Release();
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Could not BindToStorage");
|
|
if (hr == INET_E_UNKNOWN_PROTOCOL)
|
|
DPF_ERR("Fully qualified path name is required");
|
|
if (hr == INET_E_RESOURCE_NOT_FOUND)
|
|
DPF_ERR("Resource not found. Fully qualified path name is required");
|
|
}
|
|
pbctx->Release();
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Could not CreateBindCtx");
|
|
}
|
|
pmk->Release();
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Could not CreateURLMoniker");
|
|
}
|
|
|
|
|
|
return hr;
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
/*
|
|
* Persistence interfaces
|
|
* These methods read and write streams of the following form:
|
|
*
|
|
* Element Description
|
|
* -------------------------------------------------------------------------------------------------
|
|
* Type Name
|
|
*
|
|
* GUID tag GUID_DirectDrawSurfaceStream. Tags the stream as a surface stream
|
|
* DWORD dwWidth Width in pixels of the image data
|
|
* DWORD dwHeight Height in pixels of the image data
|
|
* DDPIXELFORMAT Format Format of image data
|
|
* DWORD dwPaletteCaps Palette caps. Zero if no palette.
|
|
* PALETTESTREAM PaletteData This field is only present if the dwPaletteCaps field is non-zero
|
|
* GUID CompressionFormat This field is only present if one of the DDPF_OPT flags is specified in Format
|
|
* DWORD dwDataSize Number of bytes that follow
|
|
* BYTE[] SurfaceData dwDataSize bytes of surface data
|
|
* PRIVATEDATA PrivateSurfaceData
|
|
*
|
|
*
|
|
* The PALETTESTREAM stream element has the following format:
|
|
*
|
|
* Element Description
|
|
* -------------------------------------------------------------------------------------------------
|
|
* Type Name
|
|
* GUID tag GUID_DirectDrawPaletteeStream. Tags the stream as a palette stream
|
|
* DWORD dwPaletteFlags Palette flags made up of DDPCAPS bits.
|
|
* PALETTEENTRY[] PaletteEntries The number of palette entries specified by the flags in dwPaletteFlags.
|
|
* PRIVATEDATA PrivatePaletteData Private palette data.
|
|
*
|
|
*
|
|
* The PRIVATEDATA stream element has the following format:
|
|
*
|
|
* Element Description
|
|
* -------------------------------------------------------------------------------------------------
|
|
* Type Name
|
|
*
|
|
* DWORD dwPrivateDataCount The number of private data blocks which follow
|
|
* GUID GUIDTag Tag for this block of private data, as specified by IDDS4:SetClientData
|
|
* DWORD dwPrivateSize Number of bytes of private data in this block
|
|
* BYTE[] PrivateData dwPrivateSize bytes of private data
|
|
*
|
|
* Note private data that are of pointer type (i.e. point to a user-allocated data block) will
|
|
* NOT be saved by these methods.
|
|
*
|
|
*/
|
|
|
|
template<class Object> HRESULT InternalReadPrivateData(
|
|
IStream * pStrm,
|
|
Object * lpObject)
|
|
{
|
|
HRESULT ddrval;
|
|
DWORD dwCount;
|
|
|
|
ddrval = pStrm->Read((void*) & dwCount, sizeof(DWORD), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream read failed on private data count");
|
|
return ddrval;
|
|
}
|
|
|
|
for(;dwCount;dwCount--)
|
|
{
|
|
GUID guid;
|
|
DWORD cbData;
|
|
LPVOID pData;
|
|
|
|
ddrval = pStrm->Read((void*) & guid, sizeof(guid), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream read failed on private data GUID");
|
|
return ddrval;
|
|
}
|
|
|
|
ddrval = pStrm->Read((void*) & cbData, sizeof(cbData), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream read failed on private data GUID");
|
|
return ddrval;
|
|
}
|
|
|
|
pData = MemAlloc(cbData);
|
|
if (pData)
|
|
{
|
|
ddrval = pStrm->Read((void*) pData, cbData, NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream read failed on private data GUID");
|
|
return ddrval;
|
|
}
|
|
|
|
ddrval = lpObject->SetPrivateData(guid, pData, cbData, 0);
|
|
|
|
MemFree(pData);
|
|
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Could not set private data");
|
|
return ddrval;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Couln't alloc enough space for private data");
|
|
ddrval = DDERR_OUTOFMEMORY;
|
|
return ddrval;
|
|
}
|
|
}
|
|
return ddrval;
|
|
}
|
|
|
|
HRESULT myWriteClassStm(IStream * pStrm, LPGUID pGUID)
|
|
{
|
|
return pStrm->Write(pGUID, sizeof(*pGUID),NULL);
|
|
}
|
|
|
|
HRESULT myReadClassStm(IStream * pStrm, LPGUID pGUID)
|
|
{
|
|
return pStrm->Read(pGUID, sizeof(*pGUID),NULL);
|
|
}
|
|
|
|
/*
|
|
* Be sure to call ENTER_DDRAW before and LEAVE_DDRAW after
|
|
* calling this function!
|
|
*/
|
|
HRESULT InternalWritePrivateData(
|
|
IStream * pStrm,
|
|
LPPRIVATEDATANODE pPrivateDataHead)
|
|
{
|
|
HRESULT ddrval;
|
|
DWORD dwCount = 0;
|
|
LPPRIVATEDATANODE pPrivateData = pPrivateDataHead;
|
|
|
|
while(1)
|
|
{
|
|
while(pPrivateData)
|
|
{
|
|
if (pPrivateData->dwFlags == 0)
|
|
{
|
|
dwCount++;
|
|
}
|
|
pPrivateData = pPrivateData->pNext;
|
|
}
|
|
|
|
ddrval = pStrm->Write((void*) & dwCount, sizeof(dwCount), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream write failed on count of private data");
|
|
break;
|
|
}
|
|
|
|
pPrivateData = pPrivateDataHead;
|
|
while(pPrivateData)
|
|
{
|
|
if (pPrivateData->dwFlags == 0)
|
|
{
|
|
ddrval = myWriteClassStm(pStrm, &(pPrivateData->guid));
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
ddrval = pStrm->Write((void*) &(pPrivateData->cbData), sizeof(DWORD), NULL);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
ddrval = pStrm->Write((void*) pPrivateData->pData, pPrivateData->cbData, NULL);
|
|
if (FAILED(ddrval))
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
pPrivateData = pPrivateData->pNext;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return ddrval;
|
|
}
|
|
|
|
extern "C" HRESULT DDAPI DD_Surface_Persist_GetClassID(LPDIRECTDRAWSURFACE lpDDS, CLSID * pClassID)
|
|
{
|
|
TRY
|
|
{
|
|
memcpy(pClassID, & GUID_DirectDrawSurfaceStream, sizeof(*pClassID));
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered copying GUID" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
return DD_OK;
|
|
}
|
|
|
|
extern "C" HRESULT DDAPI DD_Surface_PStream_IsDirty(LPDIRECTDRAWSURFACE lpDDS)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_INT this_int;
|
|
LPDDRAWI_DDRAWSURFACE_GBL_MORE this_more;
|
|
|
|
ENTER_DDRAW();
|
|
|
|
TRY
|
|
{
|
|
this_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDS;
|
|
if( !VALID_DIRECTDRAWSURFACE_PTR( this_int ) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
this_more = GET_LPDDRAWSURFACE_GBL_MORE(this_int->lpLcl->lpGbl);
|
|
|
|
if ( (this_more->dwSaveStamp == 0 ) ||
|
|
(this_more->dwContentsStamp != this_more->dwSaveStamp) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return S_OK;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered checking dirty" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
LEAVE_DDRAW();
|
|
return S_FALSE;
|
|
}
|
|
|
|
extern "C" HRESULT DDAPI DD_Surface_PStream_Load(LPDIRECTDRAWSURFACE lpDDS, IStream * pStrm)
|
|
{
|
|
DDSURFACEDESC2 ddsd;
|
|
HRESULT ddrval;
|
|
LPDDRAWI_DDRAWSURFACE_INT this_int;
|
|
LPDIRECTDRAWSURFACE4 lpDDS1 = NULL;
|
|
|
|
if (!VALID_PTR(pStrm,sizeof(*pStrm)))
|
|
{
|
|
DPF_ERR("Bad stream pointer");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
this_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDS;
|
|
if( !VALID_DIRECTDRAWSURFACE_PTR( this_int ) )
|
|
{
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
/*
|
|
* DO THE QI for DDOPTSURF HERE
|
|
* and appropriate loading
|
|
*/
|
|
|
|
ddrval = lpDDS->QueryInterface(IID_IDirectDrawSurface4, (void**) & lpDDS1);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
ZeroMemory(&ddsd,sizeof(ddsd));
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
|
|
ddrval = lpDDS1->Lock(NULL, &ddsd,DDLOCK_WAIT,NULL);
|
|
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
if (ddsd.ddpfPixelFormat.dwFlags & (DDPF_FOURCC) )
|
|
{
|
|
DPF_ERR("The surface isn't streamable. Bad pixel format");
|
|
ddrval = DDERR_INVALIDPIXELFORMAT;
|
|
}
|
|
else
|
|
{
|
|
while(SUCCEEDED(ddrval)) //a fake try-except while
|
|
{
|
|
DWORD y;
|
|
DWORD dwStreamWidth,dwStreamHeight;
|
|
DWORD dwPalCaps;
|
|
DDPIXELFORMAT ddpfStream;
|
|
CLSID clsid;
|
|
|
|
/*
|
|
* First attempt to read stream format GUID
|
|
*/
|
|
ddrval = myReadClassStm(pStrm, & clsid);
|
|
|
|
//don't bother to check return code, since the following test will fail in that case
|
|
if (!IsEqualGUID(clsid, GUID_DirectDrawSurfaceStream))
|
|
{
|
|
DPF_ERR("The stream does not contain a directdraw surface stream");
|
|
ddrval = DDERR_INVALIDSTREAM;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Get image format from stream
|
|
*/
|
|
ddrval = pStrm->Read((void*) & dwStreamWidth, sizeof(dwStreamWidth), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream read failed on width");
|
|
break;
|
|
}
|
|
|
|
ddrval = pStrm->Read((void*) & dwStreamHeight, sizeof(dwStreamHeight), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream read failed on height");
|
|
break;
|
|
}
|
|
|
|
ddrval = pStrm->Read((void*) & ddpfStream, sizeof(ddpfStream), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream read failed on pixel format");
|
|
break;
|
|
}
|
|
|
|
if (!doPixelFormatsMatch(&ddpfStream, &ddsd.ddpfPixelFormat))
|
|
{
|
|
DPF_ERR("Stream pixel format does not match that of surface!");
|
|
break;
|
|
}
|
|
|
|
ddrval = pStrm->Read((void*) & dwPalCaps, sizeof(dwPalCaps), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream read failed on palette caps");
|
|
break;
|
|
}
|
|
|
|
|
|
/*
|
|
* If a palette exists, then either create one or grab the palette from the surface
|
|
* and try to stream its data in too.
|
|
*/
|
|
if (dwPalCaps)
|
|
{
|
|
LPDIRECTDRAWPALETTE2 lpDDPal;
|
|
ddrval = lpDDS1->GetPalette(& lpDDPal);
|
|
if (ddrval == DDERR_NOPALETTEATTACHED)
|
|
{
|
|
PALETTEENTRY pe[256]; //just a dummy
|
|
ddrval = DD_CreatePalette(
|
|
(IDirectDraw*)(this_int->lpLcl->lpGbl) ,
|
|
dwPalCaps,
|
|
pe,
|
|
(LPDIRECTDRAWPALETTE*)&lpDDPal,
|
|
NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Failed to create palette for surface ");
|
|
break;
|
|
}
|
|
ddrval = lpDDS1->SetPalette(lpDDPal);
|
|
if (FAILED(ddrval))
|
|
{
|
|
lpDDPal->Release();
|
|
DPF_ERR("Could not set palette into surface ");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
/*
|
|
* Stream palette from stream
|
|
*/
|
|
ddrval = DD_Palette_PStream_Load( (LPDIRECTDRAWPALETTE) lpDDPal,pStrm);
|
|
lpDDPal->Release();
|
|
|
|
if (FAILED(ddrval))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Here we check for DDPF_OPT... and load a compression GUID if necessary
|
|
if (ddpfStream.dwFlags & (DDPF_OPTCOMPRESSED|DDPF_OPTREORDERED) )
|
|
{
|
|
ddrval = myReadClassStm(pStrm, & clsid);
|
|
|
|
}
|
|
else
|
|
//Surface is not compressed, so lock and read....
|
|
*/
|
|
|
|
/*
|
|
* And finally read the data
|
|
*/
|
|
for (y=0;y<ddsd.dwHeight;y++)
|
|
{
|
|
ddrval = pStrm->Read((void*) ((DWORD) ddsd.lpSurface + y*ddsd.lPitch),
|
|
(ddsd.dwWidth * ddsd.ddpfPixelFormat.dwRGBBitCount / 8),
|
|
NULL);
|
|
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream read failed");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Read private data
|
|
*/
|
|
ddrval = InternalReadPrivateData(pStrm, lpDDS1);
|
|
break;
|
|
}
|
|
} // OK pixel format
|
|
lpDDS1->Unlock(NULL);
|
|
}//lock succeeded
|
|
else
|
|
{
|
|
DPF_ERR("Could not lock surface");
|
|
}
|
|
|
|
lpDDS1->Release();
|
|
}// QIed for ddsurf ok
|
|
else
|
|
{
|
|
DPF_ERR("Bad surface object... can't QI itself for IDirectDrawSurface...");
|
|
}
|
|
|
|
return ddrval;
|
|
}
|
|
|
|
extern "C" HRESULT DDAPI DD_Surface_PStream_Save(LPDIRECTDRAWSURFACE lpDDS, IStream * pStrm, BOOL bClearDirty)
|
|
{
|
|
DDSURFACEDESC2 ddsd;
|
|
HRESULT ddrval;
|
|
LPDDRAWI_DDRAWSURFACE_INT this_int;
|
|
LPDIRECTDRAWSURFACE4 lpDDS1 = NULL;
|
|
|
|
if (!VALID_PTR(pStrm,sizeof(*pStrm)))
|
|
{
|
|
DPF_ERR("Bad stream pointer");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
this_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDS;
|
|
if( !VALID_DIRECTDRAWSURFACE_PTR( this_int ) )
|
|
{
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
/*
|
|
* DO THE QI for DDOPTSURF HERE
|
|
*/
|
|
|
|
ddrval = lpDDS->QueryInterface(IID_IDirectDrawSurface4, (void**) & lpDDS1);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
ZeroMemory(&ddsd,sizeof(ddsd));
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
|
|
ddrval = lpDDS1->Lock(NULL,&ddsd,DDLOCK_WAIT,NULL);
|
|
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
if (ddsd.ddpfPixelFormat.dwFlags & (DDPF_FOURCC) )
|
|
{
|
|
DPF_ERR("The surface isn't streamable. Bad pixel format");
|
|
ddrval = DDERR_INVALIDPIXELFORMAT;
|
|
}
|
|
else
|
|
{
|
|
while(SUCCEEDED(ddrval)) //a fake try-except while
|
|
{
|
|
LPDIRECTDRAWPALETTE2 lpDDPal;
|
|
DWORD y,dwWritten;
|
|
|
|
/*
|
|
* First attempt to read stream format GUID
|
|
*/
|
|
ddrval = myWriteClassStm(pStrm, (LPGUID) & GUID_DirectDrawSurfaceStream);
|
|
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Failed to write stream ID ");
|
|
ddrval = DDERR_INVALIDSTREAM;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Get image format from stream
|
|
*/
|
|
ddrval = pStrm->Write((void*) & ddsd.dwWidth, sizeof(DWORD), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream write failed on width");
|
|
break;
|
|
}
|
|
|
|
ddrval = pStrm->Write((void*) & ddsd.dwHeight, sizeof(DWORD), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream write failed on Height");
|
|
break;
|
|
}
|
|
|
|
ddrval = pStrm->Write((void*) & ddsd.ddpfPixelFormat, sizeof(ddsd.ddpfPixelFormat), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream write failed on width");
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If a palette exists, then write it out
|
|
*/
|
|
ddrval = lpDDS1->GetPalette(&lpDDPal);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
ddrval = lpDDPal->GetCaps(&dwWritten);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
ddrval = pStrm->Write((void*) & dwWritten, sizeof(dwWritten), NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream write failed on palette caps");
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Stream palette from stream
|
|
*/
|
|
ddrval = DD_Palette_PStream_Save((LPDIRECTDRAWPALETTE)lpDDPal,pStrm,bClearDirty);
|
|
if (FAILED(ddrval))
|
|
{
|
|
lpDDPal->Release();
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Could not get palette caps");
|
|
lpDDPal->Release();
|
|
break;
|
|
}
|
|
|
|
lpDDPal->Release();
|
|
|
|
}
|
|
else
|
|
{
|
|
dwWritten = 0;
|
|
|
|
ddrval = pStrm->Write((void*) & dwWritten, sizeof(dwWritten),NULL);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream write failed on palette caps");
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* Here we check for DDPF_OPT... and load a compression GUID if necessary
|
|
if (ddpfStream.dwFlags & (DDPF_OPTCOMPRESSED|DDPF_OPTREORDERED) )
|
|
{
|
|
ddrval = myReadClassStm(pStrm, & clsid);
|
|
|
|
}
|
|
else
|
|
//Surface is not compressed, so lock and read....
|
|
*/
|
|
|
|
/*
|
|
* And finally write the data
|
|
*/
|
|
for (y=0;y<ddsd.dwHeight;y++)
|
|
{
|
|
ddrval = pStrm->Write((void*) ((DWORD) ddsd.lpSurface + y*ddsd.lPitch),
|
|
(ddsd.dwWidth * ddsd.ddpfPixelFormat.dwRGBBitCount / 8),
|
|
NULL);
|
|
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Stream write failed");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Write out private data
|
|
*/
|
|
ENTER_DDRAW();
|
|
ddrval = InternalWritePrivateData(pStrm,
|
|
this_int->lpLcl->lpSurfMore->pPrivateDataHead);
|
|
LEAVE_DDRAW();
|
|
break;
|
|
}
|
|
} // OK pixel format
|
|
lpDDS1->Unlock(NULL);
|
|
}//lock succeeded
|
|
else
|
|
{
|
|
DPF_ERR("Could not lock surface");
|
|
}
|
|
|
|
lpDDS1->Release();
|
|
}// QIed for ddsurf ok
|
|
else
|
|
{
|
|
DPF_ERR("Bad surface object... can't QI itself for IDirectDrawSurface...");
|
|
}
|
|
|
|
if (SUCCEEDED(ddrval) && bClearDirty)
|
|
{
|
|
ENTER_DDRAW();
|
|
GET_LPDDRAWSURFACE_GBL_MORE(this_int->lpLcl->lpGbl)->dwSaveStamp =
|
|
GET_LPDDRAWSURFACE_GBL_MORE(this_int->lpLcl->lpGbl)->dwContentsStamp ;
|
|
LEAVE_DDRAW();
|
|
}
|
|
|
|
return ddrval;
|
|
}
|
|
|
|
/*
|
|
* How to calculate the size of a streamable object without really trying.
|
|
* You make a dummy IStream interface with only one valid method: Write.
|
|
* When Write is called you count the bytes and return OK. As long as the
|
|
* client (i.e. our surface and palette IPersistStream interfaces) call
|
|
* nothing but Write, it should work. Since the total is part of the fake
|
|
* stream object which is on the stack, this is thread-safe too.
|
|
*/
|
|
|
|
LPVOID CheatStreamCallbacks[3+11];
|
|
typedef struct
|
|
{
|
|
LPVOID * lpVtbl;
|
|
DWORD dwTotal;
|
|
} SUPERCHEATSTREAM;
|
|
|
|
HRESULT __stdcall SuperMegaCheater(SUPERCHEATSTREAM * pCheater, LPVOID pBuffer, ULONG dwSize, ULONG * pWritten)
|
|
{
|
|
pCheater->dwTotal += dwSize;
|
|
return S_OK;
|
|
}
|
|
|
|
extern "C" HRESULT DDAPI DD_PStream_GetSizeMax(IPersistStream * lpSurfOrPalette, ULARGE_INTEGER * pMax)
|
|
{
|
|
HRESULT ddrval = DD_OK;
|
|
SUPERCHEATSTREAM SuperCheat;
|
|
|
|
if (!VALID_PTR(pMax,sizeof(ULARGE_INTEGER)))
|
|
{
|
|
DPF_ERR("Bad stream pointer");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
SuperCheat.lpVtbl = CheatStreamCallbacks;
|
|
CheatStreamCallbacks[4] = (LPVOID)SuperMegaCheater;
|
|
SuperCheat.dwTotal = 0;
|
|
|
|
lpSurfOrPalette->Save((IStream*) & SuperCheat, FALSE);
|
|
|
|
pMax->LowPart = SuperCheat.dwTotal;
|
|
pMax->HighPart = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
extern "C" HRESULT DDAPI DD_Palette_PStream_IsDirty(LPDIRECTDRAWPALETTE lpDDP)
|
|
{
|
|
LPDDRAWI_DDRAWPALETTE_INT this_int;
|
|
LPDDRAWI_DDRAWPALETTE_GBL this_gbl;
|
|
|
|
ENTER_DDRAW();
|
|
|
|
TRY
|
|
{
|
|
this_int = (LPDDRAWI_DDRAWPALETTE_INT) lpDDP;
|
|
if( !VALID_DIRECTDRAWPALETTE_PTR( this_int ) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
this_gbl = this_int->lpLcl->lpGbl;
|
|
|
|
if ( (this_gbl->dwSaveStamp == 0 ) ||
|
|
(this_gbl->dwContentsStamp != this_gbl->dwSaveStamp) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return S_OK;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered checking dirty" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
LEAVE_DDRAW();
|
|
return S_FALSE;
|
|
}
|
|
|
|
extern "C" HRESULT DDAPI DD_Palette_Persist_GetClassID(LPDIRECTDRAWPALETTE lpDDP, CLSID * pClassID)
|
|
{
|
|
TRY
|
|
{
|
|
memcpy(pClassID, & GUID_DirectDrawPaletteStream, sizeof(*pClassID));
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered copying GUID" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
return DD_OK;
|
|
}
|
|
|
|
extern "C" HRESULT DDAPI DD_Palette_PStream_Load(LPDIRECTDRAWPALETTE lpStream, IStream * pStrm)
|
|
{
|
|
PALETTEENTRY pe[256];
|
|
HRESULT ddrval;
|
|
DWORD dwCaps, dwStreamCaps;
|
|
DWORD dwSize;
|
|
DWORD dwNumEntries;
|
|
LPDDRAWI_DDRAWPALETTE_INT this_int;
|
|
GUID g;
|
|
LPDIRECTDRAWPALETTE2 lpDDP;
|
|
|
|
this_int = (LPDDRAWI_DDRAWPALETTE_INT) lpStream;
|
|
if( !VALID_DIRECTDRAWPALETTE_PTR( this_int ) )
|
|
{
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
ddrval = lpStream->QueryInterface( IID_IDirectDrawPalette2, (void**)& lpDDP);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Couldn't QI stream for palette");
|
|
return ddrval;
|
|
}
|
|
|
|
ddrval = lpDDP->GetCaps(&dwCaps);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
dwNumEntries = FLAGS_TO_SIZE(SIZE_PCAPS_TO_FLAGS(dwCaps));
|
|
dwSize = dwNumEntries;
|
|
if ((dwCaps & DDPCAPS_8BITENTRIES) == 0)
|
|
{
|
|
//the color table is really palettee entries
|
|
dwSize *=sizeof(PALETTEENTRY);
|
|
}
|
|
//if it weren 8 bit entries, then dwSize would already be the size of the color table
|
|
|
|
ddrval = pStrm->Read((LPVOID) &g, sizeof(GUID_DirectDrawPaletteStream),NULL);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
if (IsEqualGUID(g, GUID_DirectDrawPaletteStream))
|
|
{
|
|
ddrval = pStrm->Read((LPVOID) &dwStreamCaps, sizeof(DWORD),NULL);
|
|
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
if (dwCaps == dwStreamCaps)
|
|
{
|
|
|
|
ddrval = pStrm->Read((LPVOID) pe, dwSize,NULL);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
ddrval = lpDDP->SetEntries(0,0,dwNumEntries,pe);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
/*
|
|
* Read private data
|
|
*/
|
|
ddrval = InternalReadPrivateData(pStrm, lpDDP);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Couldn't read private data");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Couldn't set palette entries");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Couldn't read palette entries");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Palette stream caps don't match palette object's caps");
|
|
ddrval = DDERR_INVALIDSTREAM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Couldn't read palette caps");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Stream doesn't contain a ddraw palette stream tag");
|
|
ddrval = DDERR_INVALIDSTREAM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Couldn't read palette stream tag");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Couldn't get palette caps");
|
|
}
|
|
lpDDP->Release();
|
|
|
|
return ddrval;
|
|
}
|
|
|
|
extern "C" HRESULT DDAPI DD_Palette_PStream_Save(LPDIRECTDRAWPALETTE lpStream, IStream * pStrm, BOOL bClearDirty)
|
|
{
|
|
PALETTEENTRY pe[256];
|
|
HRESULT ddrval;
|
|
DWORD dwCaps;
|
|
DWORD dwSize;
|
|
LPDDRAWI_DDRAWPALETTE_INT this_int;
|
|
LPDIRECTDRAWPALETTE lpDDP;
|
|
|
|
this_int = (LPDDRAWI_DDRAWPALETTE_INT) lpStream;
|
|
if( !VALID_DIRECTDRAWPALETTE_PTR( this_int ) )
|
|
{
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
ddrval = lpStream->QueryInterface(IID_IDirectDrawPalette, (void**) &lpDDP);
|
|
if (FAILED(ddrval))
|
|
{
|
|
DPF_ERR("Couldn't QI stream for palette");
|
|
return ddrval;
|
|
}
|
|
|
|
ddrval = lpDDP->GetCaps(&dwCaps);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
dwSize = FLAGS_TO_SIZE(SIZE_PCAPS_TO_FLAGS(dwCaps));
|
|
ddrval = lpDDP->GetEntries(0,0,dwSize,pe);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
if ((dwCaps & DDPCAPS_8BITENTRIES) == 0)
|
|
{
|
|
//the color table is really palettee entries
|
|
dwSize *=sizeof(PALETTEENTRY);
|
|
}
|
|
//if it weren 8 bit entries, then dwSize would already be the size of the color table
|
|
|
|
ddrval = pStrm->Write((LPVOID) &GUID_DirectDrawPaletteStream, sizeof(GUID_DirectDrawPaletteStream),NULL);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
ddrval = pStrm->Write((LPVOID) &dwCaps, sizeof(DWORD),NULL);
|
|
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
ddrval = pStrm->Write((LPVOID) pe, dwSize,NULL);
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
ENTER_DDRAW();
|
|
ddrval = InternalWritePrivateData(pStrm,
|
|
this_int->lpLcl->pPrivateDataHead);
|
|
LEAVE_DDRAW();
|
|
|
|
if (SUCCEEDED(ddrval))
|
|
{
|
|
if (bClearDirty)
|
|
{
|
|
ENTER_DDRAW();
|
|
(this_int->lpLcl->lpGbl)->dwSaveStamp = (this_int->lpLcl->lpGbl)->dwContentsStamp ;
|
|
LEAVE_DDRAW();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Couldn't write palette private data");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Couldn't write palette entries");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Couldn't write palette caps");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Couldn't write palette stream tag");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("COuldn't get palette entries");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Couldn't get palette caps");
|
|
}
|
|
lpDDP->Release();
|
|
|
|
return ddrval;
|
|
}
|