DirectDraw Tutorial 1
创建窗口并显示图片
一、处理窗口消息和消息泵
下面是一个基本的win32程序,我们的主要工作是修改消息响应和消息泵的结构,该程序包含一个菜单系统,但是并没有对他的消息做任何的响应,注意程序的结构和消息处理。
//This is a simple directdraw window and use ddutil to display a bitmap
//use dx8.0
// main.cpp
#include
<windows.h>
#include
"resource.h"
#include
"comfunc.h" //the file include all necessary function and variables
//if need redraw the window
BOOL g_bActive = FALSE;
//this is a part of window
LRESULT CALLBACK WndProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch(uMsg)
{
//if this window has a menu system you must process WM_PAINT message to
//redraw the area be covered by menu
case WM_PAINT:
// 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( g_pDisplay )
{
//try to display the a next frame
if( Render() == DDERR_SURFACELOST )
{
//if the surfaces were lost, then restore and try again
RestoreSurfaces();
Render();
}
}
break; // Continue with default processing to validate the region
case WM_MOVE:
//the client area of window is changed so we must update it
if( g_pDisplay )
g_pDisplay->UpdateBounds();
return 0;
case WM_SIZE:
//if the window is hide or minimized don't update
if( SIZE_MAXHIDE == wParam || SIZE_MINIMIZED == wParam )
g_bActive = FALSE;
else
g_bActive = TRUE;
if( g_pDisplay )
g_pDisplay->UpdateBounds();
break;
case WM_EXITMENULOOP:
// Ignore time spent in menu
g_dwLastTick = timeGetTime();
break;
case WM_EXITSIZEMOVE:
// Ignore time spent resizing
g_dwLastTick = timeGetTime();
break;
case WM_DESTROY:
// Cleanup and close the app
FreeDirectDraw();
PostQuitMessage(0);
break;
}
return DefWindowProc( hwnd, uMsg, wParam, lParam );
}
int
WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
HWND hwnd;
WNDCLASSEX wc;
//this is a simple WNDCLASSEX structure
memset( &wc, 0, sizeof(wc) );
wc.cbSize = sizeof( wc );
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor( NULL, IDC_ARROW);
wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
wc.lpszMenuName = MAKEINTRESOURCE( IDR_MENU );
wc.lpszClassName = L"DDWindow";
RegisterClassEx( &wc );
//because dimension of the window created by CreateWindowEx function
//include the caption menu and frame,
//so the important thing is resize your window,
DWORD dwFrameWidth = GetSystemMetrics( SM_CXSIZEFRAME );
DWORD dwFrameHeight = GetSystemMetrics( SM_CYSIZEFRAME );
DWORD dwMenuHeight = GetSystemMetrics( SM_CYMENU );
DWORD dwCaptionHeight = GetSystemMetrics( SM_CYCAPTION );
//the actual width and height
DWORD dwWindowWidth = WINDOW_WIDTH + dwFrameWidth * 2;
DWORD dwWindwoHeight = WINDOW_HEIGHT + dwFrameHeight * 2
+ dwMenuHeight + dwCaptionHeight;
hwnd = CreateWindowEx(0, L"DDWindow", L"DirectDraw1-CreateWindow",
WS_OVERLAPPEDWINDOW ,
CW_USEDEFAULT, 0,
dwWindowWidth,
dwWindwoHeight,
NULL, NULL, hInstance, NULL );
ShowWindow( hwnd, nCmdShow);
UpdateWindow( hwnd );
//ok directdraw
if( FAILED( InitDirectDraw( hwnd ) ) )
{
MessageBox( hwnd, TEXT("DirectDraw Init Failed."),
TEXT("DirectDraw1"), MB_ICONERROR | MB_OK );
return false;
}
g_dwLastTick = timeGetTime();
//end
MSG msg;
while(1)
{
// Look for messages, if none are found then
// update the state and display it
if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
if(0 == GetMessage( &msg, NULL, 0, 0 ) )
// WM_QUIT was posted, so exit
return (int)msg.wParam;
// Translate and dispatch the message
TranslateMessage( &msg );
DispatchMessage( &msg );
}
//not message in the thread's queue, so we do our draw things
else
{
if( g_bActive )
{
if( FAILED( Update( hwnd ) ) )
{
SAFE_DELETE( g_pDisplay );
MessageBox( hwnd, TEXT("Update failed."),
TEXT("DirectDraw1"),
MB_ICONERROR | MB_OK );
return FALSE;
}
}
else
{
// Make sure we go to sleep if we have nothing else to do
WaitMessage();
// Ignore time spent inactive
g_dwLastTick = timeGetTime();
}
}
}
return 0;
}
二、DirectDraw初始化和处理函数
#pragma
once
//this file include all important function to draw bitmap in my window
//Class CDisplay and CSurface come from ddutil you can find it in DX8.0
//you can get this head file from dx8.0 sample folder
#include
"../ddutil/ddutil.h"
#include
"../ddutil/dxutil.h"
//timeGetTime()
#pragma
comment(lib, "Winmm.lib")
#pragma
comment( lib, "ddraw" )
#pragma
comment( lib, "dxguid" )
CDisplay* g_pDisplay = NULL;
CSurface* g_pBackground = NULL;
CSurface* g_pLogo = NULL;
#define
WINDOW_WIDTH 800
#define
WINDOW_HEIGHT 600
#define
LOGOWIDTH 128
#define
LOGOHEIGHT 128
DWORD g_dwLastTick;
//d3d8math.h
static
D3DXVECTOR2 dvPos;
static
D3DXVECTOR2 dvVel;
static
float incr = 100;
HRESULT InitDirectDraw( HWND hWnd )
{
LPDIRECTDRAWPALETTE pDDPal = NULL;
HRESULT hr;
g_pDisplay = new CDisplay();
if( FAILED( hr = g_pDisplay->CreateWindowedDisplay( hWnd,
WINDOW_WIDTH, WINDOW_HEIGHT ) ) )
{
MessageBox( hWnd, TEXT("Failed initializeing DirectDraw."),
TEXT("DirectDraw1"), MB_ICONERROR | MB_OK );
return hr;
}
if( FAILED( hr = g_pDisplay->CreatePaletteFromBitmap( &pDDPal, MAKEINTRESOURCE( IDB_BK ) ) ) )
return hr;
g_pDisplay->SetPalette( pDDPal );
SAFE_RELEASE( pDDPal );
// Create a surface, and draw a bitmap resource on it.
if( FAILED( hr = g_pDisplay->CreateSurfaceFromBitmap( &g_pBackground,
MAKEINTRESOURCE( IDB_BK ), WINDOW_WIDTH, WINDOW_HEIGHT )))
return hr;
if( FAILED( hr = g_pDisplay->CreateSurfaceFromBitmap( &g_pLogo,
MAKEINTRESOURCE( IDB_LOGO ), LOGOWIDTH, LOGOHEIGHT )))
return hr;
dvVel.x = 100;
dvVel.y = 100;
return S_OK;
}
VOID FreeDirectDraw()
{
SAFE_DELETE( g_pLogo );
SAFE_DELETE( g_pBackground );
SAFE_DELETE( g_pDisplay );
}
HRESULT Render()
{
HRESULT hr;
g_pDisplay->Clear(0);
//i have changed the name of Blt function to DefBltFast but didn't modify it
g_pDisplay->DefBltFast(0, 0, g_pBackground );
g_pDisplay->DefBltFast(dvPos.x, dvPos.y, g_pLogo );
if( FAILED( hr = g_pDisplay->Present()))
return hr;
return S_OK;
}
HRESULT RestoreSurfaces()
{
LPDIRECTDRAWPALETTE pDDPal = NULL;
HRESULT hr;
if( FAILED( hr = g_pDisplay->GetDirectDraw()->RestoreAllSurfaces()))
return hr;
if( FAILED( hr = g_pDisplay->CreatePaletteFromBitmap( &pDDPal, MAKEINTRESOURCE( IDB_BK ) ) ) )
return hr;
g_pDisplay->SetPalette( pDDPal );
SAFE_RELEASE( pDDPal );
if( FAILED( hr = g_pBackground->DrawBitmap( MAKEINTRESOURCE( IDB_BK ),
WINDOW_WIDTH, WINDOW_HEIGHT ) ) )
return hr;
if( FAILED( hr = g_pLogo->DrawBitmap( MAKEINTRESOURCE( IDB_LOGO ),
LOGOWIDTH, LOGOHEIGHT )))
return hr;
return S_OK;
}
HRESULT Update( HWND hWnd )
{
//::OutputDebugString(TEXT("Update/n"));
HRESULT hr;
DWORD dwCurrTick = timeGetTime();
DWORD dwTickDiff = dwCurrTick - g_dwLastTick;
if( dwTickDiff == 0 ) return S_OK;
g_dwLastTick = dwCurrTick;
dvPos += dvVel * dwTickDiff / 1000.0f;
if( dvPos.x > WINDOW_WIDTH - LOGOWIDTH || dvPos.x < 0 )
{
dvVel.x = - dvVel.x;
dvPos.x += dvVel.x * dwTickDiff / 1000.0f;
}
if( dvPos.y > WINDOW_HEIGHT - LOGOHEIGHT || dvPos.y < 0 )
{
dvVel.y = - dvVel.y;
dvPos.y += dvVel.y * dwTickDiff / 1000.0f;
}
// Check the cooperative level before rendering
if( FAILED( hr = g_pDisplay->GetDirectDraw()->TestCooperativeLevel()))
{
switch( hr )
{
case DDERR_EXCLUSIVEMODEALREADYSET:
Sleep( 10 );
return S_OK;
case DDERR_WRONGMODE:
FreeDirectDraw();
return InitDirectDraw( hWnd );
}
return hr;
}
if( FAILED( hr = Render() ) )
{
if( hr != DDERR_SURFACELOST )
return hr;
RestoreSurfaces();
}
return S_OK;
}