#include "pch.h" ////////////////////////////////////////////////////////////////////////////// // // Surface Modes // ////////////////////////////////////////////////////////////////////////////// enum SurfaceMode { SurfaceModeDD, SurfaceModeLocked }; ////////////////////////////////////////////////////////////////////////////// // // VideoSurface // ////////////////////////////////////////////////////////////////////////////// class DDSurfaceImpl : public DDSurface { public: ////////////////////////////////////////////////////////////////////////////// // // Types // ////////////////////////////////////////////////////////////////////////////// class SurfaceData { public: int m_id; TRef m_ppf; TRef m_pdds; TRef m_pd3dtexture; }; ////////////////////////////////////////////////////////////////////////////// // // Members // ////////////////////////////////////////////////////////////////////////////// TRef m_pengine; TRef m_pdddevice; TRef m_pddsZBuffer; WinPoint m_size; WinPoint m_sizeSurface; SurfaceType m_stype; DDSDescription m_ddsdLocked; BYTE* m_pbits; int m_pitch; Color m_colorKey; TRef m_ppalette; Color m_colorText; bool m_bTextureSize; bool m_bColorKey; bool m_bSharedMemory; // // Mip-Mapped levels // SurfaceData m_data; TVector m_datas; // // Converted detail levels // SurfaceData m_dataConverted; TVector m_datasConverted; // // Surface invalidation and modes // SurfaceMode m_mode; ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void CalculateSurfaceSize() { m_sizeSurface = m_size; if (m_size.X() < 1) { ZAssert(m_size.X() == 0); m_sizeSurface.SetX(1); } if (m_size.Y() < 1) { ZAssert(m_size.Y() == 0); m_sizeSurface.SetY(1); } } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void Initialize() { CalculateSurfaceSize(); m_bTextureSize = m_sizeSurface.Y() == (int)NextPowerOf2((DWORD)m_sizeSurface.Y()) && m_sizeSurface.X() == (int)NextPowerOf2((DWORD)m_sizeSurface.X()); m_bColorKey = false; m_colorKey = Color(0, 0, 0); m_data.m_id = 0; m_mode = SurfaceModeDD; m_pbits = NULL; } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// void FinishConstruction() { // // Set the palette if there is one // if (m_ppalette) { m_data.m_pdds->SetPalette(m_ppalette->GetDDPal()); } // // Get a texture handle if needed // if (m_bTextureSize && !m_stype.Test(SurfaceTypeVideo())) { DDCall(m_data.m_pdds->QueryInterface(IID_IDirect3DTextureX, (void**)&(m_data.m_pd3dtexture))); } } ////////////////////////////////////////////////////////////////////////////// // // Create a video memory surface // ////////////////////////////////////////////////////////////////////////////// DDSurfaceImpl( DDDevice* pdddevice, SurfaceType stype, PixelFormat* ppf, PrivatePalette* ppalette, const WinPoint& size ) : m_pdddevice(pdddevice), m_pengine(pdddevice->GetEngine()), m_stype(stype), m_ppalette(ppalette), m_size(size), m_bSharedMemory(false) { m_data.m_ppf = ppf; Initialize(); // // Figure out the DD caps // DWORD caps = DDSCAPS_VIDEOMEMORY; if (Is3D()) { caps |= DDSCAPS_3DDEVICE; } else { if (m_bTextureSize) { caps |= DDSCAPS_TEXTURE; } else { caps |= DDSCAPS_OFFSCREENPLAIN; } } // // Create the surface // m_data.m_pdds = m_pdddevice->CreateSurface(size, caps, ppf, true); // // Was there enough memory to allocate the surface? // if (m_data.m_pdds != NULL) { // // Get the pitch // DDSDescription ddsd; DDCall(m_data.m_pdds->GetSurfaceDesc(&ddsd)); m_pitch = ddsd.lPitch; // // Do any other common construction tasks // FinishConstruction(); } } ////////////////////////////////////////////////////////////////////////////// // // Wrap an previously created DirectDraw surface // ////////////////////////////////////////////////////////////////////////////// DDSurfaceImpl( DDDevice* pdddevice, IDirectDrawSurfaceX* pdds, IDirectDrawSurfaceX* pddsZBuffer, PixelFormat* ppf, PrivatePalette* ppalette, SurfaceType stype ) : m_pdddevice(pdddevice), m_pengine(pdddevice->GetEngine()), m_pddsZBuffer(pddsZBuffer), m_ppalette(ppalette), m_stype(stype | SurfaceType2D()), m_bSharedMemory(false) { DDSDescription ddsd; DDCall(pdds->GetSurfaceDesc(&ddsd)); m_data.m_pdds = pdds; m_data.m_ppf = ppf; m_size = WinPoint(ddsd.XSize(), ddsd.YSize()); m_pitch = ddsd.Pitch(); Initialize(); } ////////////////////////////////////////////////////////////////////////////// // // Create a surface from a binary representation // ////////////////////////////////////////////////////////////////////////////// DDSurfaceImpl( DDDevice* pdddevice, SurfaceType stype, PixelFormat* ppf, PrivatePalette* ppalette, const WinPoint& size, int pitch, BYTE* pbits ) : m_pdddevice(pdddevice), m_pengine(pdddevice->GetEngine()), m_stype(stype), m_ppalette(ppalette), m_size(size) { // // Is the memory writable? // MEMORY_BASIC_INFORMATION meminfo; ZVerify(VirtualQuery(pbits, &meminfo, sizeof(meminfo)) == sizeof(meminfo)); m_bSharedMemory = ( ( meminfo.Protect & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY) ) != 0 ); // // initialize // m_pitch = pitch; m_data.m_ppf = ppf; Initialize(); // // !!! Dreamcast doesn't support client allocated memory // what to do about that? // // // Figure out the DD caps // DWORD caps = DDSCAPS_SYSTEMMEMORY; if (Is3D()) { caps |= DDSCAPS_3DDEVICE; } if (m_bTextureSize) { caps |= DDSCAPS_TEXTURE; } else { caps |= DDSCAPS_OFFSCREENPLAIN; } // // Create the surface // DDSDescription ddsd; ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_PITCH; ddsd.dwWidth = m_size.X(); ddsd.dwHeight = m_size.Y(); ddsd.lPitch = pitch; ddsd.ddsCaps.dwCaps = caps; ddsd.ddpfPixelFormat = m_data.m_ppf->GetDDPF(); if (m_bSharedMemory) { // // use the passed in memory // ddsd.dwFlags = ddsd.dwFlags | DDSD_LPSURFACE; ddsd.lpSurface = pbits; HRESULT hr = m_pdddevice->GetDD()->CreateSurface(&ddsd, &m_data.m_pdds, NULL); DDCall(hr); #ifdef _DEBUG DDSDescription ddsd; DDCall(m_data.m_pdds->GetSurfaceDesc(&ddsd)); ZAssert(pitch == ddsd.lPitch); #endif m_pitch = pitch; } else { // // Let directx allocate the memory // HRESULT hr = m_pdddevice->GetDD()->CreateSurface(&ddsd, &m_data.m_pdds, NULL); DDCall(hr); // // Copy the bits over // DDCall(m_data.m_pdds->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)); m_pitch = ddsd.Pitch(); ZAssert(pitch <= m_pitch); for (int y = 0; y < m_size.Y(); y++) { memcpy( ddsd.Pointer() + y * m_pitch, pbits + y * pitch, pitch ); } DDCall(m_data.m_pdds->Unlock(NULL)); } // // Do any other common construction tasks // FinishConstruction(); } bool IsMemoryShared() { return m_bSharedMemory; } ////////////////////////////////////////////////////////////////////////////// // // // ////////////////////////////////////////////////////////////////////////////// bool IsValid() { return m_data.m_pdds != NULL; } ////////////////////////////////////////////////////////////////////////////// // // Destructor // ////////////////////////////////////////////////////////////////////////////// ~DDSurfaceImpl() { } ////////////////////////////////////////////////////////////////////////////// // // Attach a ZBuffer surface // ////////////////////////////////////////////////////////////////////////////// IDirectDrawSurfaceX* GetDDSXZBuffer() { if (HasZBuffer()) { if (m_pddsZBuffer == NULL) { DWORD caps = DDSCAPS_ZBUFFER; if (m_stype.Test(SurfaceTypeVideo())) { caps |= DDSCAPS_VIDEOMEMORY; } else { caps |= DDSCAPS_SYSTEMMEMORY; } m_pddsZBuffer = m_pdddevice->CreateSurface( m_size, caps, m_pdddevice->GetZBufferPixelFormat(), true ); if (m_pddsZBuffer) { DDCall(m_data.m_pdds->AddAttachedSurface(m_pddsZBuffer)); } } } return m_pddsZBuffer; } ////////////////////////////////////////////////////////////////////////////// // // Surface updates // ////////////////////////////////////////////////////////////////////////////// void SurfaceChanged() { m_data.m_id++; if (m_data.m_id < 0) m_data.m_id = 0; } ////////////////////////////////////////////////////////////////////////////// // // Down Sample // ////////////////////////////////////////////////////////////////////////////// static DWORD Unpack(WORD pixelWord) { DWORD pixel = pixelWord; return ((pixel & 0xf800) << 5) | ((pixel & 0x07e0) << 3) | ((pixel & 0x001f) ); } static WORD Pack(DWORD pixel) { return (WORD)( ((pixel >> 5) & 0xf800) | ((pixel >> 3) & 0x07e0) | ((pixel ) & 0x001f) ); } static WORD Average(WORD pixel0, WORD pixel1, WORD pixel2, WORD pixel3) { return Pack( ( Unpack(pixel0) + Unpack(pixel1) + Unpack(pixel2) + Unpack(pixel3) ) >> 2 ); } static void DownSample( const WinPoint& sizeTarget, IDirectDrawSurfaceX* pddsTarget, IDirectDrawSurfaceX* pddsSource ) { DDSDescription ddsdSource; DDSDescription ddsdTarget; DDCall(pddsSource->Lock(NULL, &ddsdSource, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)); DDCall(pddsTarget->Lock(NULL, &ddsdTarget, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)); int pitchSource = ddsdSource.Pitch(); int pitchTarget = ddsdTarget.Pitch(); ZAssert( ddsdSource.GetPixelFormat().dwRGBBitCount == ddsdTarget.GetPixelFormat().dwRGBBitCount ); switch (ddsdSource.GetPixelFormat().dwRGBBitCount) { case 16: { ZAssert(ddsdSource.GetPixelFormat().dwRBitMask == 0xf800); ZAssert(ddsdSource.GetPixelFormat().dwGBitMask == 0x07e0); ZAssert(ddsdSource.GetPixelFormat().dwBBitMask == 0x001f); ZAssert(ddsdSource.GetPixelFormat().dwRGBAlphaBitMask == 0x0000); WORD* psource = (WORD*)ddsdSource.Pointer(); WORD* ptarget = (WORD*)ddsdTarget.Pointer(); for (int y = sizeTarget.Y() - 1; y >= 0; y--) { for (int x = sizeTarget.X() - 1; x >= 0; x--) { ptarget[x] = Average( psource[x * 2], psource[x * 2 + 1], psource[x * 2 + pitchSource / 2], psource[x * 2 + 1 + pitchSource / 2] ); } psource += 2 * pitchSource / 2; ptarget += pitchTarget / 2; } } break; case 24: { BYTE* psource = (BYTE*)ddsdSource.Pointer(); BYTE* ptarget = (BYTE*)ddsdTarget.Pointer(); for (int y = sizeTarget.Y() - 1; y >= 0; y--) { for (int x = sizeTarget.X() - 1; x >= 0; x--) { BYTE* psource0 = psource + x * 6; BYTE* psource1 = psource + x * 6 + 3; BYTE* psource2 = psource + x * 6 + pitchSource; BYTE* psource3 = psource + x * 6 + 3 + pitchSource; ptarget[x * 3 + 0] = (psource0[0] + psource1[0] + psource2[0] + psource3[0]) / 4; ptarget[x * 3 + 1] = (psource0[1] + psource1[1] + psource2[1] + psource3[1]) / 4; ptarget[x * 3 + 2] = (psource0[2] + psource1[2] + psource2[2] + psource3[2]) / 4; } psource += pitchSource * 2; ptarget += pitchTarget; } } break; default: ZError("DownSample: Invalid PixelFormat"); }; DDCall(pddsTarget->Unlock(NULL)); DDCall(pddsSource->Unlock(NULL)); } ////////////////////////////////////////////////////////////////////////////// // // Construct a new lod or converted surface // ////////////////////////////////////////////////////////////////////////////// void ConstructSurfaceData(SurfaceData& data, PixelFormat* ppf, const WinPoint& size) { data.m_id = -1; data.m_ppf = ppf; DWORD caps = DDSCAPS_SYSTEMMEMORY; if (m_bTextureSize/* && ppf->IsSoftwareTexture()*/) { caps |= DDSCAPS_TEXTURE; } else { caps |= DDSCAPS_OFFSCREENPLAIN; } data.m_pdds = m_pdddevice->CreateSurface( size, caps, ppf, false ); if (HasColorKey()) { DDCOLORKEY key; key.dwColorSpaceLowValue = key.dwColorSpaceHighValue = ppf->MakePixel(GetColorKey()).Value(); DDCall(data.m_pdds->SetColorKey(DDCKEY_SRCBLT, &key)); } if (caps & DDSCAPS_TEXTURE) { DDCall(data.m_pdds->QueryInterface(IID_IDirect3DTextureX, (void**)&(data.m_pd3dtexture))); } else { data.m_pd3dtexture = NULL; } } ////////////////////////////////////////////////////////////////////////////// // // Convert pixel formats using GDI // ////////////////////////////////////////////////////////////////////////////// static void Convert(const WinPoint& size, IDirectDrawSurfaceX* pddsTarget, IDirectDrawSurfaceX* pddsSource) { HDC hdcSource; DDCall(pddsSource->GetDC(&hdcSource)); HDC hdcTarget; DDCall(pddsTarget->GetDC(&hdcTarget)); ZVerify(::BitBlt(hdcTarget, 0, 0, size.X(), size.Y(), hdcSource, 0, 0, SRCCOPY)); DDCall(pddsTarget->ReleaseDC(hdcTarget)); DDCall(pddsSource->ReleaseDC(hdcSource)); } ////////////////////////////////////////////////////////////////////////////// // // Make sure the bits for a converted surface are available and up to date. // ////////////////////////////////////////////////////////////////////////////// void UpdateConvertedSurface(PixelFormat* ppf, const WinPoint& size, SurfaceData& data, const SurfaceData& dataSource) { if (ppf != data.m_ppf) { ConstructSurfaceData(data, ppf, size); } if (data.m_id != dataSource.m_id) { SetSurfaceMode(SurfaceModeDD); Convert(size, data.m_pdds, dataSource.m_pdds); data.m_id = dataSource.m_id; } } ////////////////////////////////////////////////////////////////////////////// // // Get a surface with a certain pixel format. // ////////////////////////////////////////////////////////////////////////////// IDirectDrawSurfaceX* GetDDSX() { SetSurfaceMode(SurfaceModeDD); return m_data.m_pdds; } IDirectDrawSurfaceX* GetDDSX(PixelFormat* ppf) { if (ppf == m_data.m_ppf) { SetSurfaceMode(SurfaceModeDD); return m_data.m_pdds; } else { UpdateConvertedSurface(ppf, m_size, m_dataConverted, m_data); return m_dataConverted.m_pdds; } } ////////////////////////////////////////////////////////////////////////////// // // Get a texture with a certain pixel format. // ////////////////////////////////////////////////////////////////////////////// IDirect3DTextureX* GetTextureX(PixelFormat* ppf, const WinPoint& size, int& id) { id = m_data.m_id; // // Return the fullsize surface if that's what's wanted. // if (size == m_size) { if (ppf == m_data.m_ppf) { SetSurfaceMode(SurfaceModeDD); #ifdef DREAMCAST if (!m_data.m_pd3dtexture) { DDCall(m_data.m_pdds->QueryInterface(IID_IDirect3DTextureX, (void**)&(m_data.m_pd3dtexture))); } #endif return m_data.m_pd3dtexture; } UpdateConvertedSurface(ppf, m_size, m_dataConverted, m_data); return m_dataConverted.m_pd3dtexture; } // // Need to return a lower level of detail // int index = 0; WinPoint sizeSource = m_size; while (true) { sizeSource.SetX(sizeSource.X() / 2); sizeSource.SetY(sizeSource.Y() / 2); // // Do we need to allocate a new lower level of detail? // if (index == m_datas.GetCount()) { m_datas.PushEnd(); m_datasConverted.PushEnd(); ConstructSurfaceData(m_datas.Get(index), m_data.m_ppf, sizeSource); } // // Do we need to update this level? // if (m_datas[index].m_id != m_data.m_id) { DownSample( sizeSource, m_datas[index].m_pdds, index == 0 ? m_data.m_pdds : m_datas[index - 1].m_pdds ); m_datas.Get(index).m_id = m_data.m_id; } // // Did we find the right size? // if (sizeSource == size) { // // Does the format need to be converted? // if (ppf == m_data.m_ppf) { return m_datas[index].m_pd3dtexture; } else { UpdateConvertedSurface(ppf, size, m_datasConverted.Get(index), m_datas[index]); return m_datasConverted[index].m_pd3dtexture; } } index++; } } TRef GetDDS() { SetSurfaceMode(SurfaceModeDD); TRef pdds; DDCall(m_data.m_pdds->QueryInterface(IID_IDirectDrawSurface, (void**)&pdds)); return pdds; } ////////////////////////////////////////////////////////////////////////////// // // Surface Type // ////////////////////////////////////////////////////////////////////////////// bool Is3D() { return m_stype.Test(SurfaceType3D()); } bool HasZBuffer() { return m_stype.Test(SurfaceTypeZBuffer()); } bool InVideoMemory() { return m_stype.Test(SurfaceTypeVideo()) != 0; } ////////////////////////////////////////////////////////////////////////////// // // Attributes // ////////////////////////////////////////////////////////////////////////////// PixelFormat* GetPixelFormat() { return m_data.m_ppf; } PrivatePalette* GetPalette() { return m_ppalette; } DDDevice* GetDDDevice() { return m_pdddevice; } Engine* GetEngine() { return m_pengine; } PrivateEngine* GetEngineImpl() { return m_pengine; } const WinPoint& GetSize() { return m_size; } SurfaceType GetSurfaceType() { return m_stype; } bool HasColorKey() { return m_bColorKey; } const Color& GetColorKey() { ZAssert(m_bColorKey); return m_colorKey; } void SetColorKey(const Color& color) { ZAssert(m_datas.GetCount() == 0); ZAssert(m_datasConverted.GetCount() == 0); m_bColorKey = true; m_colorKey = color; // // Update the ddraw surface // SetSurfaceMode(SurfaceModeDD); DDCOLORKEY key; key.dwColorSpaceLowValue = key.dwColorSpaceHighValue = m_data.m_ppf->MakePixel(m_colorKey).Value(); DDCall(m_data.m_pdds->SetColorKey(DDCKEY_SRCBLT, &key)); // // Update the converted ddraw surface // if (m_dataConverted.m_pdds) { DDCall(m_dataConverted.m_pdds->SetColorKey(DDCKEY_SRCBLT, &key)); } SurfaceChanged(); } int GetPitch() { return m_pitch; } BYTE* GetPointer() { if (m_pbits != NULL) { return m_pbits; } else { SetSurfaceMode(SurfaceModeLocked); BYTE* pbits = m_ddsdLocked.Pointer(); if (pbits == NULL) { // // DDraw returned null. Allocate some memory so the caller won't crash. // m_pbits = new BYTE[m_pitch * m_size.Y()]; return m_pbits; } return pbits; } } void ReleasePointer() { SetSurfaceMode(SurfaceModeDD); } ////////////////////////////////////////////////////////////////////////////// // // Surface modes // ////////////////////////////////////////////////////////////////////////////// void BeginScene() { SetSurfaceMode(SurfaceModeDD); } void EndScene() { } void SetSurfaceMode(SurfaceMode mode) { if (m_mode != mode) { // // switch back to DDMode // switch (m_mode) { case SurfaceModeLocked: if (m_pbits == NULL) { DDSCall(m_data.m_pdds->Unlock(NULL)); } SurfaceChanged(); break; } // // switch to the new mode // m_mode = mode; switch (mode) { case SurfaceModeLocked: DDSCall(m_data.m_pdds->Lock(NULL, &m_ddsdLocked, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)); break; } } } ////////////////////////////////////////////////////////////////////////////// // // Blts to and from a dc // ////////////////////////////////////////////////////////////////////////////// void BitBltFromDC(HDC hdc) { SetSurfaceMode(SurfaceModeDD); HDC hdcSurface; if (DDSCall(m_data.m_pdds->GetDC(&hdcSurface))) { ZVerify(::BitBlt( hdcSurface, 0, 0, m_size.X(), m_size.Y(), hdc, 0, 0, SRCCOPY )); DDSCall(m_data.m_pdds->ReleaseDC(hdcSurface)); } SurfaceChanged(); SetSurfaceMode(SurfaceModeDD); } ////////////////////////////////////////////////////////////////////////////// // // StretchBlt // ////////////////////////////////////////////////////////////////////////////// void UnclippedBlt( const WinRect& rectTarget, VideoSurface* psurfaceSource, const WinRect& rectSource, bool bColorKey ) { SetSurfaceMode(SurfaceModeDD); DWORD flags = bColorKey ? DDBLT_KEYSRC : 0; DDSurface* pddsurface; CastTo(pddsurface, psurfaceSource); DDSCall(m_data.m_pdds->Blt( (RECT*)&rectTarget, pddsurface->GetDDSX(), (RECT*)&rectSource, flags | DDBLT_WAIT, NULL )); } ////////////////////////////////////////////////////////////////////////////// // // Blt // ////////////////////////////////////////////////////////////////////////////// void UnclippedBlt( const WinRect& rect, IDirectDrawSurfaceX* pddsSource, const WinPoint& pointSource, bool bColorKey ) { SetSurfaceMode(SurfaceModeDD); DWORD flags = bColorKey ? DDBLT_KEYSRC : 0; WinRect rectSource(pointSource, pointSource + rect.Size()); DDSCall(m_data.m_pdds->Blt( (RECT*)&rect, pddsSource, (RECT*)&rectSource, flags | DDBLT_WAIT, NULL )); } void UnclippedBlt(const WinRect& rect, VideoSurface* psurfaceSource, const WinPoint& pointSource) { DDSurface* pddsurface; CastTo(pddsurface, psurfaceSource); UnclippedBlt(rect, pddsurface->GetDDSX(), pointSource, pddsurface->HasColorKey()); } ////////////////////////////////////////////////////////////////////////////// // // Fill // ////////////////////////////////////////////////////////////////////////////// void UnclippedFill(const WinRect& rect, Pixel pixel) { DDBltFX ddbltfx; ddbltfx.dwFillColor = pixel.Value(); DDSCall(m_data.m_pdds->Blt( (RECT*)&rect, NULL, (RECT*)&rect, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx )); } }; ////////////////////////////////////////////////////////////////////////////// // // Constructors // ////////////////////////////////////////////////////////////////////////////// TRef CreateDDSurface( DDDevice* pdddevice, SurfaceType stype, PixelFormat* ppf, PrivatePalette* ppalette, const WinPoint& size ) { TRef pddsurface = new DDSurfaceImpl(pdddevice, stype, ppf, ppalette, size); if (pddsurface->IsValid()) { return pddsurface; } else { return NULL; } } TRef CreateDDSurface( DDDevice* pdddevice, SurfaceType stype, PixelFormat* ppf, PrivatePalette* ppalette, const WinPoint& size, int pitch, BYTE* pbits ) { return new DDSurfaceImpl(pdddevice, stype, ppf, ppalette, size, pitch, pbits); } TRef CreateDDSurface( DDDevice* pdddevice, IDirectDrawSurfaceX* pdds, IDirectDrawSurfaceX* pddsZBuffer, PixelFormat* ppf, PrivatePalette* ppalette, SurfaceType stype ) { return new DDSurfaceImpl( pdddevice, pdds, pddsZBuffer, ppf, ppalette, stype ); }