#include <windows.h>
#include <tchar.h>
#include <ddraw.h>
#include <dinput.h>
#include <dmusicc.h>
#include <dmusici.h>
#include "ddutil.h"
static TCHAR szErrorBuf[512], szMessage[256];
void DisplayError(LPCTSTR szFile, int nLine, HRESULT hResult, LPCTSTR lpMessage)
{
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, hResult, 0, szMessage,
sizeof(szMessage) / sizeof(TCHAR), NULL);
wsprintf(szErrorBuf, _T("%s\nFile %s, line %d, error code 0x%08X: %s"),
lpMessage, szFile, nLine, hResult, szMessage);
OutputDebugString(szErrorBuf);
MessageBox(NULL, szErrorBuf, _T("Error"), MB_OK);
}
void DisplayError(LPCTSTR lpMessage)
{
OutputDebugString(szErrorBuf);
MessageBox(NULL, szErrorBuf, _T("Error"), MB_OK);
}
#define DISPLAYERROR(h, s)\
DisplayError(__FILE__, __LINE__, h, _T(s))
#define DISPLAYLASTERROR(s)\
DisplayError(__FILE__, __LINE__, GetLastError(), _T(s))
IDirectMusicPerformance8 *g_pPerformance;
IDirectMusicLoader8 *g_pLoader;
IDirectMusicSegment8 *g_pBackgroundMusic;
BOOL InitDirectMusic()
{
HRESULT h;
::CoInitialize(NULL);
h = ::CoCreateInstance(CLSID_DirectMusicPerformance, NULL,
CLSCTX_INPROC, IID_IDirectMusicPerformance8,
(void **)&g_pPerformance);
if (FAILED(h))
{
DISPLAYERROR(h, "DirectMusic could not be initialised. DirectX 8 may not be installed.");
return FALSE;
}
h = g_pPerformance->InitAudio(NULL, NULL, NULL,
DMUS_APATH_SHARED_STEREOPLUSREVERB,
64, DMUS_AUDIOF_ALL, NULL);
if (FAILED(h))
{
DISPLAYERROR(h, "DirectX Audio could not be initialised. Check for low memory or low system resources.");
return FALSE;
}
h = ::CoCreateInstance(CLSID_DirectMusicLoader, NULL,
CLSCTX_INPROC, IID_IDirectMusicLoader8,
(void **)&g_pLoader);
if (FAILED(h))
{
DISPLAYERROR(h, "DirectX Audio could not be initialised. Check for low memory or low system resources.");
return FALSE;
}
h = g_pLoader->LoadObjectFromFile(CLSID_DirectMusicSegment,
IID_IDirectMusicSegment8, L"passport.mid", (void **) &g_pBackgroundMusic);
if (FAILED(h))
{
DISPLAYERROR(h, "Background music could not be loaded.");
return FALSE;
}
g_pBackgroundMusic->SetParam(GUID_StandardMIDIFile,
0xFFFFFFFF, DMUS_SEG_ALLTRACKS, 0, NULL);
g_pBackgroundMusic->SetRepeats(DMUS_SEG_REPEAT_INFINITE);
g_pBackgroundMusic->Download(g_pPerformance);
return TRUE;
}
void PlayMusic()
{
g_pPerformance->PlaySegment(g_pBackgroundMusic, DMUS_SEGF_AFTERPREPARETIME, 0, NULL);
}
void StopMusic()
{
g_pPerformance->Stop(NULL, NULL, 0, 0);
}
void ExitDirectMusic()
{
if (g_pBackgroundMusic)
{
g_pBackgroundMusic->Release();
g_pBackgroundMusic = NULL;
}
if (g_pPerformance)
{
g_pPerformance->CloseDown();
g_pPerformance->Release();
g_pPerformance = NULL;
}
if (g_pLoader)
{
g_pLoader->Release();
g_pLoader = NULL;
}
}
GUID g_guidApp =
{ 0xbd0e8406, 0xfb56, 0x4322, { 0x8b, 0xc6, 0xbd, 0x6e, 0x48, 0x1f, 0x55, 0x64 } };
DWORD g_dwGenre = DIVIRTUAL_ARCADE_SIDE2SIDE;
LPCTSTR g_tszActionMapName = _T("Sample");
enum Actions
{
ACTIONS_LEFTRIGHT,
ACTIONS_LEFT,
ACTIONS_RIGHT,
ACTIONS_QUIT,
ACTIONS_NONE
};
bool g_bQuit;
bool g_bLeft, g_bRight;
DIACTION g_rgActions[] =
{
{ ACTIONS_LEFTRIGHT, DIAXIS_ARCADES_LATERAL, 0, "Left/Right" },
{ ACTIONS_LEFT, DIKEYBOARD_LEFT, 0, "Left" },
{ ACTIONS_RIGHT, DIKEYBOARD_RIGHT, 0, "Right" },
{ ACTIONS_QUIT, DIKEYBOARD_ESCAPE, 0, "Quit" },
};
DWORD g_nActions = sizeof(g_rgActions) / sizeof(DIACTION);
BOOL InitDirectInput();
void ExitDirectInput();
void AcquireDevices();
void UnacquireDevices();
void CheckInput();
HWND hWndMain;
IDirectDraw7 *pDD;
IDirectDrawSurface7 *lpPrimary, *lpBackBuffer;
BOOL g_bActive = FALSE;
IDirectDrawSurface7 *lpA;
IDirectDrawSurface7 *lpSprites;
void ExitDirectDraw();
BOOL InitDirectDraw()
{
HRESULT h;
h = DirectDrawCreateEx(NULL, (void **)&pDD, IID_IDirectDraw7, NULL);
if (FAILED(h))
{
DISPLAYERROR(h, "DirectDraw could not be initialised. Check for low memory or low system resources.");
return FALSE;
}
pDD->SetCooperativeLevel(hWndMain,
DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT);
if (FAILED(h))
{
ExitDirectDraw();
DISPLAYERROR(h, "DirectDraw could not be initialised. Check for low memory or low system resources.");
return FALSE;
}
h = pDD->SetDisplayMode(640, 480, 16, 0, 0);
if (FAILED(h))
{
ExitDirectDraw();
DISPLAYERROR(h, "This graphics card does not support 640x480 in 16-bit colour.");
return FALSE;
}
DDSURFACEDESC2 ddsd;
ZeroMemory(&ddsd, sizeof(DDSURFACEDESC2));
ddsd.dwSize = sizeof(DDSURFACEDESC2);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_FLIP |
DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 2;
h = pDD->CreateSurface(&ddsd, &lpPrimary, NULL);
if (FAILED(h))
{
ExitDirectDraw();
DISPLAYERROR(h, "This graphics card does not have enough video memory.");
return FALSE;
}
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
lpPrimary->GetAttachedSurface(&ddsd.ddsCaps, &lpBackBuffer);
lpA = DDLoadBitmap(pDD, "a.bmp", 0, 0);
if (lpA == NULL)
{
ExitDirectDraw();
DisplayError(_T("Could not load background image."));
return FALSE;
}
lpSprites = DDLoadBitmap(pDD, "sprites.bmp", 0, 0);
if (lpA == NULL)
{
ExitDirectDraw();
DisplayError(_T("Could not load sprites."));
return FALSE;
}
DDSetColorKey(lpSprites, RGB(255, 0, 255));
return TRUE;
}
void ExitDirectDraw()
{
lpSprites->Release();
lpSprites = NULL;
lpA->Release();
lpA = NULL;
lpPrimary->Release();
lpPrimary = NULL;
pDD->Release();
pDD = NULL;
}
void RestoreAllSurfaces()
{
pDD->RestoreAllSurfaces();
DDReLoadBitmap(lpA, "a.bmp");
DDReLoadBitmap(lpSprites, "sprites.bmp");
}
BOOL BackBlt(int x, int y, IDirectDrawSurface7 *lpSurf, LPCRECT pRect, DWORD dwFlags)
{
HRESULT h;
RECT rc = *pRect;
if ((x > 640) || (y > 480))
return TRUE;
if (x < 0)
{ rc.left -= x;
x = 0;
}
if (y < 0)
{ rc.top -= y;
y = 0;
}
if (rc.left < 0)
rc.left = 0;
if (rc.top < 0)
rc.top = 0;
if ((x + rc.right - rc.left) > 640)
rc.right -= (x + rc.right - rc.left) - 640;
if ((y + rc.bottom - rc.top) > 480)
rc.bottom -= (y + rc.bottom - rc.top) - 480;
if ((rc.right <= rc.left) || (rc.bottom <= rc.top))
return TRUE;
h = lpBackBuffer->BltFast(x, y, lpSurf, &rc, dwFlags);
if (h == DDERR_SURFACELOST)
{ RestoreAllSurfaces();
h = lpBackBuffer->BltFast(x, y, lpSurf, &rc, dwFlags);
}
if (h != DD_OK)
return FALSE;
return TRUE;
}
LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
StopMusic();
UnacquireDevices();
ExitDirectDraw();
ExitDirectInput();
ExitDirectMusic();
DestroyWindow(hWnd);
return 0;
case WM_SETCURSOR:
SetCursor(NULL);
return 0;
case WM_ACTIVATE:
if (LOWORD(wParam) == WA_INACTIVE)
{
g_bActive = FALSE;
UnacquireDevices();
}
else
{
g_bActive = TRUE;
AcquireDevices();
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
void RegisterWindowClass()
{
WNDCLASSEX wcx;
ZeroMemory(&wcx, sizeof(WNDCLASSEX));
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = MainWindowProc;
wcx.hInstance = GetModuleHandle(NULL);
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = NULL;
wcx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcx.lpszMenuName = NULL;
wcx.lpszClassName = "SampleWindowClass";
RegisterClassEx(&wcx);
}
#define AXIS_THRESHOLD 20
void HandleAction(UINT nAction, DWORD dwData)
{
int nAxisPos = (int)dwData;
switch (nAction)
{
case ACTIONS_LEFTRIGHT:
if (nAxisPos < -AXIS_THRESHOLD)
{
g_bLeft = true;
g_bRight = false;
}
else if (nAxisPos > AXIS_THRESHOLD)
{
g_bRight = true;
g_bLeft = false;
}
else
{
g_bLeft = g_bRight = false;
}
break;
case ACTIONS_LEFT:
g_bLeft = (dwData != 0);
break;
case ACTIONS_RIGHT:
g_bRight = (dwData != 0);
break;
case ACTIONS_QUIT:
g_bQuit = true;
break;
default:
break;
}
}
void OnIdle(void)
{
if (lpPrimary == NULL)
return;
if (!g_bActive)
return;
CheckInput();
if (g_bQuit)
{
PostMessage(hWndMain, WM_CLOSE, 0, 0);
return;
}
RECT r;
r.left = 0;
r.top = 0;
r.right = 640;
r.bottom = 480;
BackBlt(0, 0, lpA, &r,
DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT);
r.left = 128;
r.top = 0;
r.right = 192;
r.bottom = 64;
BackBlt(288, 208, lpSprites, &r,
DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);
static int x;
x++;
if (x > 100)
x = -100;
r.left = 0;
r.right = 64;
BackBlt(288 + x, 100, lpSprites, &r,
DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);
static int xSprite;
if (g_bLeft)
xSprite--;
if (g_bRight)
xSprite++;
r.left = 64;
r.right = 128;
BackBlt(288 + xSprite, 150, lpSprites, &r,
DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);
lpPrimary->Flip(NULL, DDFLIP_WAIT);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
MSG msg;
RegisterWindowClass();
hWndMain = CreateWindowEx(WS_EX_APPWINDOW,
"SampleWindowClass", "DirectDraw Sprites Sample", WS_POPUP,
0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
NULL, NULL, hInstance, NULL);
if (hWndMain == NULL)
{
DisplayError(_T("Could not create window."));
return 1;
}
ShowWindow(hWndMain, SW_SHOW);
if (!InitDirectMusic())
return 1;
if (!InitDirectInput())
{
DisplayError(_T("Failed to initialise DirectInput."));
ExitDirectMusic();
return 1;
}
if (!InitDirectDraw())
{
ExitDirectInput();
ExitDirectMusic();
return 1;
}
AcquireDevices();
PlayMusic();
for (;;)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!GetMessage(&msg, NULL, 0, 0))
break;
DispatchMessage(&msg);
}
OnIdle();
}
return 0;
}