You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1036 lines
30 KiB
C++
1036 lines
30 KiB
C++
//-----------------------------------------------------------------------------
|
|
// File: ddutil.cpp
|
|
//
|
|
// Desc: DirectDraw framewark classes. Feel free to use this class as a
|
|
// starting point for adding extra functionality.
|
|
//
|
|
//
|
|
// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
#define STRICT
|
|
#include <tchar.h>
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <ddraw.h>
|
|
#include <dsound.h>
|
|
#include "ddutil.h"
|
|
#include "DSUtil.h"
|
|
|
|
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
|
|
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
|
|
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CDisplay()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
CDisplay::CDisplay()
|
|
{
|
|
m_pDD = NULL;
|
|
m_pddsFrontBuffer = NULL;
|
|
m_pddsBackBuffer = NULL;
|
|
m_pddsBackBufferLeft = NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: ~CDisplay()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
CDisplay::~CDisplay()
|
|
{
|
|
DestroyObjects();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DestroyObjects()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::DestroyObjects()
|
|
{
|
|
SAFE_RELEASE( m_pddsBackBufferLeft );
|
|
SAFE_RELEASE( m_pddsBackBuffer );
|
|
SAFE_RELEASE( m_pddsFrontBuffer );
|
|
|
|
if( m_pDD )
|
|
m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
|
|
|
|
SAFE_RELEASE( m_pDD );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CreateFullScreenDisplay()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth,
|
|
DWORD dwHeight, DWORD dwBPP )
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Cleanup anything from a previous call
|
|
DestroyObjects();
|
|
|
|
// DDraw stuff begins here
|
|
if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
|
|
IID_IDirectDraw7, NULL ) ) )
|
|
return E_FAIL;
|
|
|
|
// Set cooperative level
|
|
hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
|
|
if( FAILED(hr) )
|
|
return E_FAIL;
|
|
|
|
// Set the display mode
|
|
if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) )
|
|
return E_FAIL;
|
|
|
|
// Create primary surface (with backbuffer attached)
|
|
DDSURFACEDESC2 ddsd;
|
|
ZeroMemory( &ddsd, sizeof( ddsd ) );
|
|
ddsd.dwSize = sizeof( ddsd );
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
|
|
DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
|
|
ddsd.dwBackBufferCount = 1;
|
|
|
|
if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,
|
|
NULL ) ) )
|
|
return E_FAIL;
|
|
|
|
// Get a pointer to the back buffer
|
|
DDSCAPS2 ddscaps;
|
|
ZeroMemory( &ddscaps, sizeof( ddscaps ) );
|
|
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
|
|
|
|
if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
|
|
&m_pddsBackBuffer ) ) )
|
|
return E_FAIL;
|
|
|
|
m_pddsBackBuffer->AddRef();
|
|
|
|
m_hWnd = hWnd;
|
|
m_bWindowed = FALSE;
|
|
UpdateBounds();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CreateWindowedDisplay()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight )
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Cleanup anything from a previous call
|
|
DestroyObjects();
|
|
|
|
// DDraw stuff begins here
|
|
if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
|
|
IID_IDirectDraw7, NULL ) ) )
|
|
return E_FAIL;
|
|
|
|
// Set cooperative level
|
|
hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL );
|
|
if( FAILED(hr) )
|
|
return E_FAIL;
|
|
|
|
RECT rcWork;
|
|
RECT rc;
|
|
DWORD dwStyle;
|
|
|
|
// If we are still a WS_POPUP window we should convert to a normal app
|
|
// window so we look like a windows app.
|
|
dwStyle = GetWindowStyle( hWnd );
|
|
dwStyle &= ~WS_POPUP;
|
|
dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
|
|
SetWindowLong( hWnd, GWL_STYLE, dwStyle );
|
|
|
|
// Aet window size
|
|
SetRect( &rc, 0, 0, dwWidth, dwHeight );
|
|
|
|
AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
|
|
GetWindowExStyle(hWnd) );
|
|
|
|
SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
|
|
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
|
|
|
|
SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
|
|
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
|
|
|
|
// Make sure our window does not hang outside of the work area
|
|
SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
|
|
GetWindowRect( hWnd, &rc );
|
|
if( rc.left < rcWork.left ) rc.left = rcWork.left;
|
|
if( rc.top < rcWork.top ) rc.top = rcWork.top;
|
|
SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
|
|
|
|
LPDIRECTDRAWCLIPPER pcClipper;
|
|
|
|
// Create the primary surface
|
|
DDSURFACEDESC2 ddsd;
|
|
ZeroMemory( &ddsd, sizeof( ddsd ) );
|
|
ddsd.dwSize = sizeof( ddsd );
|
|
ddsd.dwFlags = DDSD_CAPS;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
|
|
|
if( FAILED( m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
|
|
return E_FAIL;
|
|
|
|
// Create the backbuffer surface
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
|
|
ddsd.dwWidth = dwWidth;
|
|
ddsd.dwHeight = dwHeight;
|
|
|
|
if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
|
|
return E_FAIL;
|
|
|
|
if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
|
|
return E_FAIL;
|
|
|
|
if( FAILED( hr = pcClipper->SetHWnd( 0, hWnd ) ) )
|
|
{
|
|
pcClipper->Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pcClipper ) ) )
|
|
{
|
|
pcClipper->Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Done with clipper
|
|
pcClipper->Release();
|
|
|
|
m_hWnd = hWnd;
|
|
m_bWindowed = TRUE;
|
|
UpdateBounds();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::CreateSurface( CSurface** ppSurface,
|
|
DWORD dwWidth, DWORD dwHeight )
|
|
{
|
|
if( NULL == m_pDD )
|
|
return E_POINTER;
|
|
if( NULL == ppSurface )
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr;
|
|
DDSURFACEDESC2 ddsd;
|
|
ZeroMemory( &ddsd, sizeof( ddsd ) );
|
|
ddsd.dwSize = sizeof( ddsd );
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
|
ddsd.dwWidth = dwWidth;
|
|
ddsd.dwHeight = dwHeight;
|
|
|
|
(*ppSurface) = new CSurface();
|
|
if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
|
|
{
|
|
delete (*ppSurface);
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CDisplay::CreateSurfaceFromBitmap()
|
|
// Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file.
|
|
// Use MAKEINTRESOURCE() to pass a constant into strBMP.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface,
|
|
TCHAR* strBMP,
|
|
DWORD dwDesiredWidth,
|
|
DWORD dwDesiredHeight )
|
|
{
|
|
HRESULT hr;
|
|
HBITMAP hBMP = NULL;
|
|
BITMAP bmp;
|
|
DDSURFACEDESC2 ddsd;
|
|
|
|
if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL )
|
|
return E_INVALIDARG;
|
|
|
|
*ppSurface = NULL;
|
|
|
|
// Try to load the bitmap as a resource, if that fails, try it as a file
|
|
hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
|
|
IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
|
|
LR_CREATEDIBSECTION );
|
|
if( hBMP == NULL )
|
|
{
|
|
hBMP = (HBITMAP) LoadImage( NULL, strBMP,
|
|
IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
|
|
LR_LOADFROMFILE | LR_CREATEDIBSECTION );
|
|
if( hBMP == NULL )
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Get size of the bitmap
|
|
GetObject( hBMP, sizeof(bmp), &bmp );
|
|
|
|
// Create a DirectDrawSurface for this bitmap
|
|
ZeroMemory( &ddsd, sizeof(ddsd) );
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
|
ddsd.dwWidth = bmp.bmWidth;
|
|
ddsd.dwHeight = bmp.bmHeight;
|
|
|
|
(*ppSurface) = new CSurface();
|
|
if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
|
|
{
|
|
delete (*ppSurface);
|
|
return hr;
|
|
}
|
|
|
|
// Draw the bitmap on this surface
|
|
if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
|
|
{
|
|
DeleteObject( hBMP );
|
|
return hr;
|
|
}
|
|
|
|
DeleteObject( hBMP );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CDisplay::CreateSurfaceFromText()
|
|
// Desc: Creates a DirectDrawSurface from a text string using hFont or the default
|
|
// GDI font if hFont is NULL.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface,
|
|
HFONT hFont, TCHAR* strText,
|
|
COLORREF crBackground, COLORREF crForeground )
|
|
{
|
|
HDC hDC = NULL;
|
|
LPDIRECTDRAWSURFACE7 pDDS = NULL;
|
|
HRESULT hr;
|
|
DDSURFACEDESC2 ddsd;
|
|
SIZE sizeText;
|
|
|
|
if( m_pDD == NULL || strText == NULL || ppSurface == NULL )
|
|
return E_INVALIDARG;
|
|
|
|
*ppSurface = NULL;
|
|
|
|
hDC = GetDC( NULL );
|
|
|
|
if( hFont )
|
|
SelectObject( hDC, hFont );
|
|
|
|
GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText );
|
|
ReleaseDC( NULL, hDC );
|
|
|
|
// Create a DirectDrawSurface for this bitmap
|
|
ZeroMemory( &ddsd, sizeof(ddsd) );
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
|
ddsd.dwWidth = sizeText.cx;
|
|
ddsd.dwHeight = sizeText.cy;
|
|
|
|
(*ppSurface) = new CSurface();
|
|
if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
|
|
{
|
|
delete (*ppSurface);
|
|
return hr;
|
|
}
|
|
|
|
if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, 0, 0,
|
|
crBackground, crForeground ) ) )
|
|
return hr;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::Present()
|
|
{
|
|
HRESULT hr;
|
|
|
|
if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer )
|
|
return E_POINTER;
|
|
|
|
while( 1 )
|
|
{
|
|
if( m_bWindowed )
|
|
hr = m_pddsFrontBuffer->Blt( &m_rcWindow, m_pddsBackBuffer,
|
|
NULL, DDBLT_WAIT, NULL );
|
|
else
|
|
hr = m_pddsFrontBuffer->Flip( NULL, 0 );
|
|
|
|
if( hr == DDERR_SURFACELOST )
|
|
{
|
|
m_pddsFrontBuffer->Restore();
|
|
m_pddsBackBuffer->Restore();
|
|
}
|
|
|
|
if( hr != DDERR_WASSTILLDRAWING )
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette )
|
|
{
|
|
if( NULL == m_pddsFrontBuffer || NULL == m_pddsBackBuffer )
|
|
return E_POINTER;
|
|
|
|
// Set the palette before loading the bitmap
|
|
if( pPalette )
|
|
m_pddsFrontBuffer->SetPalette( pPalette );
|
|
|
|
CSurface backBuffer;
|
|
backBuffer.Create( m_pddsBackBuffer );
|
|
|
|
if( FAILED( backBuffer.DrawBitmap( hbm, 0, 0, 0, 0 ) ) )
|
|
return E_FAIL;
|
|
|
|
return Present();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
|
|
RECT* prc )
|
|
{
|
|
if( NULL == m_pddsBackBuffer )
|
|
return E_POINTER;
|
|
|
|
return m_pddsBackBuffer->BltFast( x, y, pdds, prc, DDBLTFAST_SRCCOLORKEY );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc,
|
|
DWORD dwFlags )
|
|
{
|
|
if( NULL == m_pddsBackBuffer )
|
|
return E_POINTER;
|
|
|
|
return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc )
|
|
{
|
|
if( NULL == pSurface )
|
|
return E_INVALIDARG;
|
|
|
|
if( pSurface->IsColorKeyed() )
|
|
return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY );
|
|
else
|
|
return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::Clear( DWORD dwColor )
|
|
{
|
|
if( NULL == m_pddsBackBuffer )
|
|
return E_POINTER;
|
|
|
|
// Erase the background
|
|
DDBLTFX ddbltfx;
|
|
ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
|
|
ddbltfx.dwSize = sizeof(ddbltfx);
|
|
ddbltfx.dwFillColor = dwColor;
|
|
|
|
return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::SetPalette( LPDIRECTDRAWPALETTE pPalette )
|
|
{
|
|
if( NULL == m_pddsFrontBuffer )
|
|
return E_POINTER;
|
|
|
|
return m_pddsFrontBuffer->SetPalette( pPalette );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette,
|
|
const TCHAR* strBMP )
|
|
{
|
|
HRSRC hResource = NULL;
|
|
RGBQUAD* pRGB = NULL;
|
|
BITMAPINFOHEADER* pbi = NULL;
|
|
PALETTEENTRY aPalette[256];
|
|
HANDLE hFile = NULL;
|
|
DWORD iColor;
|
|
DWORD dwColors;
|
|
BITMAPFILEHEADER bf;
|
|
BITMAPINFOHEADER bi;
|
|
DWORD dwBytesRead;
|
|
|
|
if( m_pDD == NULL || strBMP == NULL || ppPalette == NULL )
|
|
return E_INVALIDARG;
|
|
|
|
*ppPalette = NULL;
|
|
|
|
// Try to load the bitmap as a resource, if that fails, try it as a file
|
|
hResource = FindResource( NULL, strBMP, RT_BITMAP );
|
|
if( hResource )
|
|
{
|
|
pbi = (LPBITMAPINFOHEADER) LockResource( LoadResource( NULL, hResource ) );
|
|
if( NULL == pbi )
|
|
return E_FAIL;
|
|
|
|
pRGB = (RGBQUAD*) ( (BYTE*) pbi + pbi->biSize );
|
|
|
|
// Figure out how many colors there are
|
|
if( pbi == NULL || pbi->biSize < sizeof(BITMAPINFOHEADER) )
|
|
dwColors = 0;
|
|
else if( pbi->biBitCount > 8 )
|
|
dwColors = 0;
|
|
else if( pbi->biClrUsed == 0 )
|
|
dwColors = 1 << pbi->biBitCount;
|
|
else
|
|
dwColors = pbi->biClrUsed;
|
|
|
|
// A DIB color table has its colors stored BGR not RGB
|
|
// so flip them around.
|
|
for( iColor = 0; iColor < dwColors; iColor++ )
|
|
{
|
|
aPalette[iColor].peRed = pRGB[iColor].rgbRed;
|
|
aPalette[iColor].peGreen = pRGB[iColor].rgbGreen;
|
|
aPalette[iColor].peBlue = pRGB[iColor].rgbBlue;
|
|
aPalette[iColor].peFlags = 0;
|
|
}
|
|
|
|
return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
|
|
}
|
|
|
|
// Attempt to load bitmap as a file
|
|
hFile = CreateFile( strBMP, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
|
|
if( NULL == hFile )
|
|
return E_FAIL;
|
|
|
|
// Read the BITMAPFILEHEADER
|
|
ReadFile( hFile, &bf, sizeof(bf), &dwBytesRead, NULL );
|
|
if( dwBytesRead != sizeof(bf) )
|
|
{
|
|
CloseHandle( hFile );
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Read the BITMAPINFOHEADER
|
|
ReadFile( hFile, &bi, sizeof(bi), &dwBytesRead, NULL );
|
|
if( dwBytesRead != sizeof(bi) )
|
|
{
|
|
CloseHandle( hFile );
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Read the PALETTEENTRY
|
|
ReadFile( hFile, aPalette, sizeof(aPalette), &dwBytesRead, NULL );
|
|
if( dwBytesRead != sizeof(aPalette) )
|
|
{
|
|
CloseHandle( hFile );
|
|
return E_FAIL;
|
|
}
|
|
|
|
CloseHandle( hFile );
|
|
|
|
// Figure out how many colors there are
|
|
if( bi.biSize != sizeof(BITMAPINFOHEADER) )
|
|
dwColors = 0;
|
|
else if (bi.biBitCount > 8)
|
|
dwColors = 0;
|
|
else if (bi.biClrUsed == 0)
|
|
dwColors = 1 << bi.biBitCount;
|
|
else
|
|
dwColors = bi.biClrUsed;
|
|
|
|
// A DIB color table has its colors stored BGR not RGB
|
|
// so flip them around since DirectDraw uses RGB
|
|
for( iColor = 0; iColor < dwColors; iColor++ )
|
|
{
|
|
BYTE r = aPalette[iColor].peRed;
|
|
aPalette[iColor].peRed = aPalette[iColor].peBlue;
|
|
aPalette[iColor].peBlue = r;
|
|
}
|
|
|
|
return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::UpdateBounds()
|
|
{
|
|
if( m_bWindowed )
|
|
{
|
|
GetClientRect( m_hWnd, &m_rcWindow );
|
|
ClientToScreen( m_hWnd, (POINT*)&m_rcWindow );
|
|
ClientToScreen( m_hWnd, (POINT*)&m_rcWindow+1 );
|
|
}
|
|
else
|
|
{
|
|
SetRect( &m_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN),
|
|
GetSystemMetrics(SM_CYSCREEN) );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CDisplay::InitClipper
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDisplay::InitClipper()
|
|
{
|
|
LPDIRECTDRAWCLIPPER pClipper;
|
|
HRESULT hr;
|
|
|
|
// Create a clipper when using GDI to draw on the primary surface
|
|
if( FAILED( hr = m_pDD->CreateClipper( 0, &pClipper, NULL ) ) )
|
|
return hr;
|
|
|
|
pClipper->SetHWnd( 0, m_hWnd );
|
|
|
|
if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pClipper ) ) )
|
|
return hr;
|
|
|
|
// We can release the clipper now since g_pDDSPrimary
|
|
// now maintains a ref count on the clipper
|
|
SAFE_RELEASE( pClipper );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
CSurface::CSurface()
|
|
{
|
|
m_pdds = NULL;
|
|
m_bColorKeyed = NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
CSurface::~CSurface()
|
|
{
|
|
SAFE_RELEASE( m_pdds );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSurface::Create( LPDIRECTDRAWSURFACE7 pdds )
|
|
{
|
|
m_pdds = pdds;
|
|
|
|
if( m_pdds )
|
|
{
|
|
m_pdds->AddRef();
|
|
|
|
// Get the DDSURFACEDESC structure for this surface
|
|
m_ddsd.dwSize = sizeof(m_ddsd);
|
|
m_pdds->GetSurfaceDesc( &m_ddsd );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd )
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Create the DDraw surface
|
|
if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) )
|
|
return hr;
|
|
|
|
// Prepare the DDSURFACEDESC structure
|
|
m_ddsd.dwSize = sizeof(m_ddsd);
|
|
|
|
// Get the DDSURFACEDESC structure for this surface
|
|
m_pdds->GetSurfaceDesc( &m_ddsd );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSurface::Destroy()
|
|
{
|
|
SAFE_RELEASE( m_pdds );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CSurface::DrawBitmap()
|
|
// Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the
|
|
// bitmap if nessasary
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSurface::DrawBitmap( HBITMAP hBMP,
|
|
DWORD dwBMPOriginX, DWORD dwBMPOriginY,
|
|
DWORD dwBMPWidth, DWORD dwBMPHeight )
|
|
{
|
|
HDC hDCImage;
|
|
HDC hDC;
|
|
BITMAP bmp;
|
|
DDSURFACEDESC2 ddsd;
|
|
HRESULT hr;
|
|
|
|
if( hBMP == NULL || m_pdds == NULL )
|
|
return E_INVALIDARG;
|
|
|
|
// Make sure this surface is restored.
|
|
if( FAILED( hr = m_pdds->Restore() ) )
|
|
return hr;
|
|
|
|
// Get the surface.description
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
m_pdds->GetSurfaceDesc( &ddsd );
|
|
|
|
if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC )
|
|
return E_NOTIMPL;
|
|
|
|
// Select bitmap into a memoryDC so we can use it.
|
|
hDCImage = CreateCompatibleDC( NULL );
|
|
if( NULL == hDCImage )
|
|
return E_FAIL;
|
|
|
|
SelectObject( hDCImage, hBMP );
|
|
|
|
// Get size of the bitmap
|
|
GetObject( hBMP, sizeof(bmp), &bmp );
|
|
|
|
// Use the passed size, unless zero
|
|
dwBMPWidth = ( dwBMPWidth == 0 ) ? bmp.bmWidth : dwBMPWidth;
|
|
dwBMPHeight = ( dwBMPHeight == 0 ) ? bmp.bmHeight : dwBMPHeight;
|
|
|
|
// Stretch the bitmap to cover this surface
|
|
if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
|
|
return hr;
|
|
|
|
StretchBlt( hDC, 0, 0,
|
|
ddsd.dwWidth, ddsd.dwHeight,
|
|
hDCImage, dwBMPOriginX, dwBMPOriginY,
|
|
dwBMPWidth, dwBMPHeight, SRCCOPY );
|
|
|
|
if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
|
|
return hr;
|
|
|
|
DeleteDC( hDCImage );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CSurface::DrawText()
|
|
// Desc: Draws a text string on a DirectDraw surface using hFont or the default
|
|
// GDI font if hFont is NULL.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText,
|
|
DWORD dwOriginX, DWORD dwOriginY,
|
|
COLORREF crBackground, COLORREF crForeground )
|
|
{
|
|
HDC hDC = NULL;
|
|
HRESULT hr;
|
|
|
|
if( m_pdds == NULL || strText == NULL )
|
|
return E_INVALIDARG;
|
|
|
|
// Make sure this surface is restored.
|
|
if( FAILED( hr = m_pdds->Restore() ) )
|
|
return hr;
|
|
|
|
if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
|
|
return hr;
|
|
|
|
// Set the background and foreground color
|
|
SetBkColor( hDC, crBackground );
|
|
SetTextColor( hDC, crForeground );
|
|
|
|
if( hFont )
|
|
SelectObject( hDC, hFont );
|
|
|
|
// Use GDI to draw the text on the surface
|
|
TextOut( hDC, dwOriginX, dwOriginY, strText, _tcslen(strText) );
|
|
|
|
if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
|
|
return hr;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CSurface::ReDrawBitmapOnSurface()
|
|
// Desc: Load a bitmap from a file or resource into a DirectDraw surface.
|
|
// normaly used to re-load a surface after a restore.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSurface::DrawBitmap( TCHAR* strBMP,
|
|
DWORD dwDesiredWidth, DWORD dwDesiredHeight )
|
|
{
|
|
HBITMAP hBMP;
|
|
HRESULT hr;
|
|
|
|
if( m_pdds == NULL || strBMP == NULL )
|
|
return E_INVALIDARG;
|
|
|
|
// Try to load the bitmap as a resource, if that fails, try it as a file
|
|
hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
|
|
IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
|
|
LR_CREATEDIBSECTION );
|
|
if( hBMP == NULL )
|
|
{
|
|
hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP,
|
|
dwDesiredWidth, dwDesiredHeight,
|
|
LR_LOADFROMFILE | LR_CREATEDIBSECTION );
|
|
if( hBMP == NULL )
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Draw the bitmap on this surface
|
|
if( FAILED( hr = DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
|
|
{
|
|
DeleteObject( hBMP );
|
|
return hr;
|
|
}
|
|
|
|
DeleteObject( hBMP );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSurface::SetColorKey( DWORD dwColorKey )
|
|
{
|
|
if( NULL == m_pdds )
|
|
return E_POINTER;
|
|
|
|
m_bColorKeyed = TRUE;
|
|
|
|
DDCOLORKEY ddck;
|
|
ddck.dwColorSpaceLowValue = ConvertGDIColor( dwColorKey );
|
|
ddck.dwColorSpaceHighValue = ConvertGDIColor( dwColorKey );
|
|
|
|
return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CSurface::ConvertGDIColor()
|
|
// Desc: Converts a GDI color (0x00bbggrr) into the equivalent color on a
|
|
// DirectDrawSurface using its pixel format.
|
|
//-----------------------------------------------------------------------------
|
|
DWORD CSurface::ConvertGDIColor( COLORREF dwGDIColor )
|
|
{
|
|
if( m_pdds == NULL )
|
|
return 0x00000000;
|
|
|
|
COLORREF rgbT;
|
|
HDC hdc;
|
|
DWORD dw = CLR_INVALID;
|
|
DDSURFACEDESC2 ddsd;
|
|
HRESULT hr;
|
|
|
|
// Use GDI SetPixel to color match for us
|
|
if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK)
|
|
{
|
|
rgbT = GetPixel(hdc, 0, 0); // Save current pixel value
|
|
SetPixel(hdc, 0, 0, dwGDIColor); // Set our value
|
|
m_pdds->ReleaseDC(hdc);
|
|
}
|
|
|
|
// Now lock the surface so we can read back the converted color
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
hr = m_pdds->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
|
|
if( hr == DD_OK)
|
|
{
|
|
dw = *(DWORD *) ddsd.lpSurface;
|
|
if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
|
|
dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;
|
|
m_pdds->Unlock(NULL);
|
|
}
|
|
|
|
// Now put the color that was there back.
|
|
if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK )
|
|
{
|
|
SetPixel( hdc, 0, 0, rgbT );
|
|
m_pdds->ReleaseDC(hdc);
|
|
}
|
|
|
|
return dw;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CSurface::GetBitMaskInfo()
|
|
// Desc: Returns the number of bits and the shift in the bit mask
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CSurface::GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits )
|
|
{
|
|
DWORD dwShift = 0;
|
|
DWORD dwBits = 0;
|
|
|
|
if( pdwShift == NULL || pdwBits == NULL )
|
|
return E_INVALIDARG;
|
|
|
|
if( dwBitMask )
|
|
{
|
|
while( (dwBitMask & 1) == 0 )
|
|
{
|
|
dwShift++;
|
|
dwBitMask >>= 1;
|
|
}
|
|
}
|
|
|
|
while( (dwBitMask & 1) != 0 )
|
|
{
|
|
dwBits++;
|
|
dwBitMask >>= 1;
|
|
}
|
|
|
|
*pdwShift = dwShift;
|
|
*pdwBits = dwBits;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|