#include "stdafx.h" #include "OverlaySurface.h" #pragma comment( lib, "ddraw" ) COverlaySurface* g_poverlaySurface = NULL; //COverlaySurface g_overlaySurface; //----------------------------------------------------------------------------- // Defines, constants, and global variables //----------------------------------------------------------------------------- #define SURFACE_WIDTH_NTSC 720 #define SURFACE_HEIGHT_NTSC 480 #define SURFACE_WIDTH_PAL 720 #define SURFACE_HEIGHT_PAL 576 #define INIT_DIRECTDRAW_STRUCT(x) (ZeroMemory(&x, sizeof(x)), x.dwSize=sizeof(x)) DWORD DDColorMatch(IDirectDrawSurface7 * pdds, COLORREF rgb); COverlaySurface::COverlaySurface() { m_pDD = NULL; m_pDDSPrimary = NULL; m_pDDSOverlay = NULL; m_pDDSOverlayBack = NULL; m_dwOverlayFlags = 0; //m_dwBackgroundColor = RGB(255, 0, 255); m_dwBackgroundColor = RGB(16,0,16); ZeroMemory(&m_rcSrc, sizeof(m_rcSrc)); ZeroMemory(&m_rcDst, sizeof(m_rcDst)); ZeroMemory(&m_OverlayFX, sizeof(m_OverlayFX)); ZeroMemory(&m_ddcaps, sizeof(m_ddcaps)); } COverlaySurface::~COverlaySurface() { FreeDirectDraw(); } //----------------------------------------------------------------------------- // Name: InitDirectDraw() // Desc: Create the DirectDraw object, and init the surfaces //----------------------------------------------------------------------------- HRESULT COverlaySurface::InitDirectDraw( HWND hWnd ) { DDSURFACEDESC2 ddsd; HRESULT hr; // Create the main DirectDraw object if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD, IID_IDirectDraw7, NULL ) ) ) return hr; // Request normal cooperative level to put us in windowed mode if( FAILED( hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL ) ) ) return hr; // Get driver capabilities to determine Overlay support. ZeroMemory( &m_ddcaps, sizeof(m_ddcaps) ); m_ddcaps.dwSize = sizeof(m_ddcaps); if( FAILED( hr = m_pDD->GetCaps( &m_ddcaps, NULL ) ) ) return hr; // Create the primary surface, which in windowed mode is the desktop. ZeroMemory(&ddsd,sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pDDSPrimary, NULL ) ) ) return hr; DDCAPS ddcaps; ZeroMemory(&ddcaps,sizeof(ddcaps)); ddcaps.dwSize = sizeof(ddcaps); if (m_pDD->GetCaps(&ddcaps, NULL) == DD_OK) { if (ddcaps.dwCaps & DDCAPS_CANBLTSYSMEM) { TRACE("the device supports DMA\n"); TRACE("ddcaps.dwSVBCaps = %x\n", ddcaps.dwSVBCaps); TRACE("ddcaps.dwSVBCKeyCaps = %x\n", ddcaps.dwSVBCKeyCaps); TRACE("ddcaps.dwSVBFXCaps = %x\n", ddcaps.dwSVBFXCaps); TRACE("ddcaps.dwSVBRops = %x\n", ddcaps.dwSVBRops); TRACE("ddcaps.dwVSBCaps = %x\n", ddcaps.dwVSBCaps); TRACE("ddcaps.dwVSBCKeyCaps = %x\n", ddcaps.dwVSBCKeyCaps); TRACE("ddcaps.dwVSBFXCaps = %x\n", ddcaps.dwVSBFXCaps); TRACE("ddcaps.dwVSBRops = %x\n", ddcaps.dwVSBRops); TRACE("ddcaps.dwSSBCaps = %x\n", ddcaps.dwSSBCaps); TRACE("ddcaps.dwSSBCKeyCaps = %x\n", ddcaps.dwSSBCKeyCaps ); TRACE("ddcaps.dwSSBFXCaps = %x\n", ddcaps.dwSSBFXCaps ); TRACE("ddcaps.dwSSBRops = %x\n", ddcaps.dwSSBRops ); } else { TRACE("the device does not supports DMA\n"); } if (ddcaps.dwCaps & DDCAPS2_NOPAGELOCKREQUIRED) { TRACE("DDCAPS2_NOPAGELOCKREQUIRED set\n"); } else { TRACE("DDCAPS2_NOPAGELOCKREQUIRED not set\n"); } } return S_OK; } //----------------------------------------------------------------------------- // Name: HasOverlaySupport() // Desc: Returns TRUE if the device supports overlays, FALSE otherwise //----------------------------------------------------------------------------- BOOL COverlaySurface::HasOverlaySupport() { // Get driver capabilities to determine overlay support. ZeroMemory( &m_ddcaps, sizeof(m_ddcaps) ); m_ddcaps.dwSize = sizeof(m_ddcaps); m_pDD->GetCaps( &m_ddcaps, NULL ); // Does the driver support overlays in the current mode? // The DirectDraw emulation layer does not support overlays // so overlay related APIs will fail without hardware support. if( m_ddcaps.dwCaps & DDCAPS_OVERLAY ) { // Make sure it supports stretching (scaling) if ( m_ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH ) return TRUE; else return FALSE; } else { return FALSE; } } //----------------------------------------------------------------------------- // Name: CreateDirectDrawSurfaces() // Desc: Creates the DirectDraw surfaces //----------------------------------------------------------------------------- HRESULT COverlaySurface::CreateDirectDrawSurfaces(HWND hWnd, DWORD width, DWORD heght) { DDSURFACEDESC2 ddsd; DDPIXELFORMAT ddpfOverlayFormat; DDSCAPS2 ddscaps; HRESULT hr; // Release any previous surfaces SAFE_RELEASE( m_pDDSOverlay ); ZeroMemory( &ddpfOverlayFormat, sizeof(ddpfOverlayFormat) ); ddpfOverlayFormat.dwSize = sizeof(ddpfOverlayFormat); ddpfOverlayFormat.dwFlags = DDPF_FOURCC; DDPIXELFORMAT g_ddpfOverlayFormats = {sizeof(DDPIXELFORMAT), DDPF_FOURCC,MAKEFOURCC('Y','U','Y','2'),0,0,0,0,0} // YUY2 ; // Setup the overlay surface's attributes in the surface descriptor ZeroMemory( &ddsd, sizeof(ddsd) ); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_BACKBUFFERCOUNT | DDSD_PIXELFORMAT; ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP | DDSCAPS_COMPLEX | DDSCAPS_VIDEOMEMORY; ddsd.dwBackBufferCount = 1; ddsd.dwWidth = width; ddsd.dwHeight = heght; ddsd.ddpfPixelFormat = g_ddpfOverlayFormats; m_rcSrc.left = 0; m_rcSrc.top = 0; m_rcSrc.right = width; m_rcSrc.bottom = heght; m_rcDst = m_rcSrc; // Attempt to create the surface with theses settings if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pDDSOverlay, NULL ) ) ) return hr; ZeroMemory(&ddscaps, sizeof(ddscaps)); ddscaps.dwCaps = DDSCAPS_BACKBUFFER; if( FAILED( hr = m_pDDSOverlay->GetAttachedSurface( &ddscaps, &m_pDDSOverlayBack ) ) ) return hr; // Setup effects structure ZeroMemory( &m_OverlayFX, sizeof(m_OverlayFX) ); m_OverlayFX.dwSize = sizeof(m_OverlayFX); // Setup overlay flags. m_dwOverlayFlags = DDOVER_SHOW; // Check for destination color keying capability if (m_ddcaps.dwCKeyCaps & DDCKEYCAPS_DESTOVERLAY) { m_OverlayFX.dckDestColorkey.dwColorSpaceLowValue = DDColorMatch(m_pDDSPrimary, m_dwBackgroundColor); m_OverlayFX.dckDestColorkey.dwColorSpaceHighValue = DDColorMatch(m_pDDSPrimary, m_dwBackgroundColor); m_dwOverlayFlags |= DDOVER_DDFX | DDOVER_KEYDESTOVERRIDE; } else { LPDIRECTDRAWCLIPPER pClipper = NULL; // If not, we'll setup a clipper for the window. This will fix the // problem on a few video cards - but the ones that don't shouldn't // care. if( FAILED( hr = m_pDD->CreateClipper(0, &pClipper, NULL) ) ) return hr; if( FAILED( hr = pClipper->SetHWnd(0, hWnd ) ) ) return hr; if( FAILED( hr = m_pDDSPrimary->SetClipper( pClipper ) ) ) return hr; SAFE_RELEASE( pClipper ); } return S_OK; } //----------------------------------------------------------------------------- // Name: FreeDirectDraw() // Desc: Release all the DirectDraw objects //----------------------------------------------------------------------------- VOID COverlaySurface::FreeDirectDraw() { SAFE_RELEASE( m_pDDSOverlay ); // m_pDDSOverlayBack will be automatically released here SAFE_RELEASE( m_pDDSPrimary ); SAFE_RELEASE( m_pDD ); } //----------------------------------------------------------------------------- // Name: RestoreSurfaces() // Desc: Restore all the surfaces, and redraw the sprite surfaces. //----------------------------------------------------------------------------- HRESULT COverlaySurface::RestoreSurfaces() { HRESULT hr; if( FAILED( hr = m_pDD->RestoreAllSurfaces() ) ) return hr; return S_OK; } void COverlaySurface::UpdateOverlay() { // Update the screen if we need to refresh. This case occurs // when in windowed mode and the window is behind others. // The app will not be active, but it will be visible. if( m_pDDSPrimary ) { // UpdateOverlay is how we put the overlay on the screen. if( m_rcDst.top == m_rcDst.bottom ) { m_pDDSOverlay->UpdateOverlay( NULL, m_pDDSPrimary, NULL, DDOVER_HIDE, NULL ); } else { m_pDDSOverlay->UpdateOverlay( &m_rcSrc, m_pDDSPrimary, &m_rcDst, m_dwOverlayFlags, &m_OverlayFX); } } } DWORD DDColorMatch(IDirectDrawSurface7 * pdds, COLORREF rgb) { COLORREF rgbT; HDC hdc; DWORD dw = CLR_INVALID; DDSURFACEDESC2 ddsd; HRESULT hres; // // Use GDI SetPixel to color match for us // if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) { rgbT = GetPixel(hdc, 0, 0); // Save current pixel value SetPixel(hdc, 0, 0, rgb); // Set our value pdds->ReleaseDC(hdc); } // // Now lock the surface so we can read back the converted color // INIT_DIRECTDRAW_STRUCT(ddsd); while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING); if (hres == DD_OK) { dw = *(DWORD *) ddsd.lpSurface; // Get DWORD if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32) dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1; // Mask it to bpp pdds->Unlock(NULL); } // // Now put the color that was there back. // if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) { SetPixel(hdc, 0, 0, rgbT); pdds->ReleaseDC(hdc); } return dw; } /*BOOL SurfaceLock(LPDIRECTDRAWSURFACE7 pDDSOverlay, OVERLAY_SURFACE_INFO* pInfo) { HRESULT hRet; // This is where we put return values from DirectDraw. DDSURFACEDESC2 ddsd; if (!pDDSOverlay) return FALSE; ZeroMemory( &ddsd, sizeof(ddsd) ); ddsd.dwSize = sizeof(ddsd); // Lock down the surface so we can modify it's contents. hRet = pDDSOverlay->Lock( NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); if (FAILED(hRet)) return FALSE; pInfo->width = ddsd.dwWidth; pInfo->height = ddsd.dwHeight; pInfo->pitch = ddsd.lPitch; pInfo->virtualAddrSurface = (ULONG)ddsd.lpSurface; pInfo->bytesPerPixel = ddsd.ddpfPixelFormat.dwYUVBitCount / 8; return TRUE; } void SurfaceUnlock(LPDIRECTDRAWSURFACE7 pDDSOverlay) { if (!pDDSOverlay) return; pDDSOverlay->Unlock(NULL); }*/