517 lines
14 KiB
C++
517 lines
14 KiB
C++
/*******************************************************************************
|
|
* DXSurfB.cpp *
|
|
*------------*
|
|
* Description:
|
|
* This module contains the CDXBaseSurface implementaion.
|
|
*-------------------------------------------------------------------------------
|
|
* Created By: RAL Date: 02/12/1998
|
|
* Copyright (C) 1998 Microsoft Corporation
|
|
* All Rights Reserved
|
|
*
|
|
*-------------------------------------------------------------------------------
|
|
* Revisions:
|
|
*
|
|
*******************************************************************************/
|
|
//--- Additional includes
|
|
#include "stdafx.h"
|
|
#include <DXTrans.h>
|
|
#include "DXSurfB.h"
|
|
#include "new.h"
|
|
|
|
CDXBaseSurface::CDXBaseSurface() :
|
|
m_ulLocks(0),
|
|
m_ulThreadsWaiting(0),
|
|
m_Height(0),
|
|
m_Width(0),
|
|
m_pFreePtr(NULL),
|
|
m_dwStatusFlags(DXSURF_READONLY),
|
|
m_dwAppData(0)
|
|
{
|
|
m_hSemaphore = CreateSemaphore(NULL, 0, MAXLONG, NULL);
|
|
m_ulNumInRequired = m_ulMaxInputs = 0;
|
|
}
|
|
|
|
HRESULT CDXBaseSurface::FinalConstruct()
|
|
{
|
|
return m_hSemaphore ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
void CDXBaseSurface::FinalRelease()
|
|
{
|
|
while (m_pFreePtr)
|
|
{
|
|
CDXBaseARGBPtr *pNext = m_pFreePtr->m_pNext;
|
|
DeleteARGBPointer(m_pFreePtr);
|
|
m_pFreePtr = pNext;
|
|
}
|
|
if (m_hSemaphore)
|
|
{
|
|
CloseHandle(m_hSemaphore);
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CDXBaseSurface::GetGenerationId(ULONG *pGenerationId)
|
|
{
|
|
if (DXIsBadWritePtr(pGenerationId, sizeof(*pGenerationId)))
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
Lock();
|
|
OnUpdateGenerationId();
|
|
*pGenerationId = m_dwGenerationId;
|
|
Unlock();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CDXBaseSurface::IncrementGenerationId(BOOL /*bRefresh */)
|
|
{
|
|
Lock();
|
|
m_dwGenerationId++;
|
|
Unlock();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDXBaseSurface::GetObjectSize(ULONG *pcbSize)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (DXIsBadWritePtr(pcbSize, sizeof(*pcbSize)))
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
Lock();
|
|
*pcbSize = OnGetObjectSize();
|
|
Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CDXBaseSurface::MapBoundsIn2Out
|
|
(const DXBNDS *pInBounds, ULONG ulNumInBnds, ULONG /*ulOutIndex*/, DXBNDS *pOutBounds)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (DXIsBadWritePtr(pOutBounds, sizeof(*pOutBounds)))
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
Lock();
|
|
new(pOutBounds) CDXDBnds(m_Width, m_Height);
|
|
Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CDXBaseSurface::InitSurface(IUnknown *pDirectDraw,
|
|
const DDSURFACEDESC * pDDSurfaceDesc,
|
|
const GUID * pFormatId,
|
|
const DXBNDS *pBounds,
|
|
DWORD dwFlags)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (pDDSurfaceDesc || DXIsBadReadPtr(pBounds, sizeof(*pBounds)) || pBounds->eType != DXBT_DISCRETE)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
_EnterCritWith0PtrLocks();
|
|
if (m_Width)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
|
|
}
|
|
else
|
|
{
|
|
CDXDBnds *pbnds = (CDXDBnds *)pBounds;
|
|
hr = OnSetSize(pbnds->Width(), pbnds->Height());
|
|
}
|
|
Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDXBaseSurface::GetPixelFormat(GUID *pFormat, DXSAMPLEFORMATENUM *pSampleFormatEnum)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (DX_IS_BAD_OPTIONAL_WRITE_PTR(pFormat) ||
|
|
DX_IS_BAD_OPTIONAL_WRITE_PTR(pSampleFormatEnum))
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
if (pFormat) *pFormat = SurfaceCLSID();
|
|
if (pSampleFormatEnum) *pSampleFormatEnum = SampleFormatEnum();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CDXBaseSurface::GetBounds(DXBNDS* pBounds)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (DXIsBadWritePtr(pBounds, sizeof(*pBounds)))
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
Lock();
|
|
new(pBounds) CDXDBnds(m_Width, m_Height);
|
|
Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CDXBaseSurface::GetStatusFlags(DWORD* pdwStatusFlags)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (DXIsBadWritePtr(pdwStatusFlags, sizeof(*pdwStatusFlags)))
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
Lock();
|
|
*pdwStatusFlags = m_dwStatusFlags;
|
|
Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CDXBaseSurface::SetStatusFlags(DWORD dwStatusFlags )
|
|
{
|
|
_EnterCritWith0PtrLocks();
|
|
// BUGBUG -- Think about this
|
|
m_dwStatusFlags = dwStatusFlags | DXSURF_READONLY;
|
|
m_dwGenerationId++;
|
|
Unlock();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CDXBaseSurface::GetDirectDrawSurface(REFIID riid, void **ppSurface)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CDXBaseSurface::LockSurface(const DXBNDS *pBounds, ULONG ulTimeOut,
|
|
DWORD dwFlags, REFIID riid, void **ppPointer,
|
|
DWORD * pGenerationId)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL bMPLockOnly = m_bInMultiThreadWorkProc;
|
|
|
|
if (!bMPLockOnly) Lock();
|
|
m_MPWorkProcCrit.Lock();
|
|
|
|
if (m_Width == 0)
|
|
{
|
|
hr = E_FAIL; // BUGBUG -- What code??
|
|
}
|
|
else
|
|
{
|
|
RECT r;
|
|
r.top = r.left = 0;
|
|
r.right = m_Width;
|
|
r.bottom = m_Height;
|
|
if (pBounds)
|
|
{
|
|
if (pBounds->eType != DXBT_DISCRETE)
|
|
{
|
|
hr = DXTERR_INVALID_BOUNDS;
|
|
}
|
|
else
|
|
{
|
|
((CDXDBnds *)pBounds)->GetXYRect(r);
|
|
if (r.top < 0 || r.left < 0 || (ULONG)r.right > m_Width || (ULONG)r.bottom > m_Height || r.bottom <= r.top || r.right <= r.left)
|
|
{
|
|
hr = DXTERR_INVALID_BOUNDS;
|
|
}
|
|
}
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CDXBaseARGBPtr * pPtr = m_pFreePtr;
|
|
if (pPtr)
|
|
{
|
|
m_pFreePtr = pPtr->m_pNext;
|
|
}
|
|
else
|
|
{
|
|
hr = CreateARGBPointer(this, &pPtr);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pPtr->InitFromLock(r, ulTimeOut, dwFlags, riid, ppPointer);
|
|
if (pGenerationId)
|
|
{
|
|
if (DXIsBadWritePtr(pGenerationId, sizeof(*pGenerationId)))
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
*pGenerationId = m_dwGenerationId;
|
|
}
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_ulLocks++;
|
|
}
|
|
else
|
|
{
|
|
pPtr->m_pNext = m_pFreePtr;
|
|
m_pFreePtr = pPtr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_MPWorkProcCrit.Unlock();
|
|
if (!bMPLockOnly) Unlock();
|
|
return hr;
|
|
}
|
|
|
|
void CDXBaseSurface::_InternalUnlock(CDXBaseARGBPtr *pPtrToUnlock)
|
|
{
|
|
BOOL bMPLockOnly = m_bInMultiThreadWorkProc;
|
|
|
|
if (!bMPLockOnly) Lock();
|
|
m_MPWorkProcCrit.Lock();
|
|
pPtrToUnlock->m_pNext = m_pFreePtr;
|
|
m_pFreePtr = pPtrToUnlock;
|
|
m_ulLocks--;
|
|
if ((m_ulLocks == 0) && m_ulThreadsWaiting)
|
|
{
|
|
ReleaseSemaphore(m_hSemaphore, m_ulThreadsWaiting, NULL);
|
|
m_ulThreadsWaiting = 0;
|
|
}
|
|
m_MPWorkProcCrit.Unlock();
|
|
if (!bMPLockOnly) Unlock();
|
|
|
|
IUnknown *punkOuter = GetControllingUnknown();
|
|
punkOuter->Release(); // Release pointer's reference to us
|
|
// which could kill us! Don't touch
|
|
// any members after this point.
|
|
}
|
|
|
|
//
|
|
// Picking interface needs to test the appropriate point for hit testing
|
|
//
|
|
HRESULT CDXBaseSurface::OnSurfacePick(const CDXDBnds & OutPoint, ULONG & ulInputIndex, CDXDVec & InVec)
|
|
{
|
|
HRESULT hr;
|
|
IDXARGBReadPtr *pPtr;
|
|
hr = LockSurface(&OutPoint, m_ulLockTimeOut, DXLOCKF_READ,
|
|
IID_IDXARGBReadPtr, (void **)&pPtr, NULL);
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
DXPMSAMPLE val;
|
|
pPtr->UnpackPremult(&val, 1, FALSE);
|
|
pPtr->Release();
|
|
hr = val.Alpha ? DXT_S_HITOUTPUT : S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (hr == DXTERR_INVALID_BOUNDS) hr = S_FALSE;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* RegisterSurface (STATIC member function)
|
|
*-----------------------------------------------------------------------------
|
|
* Description:
|
|
*-----------------------------------------------------------------------------
|
|
* Created By: RAL Date: 12/10/97
|
|
*-----------------------------------------------------------------------------
|
|
* Parameters:
|
|
*****************************************************************************/
|
|
HRESULT CDXBaseSurface::
|
|
RegisterSurface(REFCLSID rcid, int ResourceId, ULONG cCatImpl, const CATID * pCatImpl,
|
|
ULONG cCatReq, const CATID * pCatReq, BOOL bRegister)
|
|
{
|
|
HRESULT hr = bRegister ? _Module.UpdateRegistryFromResource(ResourceId, bRegister) : S_OK;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CComPtr<ICatRegister> pCatRegister;
|
|
HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_ALL, IID_ICatRegister, (void **)&pCatRegister);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (bRegister)
|
|
{
|
|
hr = pCatRegister->RegisterClassImplCategories(rcid, cCatImpl, (CATID *)pCatImpl);
|
|
if (SUCCEEDED(hr) && cCatReq && pCatReq) {
|
|
hr = pCatRegister->RegisterClassReqCategories(rcid, cCatReq, (CATID *)pCatReq);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCatRegister->UnRegisterClassImplCategories(rcid, cCatImpl, (CATID *)pCatImpl);
|
|
if (cCatReq && pCatReq)
|
|
{
|
|
pCatRegister->UnRegisterClassReqCategories(rcid, cCatReq, (CATID *)pCatReq);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ((!bRegister) && SUCCEEDED(hr))
|
|
{
|
|
_Module.UpdateRegistryFromResource(ResourceId, bRegister);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// CDXBaseARGBPtr
|
|
//
|
|
STDMETHODIMP CDXBaseARGBPtr::QueryInterface(REFIID riid, void ** ppv)
|
|
{
|
|
if (IsEqualGUID(riid, IID_IUnknown) ||
|
|
IsEqualGUID(riid, IID_IDXARGBReadPtr))
|
|
{
|
|
*ppv = (IDXARGBReadPtr *)this;
|
|
m_ulRefCount++;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
|
|
ULONG STDMETHODCALLTYPE CDXBaseARGBPtr::AddRef()
|
|
{
|
|
return ++m_ulRefCount;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CDXBaseARGBPtr::Release()
|
|
{
|
|
--m_ulRefCount;
|
|
ULONG c = m_ulRefCount;
|
|
if (c == 0)
|
|
{
|
|
m_pSurface->_InternalUnlock(this); // Don't touch members after this call.
|
|
}
|
|
return c;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CDXBaseARGBPtr::GetSurface(REFIID riid, void **ppSurface)
|
|
{
|
|
return m_pSurface->GetControllingUnknown()->QueryInterface(riid, ppSurface);
|
|
}
|
|
|
|
|
|
DXSAMPLEFORMATENUM STDMETHODCALLTYPE CDXBaseARGBPtr::GetNativeType(DXNATIVETYPEINFO *pInfo)
|
|
{
|
|
if (pInfo)
|
|
{
|
|
memset(pInfo, 0, sizeof(pInfo));
|
|
}
|
|
return m_pSurface->SampleFormatEnum();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE CDXBaseARGBPtr::Move(long cSamples)
|
|
{
|
|
m_FillInfo.x += cSamples;
|
|
//--- Moving one column past the end is okay
|
|
_ASSERT((long)m_FillInfo.x <= m_LockedRect.right);
|
|
}
|
|
|
|
void STDMETHODCALLTYPE CDXBaseARGBPtr::MoveToRow(ULONG y)
|
|
{
|
|
m_FillInfo.x = m_LockedRect.left;
|
|
m_FillInfo.y = y + m_LockedRect.top;
|
|
_ASSERT((long)m_FillInfo.y < m_LockedRect.bottom);
|
|
}
|
|
|
|
void STDMETHODCALLTYPE CDXBaseARGBPtr::MoveToXY(ULONG x, ULONG y)
|
|
{
|
|
m_FillInfo.x = x + m_LockedRect.left;
|
|
m_FillInfo.y = y + m_LockedRect.top;
|
|
//--- Moving one column past the end is okay
|
|
_ASSERT((long)m_FillInfo.x <= m_LockedRect.right);
|
|
_ASSERT((long)m_FillInfo.y < m_LockedRect.bottom);
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CDXBaseARGBPtr::MoveAndGetRunInfo(ULONG Row, const DXRUNINFO ** ppInfo)
|
|
{
|
|
m_FillInfo.x = m_LockedRect.left;
|
|
m_FillInfo.y = Row + m_LockedRect.top;
|
|
_ASSERT((long)m_FillInfo.y < m_LockedRect.bottom);
|
|
*ppInfo = &m_RunInfo;
|
|
return 1;
|
|
}
|
|
|
|
DXSAMPLE *STDMETHODCALLTYPE CDXBaseARGBPtr::Unpack(DXSAMPLE *pSamples, ULONG cSamples, BOOL bMove)
|
|
{
|
|
m_FillInfo.pSamples = pSamples;
|
|
m_FillInfo.cSamples = cSamples;
|
|
m_FillInfo.bPremult = false;
|
|
FillSamples(m_FillInfo);
|
|
if (bMove) m_FillInfo.x += cSamples;
|
|
return pSamples;
|
|
}
|
|
|
|
DXPMSAMPLE *STDMETHODCALLTYPE CDXBaseARGBPtr::UnpackPremult(DXPMSAMPLE *pSamples, ULONG cSamples, BOOL bMove)
|
|
{
|
|
m_FillInfo.pSamples = pSamples;
|
|
m_FillInfo.cSamples = cSamples;
|
|
m_FillInfo.bPremult = true;
|
|
FillSamples(m_FillInfo);
|
|
if (bMove) m_FillInfo.x += cSamples;
|
|
return pSamples;
|
|
}
|
|
|
|
void STDMETHODCALLTYPE CDXBaseARGBPtr::UnpackRect(const DXPACKEDRECTDESC *pDesc)
|
|
{
|
|
DXPtrFillInfo FillInfo;
|
|
FillInfo.pSamples = pDesc->pSamples;
|
|
FillInfo.cSamples = pDesc->rect.right - pDesc->rect.left;
|
|
FillInfo.x = pDesc->rect.left + m_LockedRect.left;
|
|
FillInfo.bPremult = pDesc->bPremult;
|
|
ULONG YLimit = pDesc->rect.bottom + m_LockedRect.top;
|
|
for (FillInfo.y = pDesc->rect.top + m_LockedRect.top;
|
|
FillInfo.y < YLimit;
|
|
FillInfo.y++)
|
|
{
|
|
FillSamples(FillInfo);
|
|
FillInfo.pSamples += FillInfo.cSamples;
|
|
}
|
|
}
|
|
|
|
HRESULT CDXBaseARGBPtr::InitFromLock(const RECT & rect, ULONG /*ulTimeOut*/, DWORD dwLockFlags, REFIID riid, void ** ppv)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (dwLockFlags & DXLOCKF_READWRITE)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
m_LockedRect = rect;
|
|
m_RunInfo.Count = rect.right - rect.left;
|
|
if (m_pSurface->SampleFormatEnum() & DXPF_TRANSPARENCY)
|
|
{
|
|
m_RunInfo.Type = DXRUNTYPE_UNKNOWN;
|
|
}
|
|
else
|
|
{
|
|
m_RunInfo.Type = DXRUNTYPE_OPAQUE;
|
|
}
|
|
m_FillInfo.x = rect.left;
|
|
m_FillInfo.y = rect.top;
|
|
hr = QueryInterface(riid, ppv);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_pSurface->GetControllingUnknown()->AddRef();
|
|
}
|
|
}
|
|
return hr;
|
|
}
|