home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
msdn_vcb
/
samples
/
vc98
/
sdk
/
graphics
/
directx
/
misc
/
rmfull.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1997-07-14
|
36KB
|
1,165 lines
/*
* Copyright (C) 1995, 1996 Microsoft Corporation. All Rights Reserved.
*
* File: rmfull.cpp
*
* Each of the Direct3D retained mode (D3DRM) samples may be linked with
* this file. It contains the code which allows them to run in the Windows
* environment as a window or fullscreen. It is a modified version of
* d3dmain.cpp. Comparing these two files is instructive.
*
* A window is created using rmfull.res which allows the user to select the
* Direct3D driver to use and change the render options. The D3DApp
* collection of functions is used to initialize DirectDraw, Direct3D and
* keep surfaces and D3D devices available for rendering.
*
* Frame rate and a screen mode information buffer is Blt'ed to the screen
* by functions in rmstats.cpp.
*
* Individual samples are executed through two functions, BuildScene and
* OverrideDefaults, as described in rmdemo.h. Samples can also read
* mouse input via ReadMouse.
*/
#include "rmfull.h"
#include <stdarg.h>
/*
* GLOBAL VARIABLES
*/
D3DAppInfo* d3dapp; /* Pointer to read only collection of DD and D3D
objects maintained by D3DApp */
rmfullglobals myglobs; /* collection of global variables */
LPDIRECT3DRM lpD3DRM; /* Direct3DRM object */
/*
* INTERNAL FUNCTION PROTOTYPES
*/
static BOOL AppInit(HINSTANCE hInstance, LPSTR lpCmdLine);
static BOOL CreateD3DApp(LPSTR lpCmdLine);
static BOOL BeforeDeviceDestroyed(LPVOID lpContext);
static BOOL AfterDeviceCreated(int w, int h, LPDIRECT3DVIEWPORT* lpViewport,
LPVOID lpContext);
void CleanUpAndPostQuit(void);
static void InitGlobals(void);
static BOOL AppPause(BOOL f);
void ReportD3DAppError(void);
static BOOL RenderLoop(void);
static BOOL RestoreSurfaces();
long FAR PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam );
extern "C" void ReadMouse(int*, int*, int*);
extern "C" char* D3DRMErrorToString(HRESULT error);
BOOL CreateD3DRM(HWND win);
BOOL SetRenderState(void);
/****************************************************************************/
/* WinMain */
/****************************************************************************/
/*
* Initializes the application then enters a message loop which calls sample's
* RenderScene until a quit message is received.
*/
int PASCAL
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
{
int failcount = 0; /* number of times RenderLoop has failed */
MSG msg;
HACCEL hAccelApp;
hPrevInstance;
/*
* Create the window and initialize all objects needed to begin rendering
*/
if(!AppInit(hInstance, lpCmdLine))
return FALSE;
hAccelApp = LoadAccelerators(hInstance, "AppAccel");
while (!myglobs.bQuit) {
/*
* Monitor the message queue until there are no pressing
* messages
*/
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
CleanUpAndPostQuit();
break;
}
if (!myglobs.hWndMain || !TranslateAccelerator(myglobs.hWndMain,
hAccelApp, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/*
* If the app is not minimized, not about to quit, not paused, either the
* active fullscreen app or in a window and D3D has been initialized,
* we can render
*/
} else if (d3dapp->bRenderingIsOK && !d3dapp->bMinimized
&& !d3dapp->bPaused && !myglobs.bQuit
&& (d3dapp->bAppActive || !d3dapp->bFullscreen)) {
/*
* If were are not in single step mode or if we are and the
* bDrawAFrame flag is set, render one frame
*/
if (!(myglobs.bSingleStepMode && !myglobs.bDrawAFrame)) {
/*
* Attempt to render a frame, if it fails, take a note. If
* rendering fails more than twice, abort execution.
*/
if (!RenderLoop()) {
++failcount;
if (failcount == 3) {
Msg("Rendering has failed too many times. Aborting execution.\n");
CleanUpAndPostQuit();
break;
}
}
}
/*
* Reset the bDrawAFrame flag if we are in single step mode
*/
if (myglobs.bSingleStepMode)
myglobs.bDrawAFrame = FALSE;
} else {
WaitMessage();
}
}
DestroyWindow(myglobs.hWndMain);
return msg.wParam;
}
/****************************************************************************/
/* D3DApp Initialization and callback functions */
/****************************************************************************/
/*
* AppInit
* Creates the window and initializes all objects necessary to begin rendering
*/
static BOOL
AppInit(HINSTANCE hInstance, LPSTR lpCmdLine)
{
WNDCLASS wc;
HMENU hmenu;
DWORD flags;
int i;
Defaults defaults;
/*
* Register the window class
*/
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( hInstance, "AppIcon");
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = "AppMenu";
wc.lpszClassName = "Example";
if (!RegisterClass(&wc))
return FALSE;
/*
* Initialize the global variables and allow the sample code to override
* some of these default settings.
*/
InitGlobals();
myglobs.hInstApp = hInstance;
defaults.bNoTextures = myglobs.bNoTextures;
defaults.bConstRenderQuality = myglobs.bConstRenderQuality;
defaults.bResizingDisabled = FALSE;
lstrcpy(defaults.Name, "D3DRM Example");
OverrideDefaults(&defaults);
myglobs.bNoTextures = defaults.bNoTextures;
myglobs.bConstRenderQuality = defaults.bConstRenderQuality;
myglobs.lpCmdLine = lpCmdLine;
/*
* Enumerate the DD drivers
*/
if (!D3DAppEnumerateDDDevices(&myglobs.NumDDDrivers, &myglobs.DDDriver[0])) {
ReportD3DAppError();
return FALSE;
}
/*
* Choose the last device enumerated which will probably be secondary 3d hardware.
*/
myglobs.CurrDDDriver = myglobs.NumDDDrivers - 1;
/*
* Create the window
*/
if (defaults.bResizingDisabled)
flags = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
else
flags = WS_OVERLAPPEDWINDOW;
/*
* Create a window with some default settings that may change
*/
myglobs.hWndMain = CreateWindowEx(
WS_EX_APPWINDOW,
"Example",
defaults.Name,
flags,
CW_USEDEFAULT, CW_USEDEFAULT,
START_WIN_SIZE, START_WIN_SIZE,
NULL, /* parent window */
NULL, /* menu handle */
hInstance, /* program handle */
NULL); /* create parms */
if (!myglobs.hWndMain){
Msg("CreateWindowEx failed");
return FALSE;
}
/*
* Display the window
*/
ShowWindow(myglobs.hWndMain, SW_SHOWNORMAL);
UpdateWindow(myglobs.hWndMain);
/*
* Add the list of DD drivers D3DApp found to the file menu
*/
hmenu = GetSubMenu(GetMenu(myglobs.hWndMain), 0);
for (i = 0; i < myglobs.NumDDDrivers; i++) {
InsertMenu(hmenu, 6 + i, MF_BYPOSITION | MF_STRING,
MENU_FIRST_DDDRIVER + i, myglobs.DDDriver[i].Name);
}
/*
* Create the D3DRM object which are initialized only when the program
* starts
*/
if (!CreateD3DRM(myglobs.hWndMain))
return FALSE;
/*
* Call D3DApp to initialize all DD and D3D objects necessary to render.
* D3DApp will call the device creation callback which will initialize the
* viewport and the sample's execute buffers.
*/
if (!CreateD3DApp(lpCmdLine))
return FALSE;
/*
* Create the scene to be rendered by calling this sample's BuildScene
*/
if (!BuildScene(myglobs.dev, myglobs.view, myglobs.scene, myglobs.camera))
return FALSE;
return TRUE;
}
/*
* CreateD3DRM
* Create main D3DRM objects which are only initialized once.
*/
BOOL
CreateD3DRM(HWND win)
{
HRESULT rval;
/*
* Create the D3DRM object
*/
rval = Direct3DRMCreate(&lpD3DRM);
if (rval != D3DRM_OK) {
Msg("Failed to create Direct3DRM.\n%s", D3DAppErrorToString(rval));
return FALSE;
}
/*
* Create the master scene frame and camera frame
*/
rval = lpD3DRM->CreateFrame(NULL, &myglobs.scene);
if (rval != D3DRM_OK) {
Msg("Failed to create the master scene frame.\n%s", D3DAppErrorToString(rval));
return FALSE;
}
rval = lpD3DRM->CreateFrame(myglobs.scene, &myglobs.camera);
if (rval != D3DRM_OK) {
Msg("Failed to create the camera's frame.\n%s", D3DAppErrorToString(rval));
return FALSE;
}
rval = myglobs.camera->SetPosition(myglobs.scene, D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0));
if (rval != D3DRM_OK) {
Msg("Failed to position the camera in the frame.\n%s", D3DAppErrorToString(rval));
return FALSE;
}
return TRUE;
}
/*
* CreateD3DApp
* Create all DirectDraw and Direct3D objects necessary to begin rendering.
* Add the list of D3D drivers to the file menu.
*/
static BOOL
CreateD3DApp(LPSTR lpCmdLine)
{
HMENU hmenu;
int i;
LPSTR option;
BOOL bOnlySystemMemory, bOnlyEmulation;
DWORD flags;
/*
* Parse the command line in seach of one of the following options:
* systemmemory All surfaces should be created in system memory.
* Hardware DD and D3D devices are disabled, but
* debugging during the Win16 lock becomes possible.
* emulation Do not use hardware DD or D3D devices.
*/
bOnlySystemMemory = FALSE;
bOnlyEmulation = FALSE;
option = strtok(lpCmdLine, " -");
while(option != NULL ) {
if (!lstrcmp(option, "systemmemory")) {
bOnlySystemMemory = TRUE;
} else if (!lstrcmp(option, "emulation")) {
bOnlyEmulation = TRUE;
} else {
Msg("Invalid command line options given.\nLegal options: -systemmemory, -emulation\n");
return FALSE;
}
option = strtok(NULL, " -");
}
/*
* Set the flags to pass to the D3DApp creation based on command line
*/
flags = ((bOnlySystemMemory) ? D3DAPP_ONLYSYSTEMMEMORY : 0) |
((bOnlyEmulation) ? (D3DAPP_ONLYD3DEMULATION |
D3DAPP_ONLYDDEMULATION) : 0);
/*
* Create all the DirectDraw and D3D objects neccesary to render. The
* AfterDeviceCreated callback function is called by D3DApp to create the
* viewport and the example's execute buffers.
*/
if (!D3DAppCreateFromHWND(flags, myglobs.hWndMain,
myglobs.DDDriver[myglobs.CurrDDDriver].bIsPrimary ? NULL : &myglobs.DDDriver[myglobs.CurrDDDriver].Guid,
AfterDeviceCreated, NULL, BeforeDeviceDestroyed, NULL, &d3dapp)) {
ReportD3DAppError();
return FALSE;
}
/*
* Add the the list of display modes D3DApp found to the mode menu
*/
hmenu = GetSubMenu(GetMenu(myglobs.hWndMain), 2);
for (i = 0; i < d3dapp->NumModes; i++) {
char ach[80];
wsprintf(ach,"%dx%dx%d", d3dapp->Mode[i].w, d3dapp->Mode[i].h,
d3dapp->Mode[i].bpp);
AppendMenu(hmenu, MF_STRING, MENU_FIRST_MODE+i, ach);
}
/*
* Add the list of D3D drivers D3DApp foudn to the file menu
*/
hmenu = GetSubMenu(GetMenu(myglobs.hWndMain), 0);
for (i = 0; i < d3dapp->NumDrivers; i++) {
InsertMenu(hmenu, 7 + myglobs.NumDDDrivers + i, MF_BYPOSITION | MF_STRING,
MENU_FIRST_DRIVER + i, d3dapp->Driver[i].Name);
}
return TRUE;
}
/*
* DestroyD3DApp
*
* Destroy D3DApp and changes to menu
*/
static void
DestroyD3DApp(void)
{
HMENU hmenu;
int i;
/*
* Remove the list of display modes
*/
hmenu = GetSubMenu(GetMenu(myglobs.hWndMain), 4);
for (i = 0; i < d3dapp->NumModes; i++) {
DeleteMenu(hmenu, MENU_FIRST_MODE + i, MF_BYCOMMAND);
}
/*
* Remove the list of D3D drivers
*/
hmenu = GetSubMenu(GetMenu(myglobs.hWndMain), 0);
for (i = 0; i < d3dapp->NumDrivers; i++) {
DeleteMenu(hmenu, MENU_FIRST_DRIVER + i, MF_BYCOMMAND);
}
RELEASE(myglobs.lpInfoBuffer);
RELEASE(myglobs.lpFrameRateBuffer);
D3DAppDestroy();
}
/*
* AfterDeviceCreated
* D3DApp will call this function immediately after the D3D device has been
* created (or re-created). D3DApp expects the D3D viewport to be created and
* returned. In this case, we will return NULL because we only have a D3DRM
* viewport. This is fine as long as we don't use any of the D3D viewport
* functionality of D3DApp.
*/
static BOOL
AfterDeviceCreated(int w, int h, LPDIRECT3DVIEWPORT* lplpViewport, LPVOID lpContext)
{
HRESULT rval;
rval = lpD3DRM->CreateDeviceFromD3D(d3dapp->lpD3D, d3dapp->lpD3DDevice,
&myglobs.dev);
if (rval != D3DRM_OK) {
Msg("Creation of D3DRM device failed.\n%s", D3DAppErrorToString(rval));
return FALSE;
}
/*
* Create the D3DRM viewport using the camera frame. Set the background
* depth to a large number. The width and height may be slightly
* adjusted, so get them from the device to be sure.
*/
w = myglobs.dev->GetWidth();
h = myglobs.dev->GetHeight();
rval = lpD3DRM->CreateViewport(myglobs.dev, myglobs.camera, 0, 0, w,
h, &myglobs.view);
if (rval != D3DRM_OK) {
Msg("Failed to create the D3DRM viewport.\n%s",
D3DAppErrorToString(rval));
RELEASE(myglobs.dev);
return FALSE;
}
rval = myglobs.view->SetBack(D3DVAL(5000.0));
if (rval != D3DRM_OK) {
Msg("Failed to set the background depth of the D3DRM viewport.\n%s",
D3DAppErrorToString(rval));
RELEASE(myglobs.dev);
RELEASE(myglobs.view);
return FALSE;
}
/*
* Set the render quality, fill mode, lighting state and color shade info
*/
if (!SetRenderState())
return FALSE;
/*
* Return NULL for the viewport
*/
*lplpViewport = NULL;
/*
* Create and initialize the surfaces containing the frame rate and
* window information
*/
InitFontAndTextBuffers();
return TRUE;
}
/*
* BeforeDeviceDestroyed
* D3DApp will call this function before the current D3D device is destroyed
* to give the app the opportunity to destroy objects it has created with the
* DD or D3D objects.
*/
static BOOL
BeforeDeviceDestroyed(LPVOID lpContext)
{
RELEASE(myglobs.view);
RELEASE(myglobs.dev);
return TRUE;
}
/****************************************************************************/
/* Rendering loop */
/****************************************************************************/
/*
* RenderLoop
* Render the next frame and update the window
*/
static BOOL
RenderLoop()
{
D3DRECT extents[D3DAPP_MAXCLEARRECTS];
int count;
HRESULT rval;
static BOOL b = FALSE; // Clear the second buffer on also
/*
* If all the DD and D3D objects have been initialized we can render
*/
if (d3dapp->bRenderingIsOK) {
/*
* Restore any lost surfaces
*/
if (!RestoreSurfaces()) {
/*
* Restoring surfaces sometimes fails because the surfaces cannot
* yet be restored. If this is the case, the error will show up
* somewhere else and we should return success here to prevent
* unnecessary error's being reported.
*/
return TRUE;
}
/*
* Force an update of the entire client window if the resized flag is set
*/
if (myglobs.bResized || b)
myglobs.view->ForceUpdate(0, 0, d3dapp->szClient.cx, d3dapp->szClient.cy);
/*
* Use b to makesure the second buffer is cleared also
*/
if (b)
b = FALSE;
if (myglobs.bResized)
b = TRUE;
/*
* Calculate the frame rate
*/
if (!CalculateFrameRate())
return FALSE;
/*
* Tick the scene
*/
rval = myglobs.scene->Move(D3DVAL(1.0));
if (rval != D3DRM_OK) {
Msg("Moving scene failed.\n%s", D3DAppErrorToString(rval));
return FALSE;
}
/*
* Clear the viewport
*/
rval = myglobs.view->Clear();
if (rval != D3DRM_OK) {
Msg("Clearing viewport failed.\n%s", D3DAppErrorToString(rval));
return FALSE;
}
/*
* Render the scene to the viewport
*/
rval = myglobs.view->Render(myglobs.scene);
if (rval != D3DRM_OK) {
Msg("Rendering scene failed.\n%s", D3DAppErrorToString(rval));
return FALSE;
}
/*
* Blt the frame rate and window stat text to the back buffer
*/
count = 0;
if (!DisplayFrameRate(&count, &extents[0]))
return FALSE;
for (;count;--count)
myglobs.view->ForceUpdate(extents[count-1].x1, extents[count-1].y1,
extents[count-1].x2, extents[count-1].y2);
/*
* Update the window
*/
rval = myglobs.dev->Update();
if (rval != D3DRM_OK) {
Msg("Updating device failed.\n%s", D3DAppErrorToString(rval));
return FALSE;
}
/*
* Blt or flip the back buffer to the front buffer. If this fails,
* don't report an error.
*/
D3DAppShowBackBuffer(myglobs.bResized ? D3DAPP_SHOWALL : NULL);
/*
* Reset the resize flag
*/
myglobs.bResized = FALSE;
}
return TRUE;
}
/*
* AppPause
* Pause and unpause the application
*/
static BOOL
AppPause(BOOL f)
{
/*
* Flip to the GDI surface and halt rendering
*/
if (!D3DAppPause(f))
return FALSE;
/*
* When returning from a pause, reset the frame rate count
*/
if (!f) {
ResetFrameRate();
myglobs.bResized = TRUE;
}
return TRUE;
}
/*
* RestoreSurfaces
* Restores any lost surfaces. Returns TRUE if all surfaces are not lost and
* FALSE if one or more surfaces is lost and can not be restored at the
* moment.
*/
static BOOL
RestoreSurfaces()
{
HRESULT d3drval;
/*
* Have D3DApp check all the surfaces it's in charge of
*/
if (!D3DAppCheckForLostSurfaces()) {
return FALSE;
}
/*
* Check frame rate and info surfaces and re-write them if they
* were lost.
*/
if (myglobs.lpFrameRateBuffer->IsLost() == DDERR_SURFACELOST) {
d3drval = myglobs.lpFrameRateBuffer->Restore();
if (d3drval != DD_OK) {
return FALSE;
}
if (!WriteFrameRateBuffer(0.0f, 0))
return FALSE;
}
if (myglobs.lpInfoBuffer->IsLost() == DDERR_SURFACELOST) {
d3drval = myglobs.lpInfoBuffer->Restore();
if (d3drval != DD_OK) {
return FALSE;
}
if (!WriteInfoBuffer())
return FALSE;
}
return TRUE;
}
/*************************************************************************
Windows message handlers
*************************************************************************/
/*
* AppAbout
* About box message handler
*/
BOOL
FAR PASCAL AppAbout(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
if (LOWORD(wParam) == IDOK)
EndDialog(hwnd, TRUE);
break;
case WM_INITDIALOG:
return TRUE;
}
return FALSE;
}
/*
* WindowProc
* Main window message handler.
*/
long
FAR PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam )
{
int i;
BOOL bStop;
LRESULT lresult;
/*
* Give D3DApp an opportunity to process any messages it MUST see in order
* to perform it's function.
*/
if (!D3DAppWindowProc(&bStop, &lresult, hWnd, message, wParam, lParam)) {
ReportD3DAppError();
CleanUpAndPostQuit();
return 0;
}
/*
* If bStop is set by D3DApp, the app should not process the message but
* return lresult.
*/
if (bStop)
return lresult;
if (!d3dapp || !d3dapp->bRenderingIsOK) {
return DefWindowProc(hWnd, message, wParam, lParam);
}
switch( message ) {
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
/*
* Record the mouse state for ReadMouse
*/
myglobs.mouse_buttons = wParam;
myglobs.mouse_x = LOWORD(lParam);
myglobs.mouse_y = HIWORD(lParam);
break;
case WM_ENTERMENULOOP:
AppPause(TRUE);
break;
case WM_EXITMENULOOP:
AppPause(FALSE);
break;
case WM_DESTROY:
myglobs.hWndMain = NULL;
CleanUpAndPostQuit();
break;
case WM_INITMENUPOPUP:
/*
* Check and enable the appropriate menu items
*/
CheckMenuItem((HMENU)wParam, MENU_STEP, (myglobs.bSingleStepMode) ? MF_CHECKED : MF_UNCHECKED);
EnableMenuItem((HMENU)wParam, MENU_GO, (myglobs.bSingleStepMode) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem((HMENU)wParam, MENU_PHONG, MF_GRAYED);
if (!myglobs.bConstRenderQuality) {
CheckMenuItem((HMENU)wParam, MENU_LIGHTING, (myglobs.RenderQuality & D3DRMLIGHT_MASK) == D3DRMLIGHT_ON ? MF_CHECKED : MF_GRAYED);
CheckMenuItem((HMENU)wParam, MENU_FLAT, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_FLAT ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem((HMENU)wParam, MENU_GOURAUD, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_GOURAUD ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem((HMENU)wParam, MENU_PHONG, (myglobs.RenderQuality & D3DRMSHADE_MASK) == D3DRMSHADE_PHONG ? MF_CHECKED : MF_UNCHECKED);
EnableMenuItem((HMENU)wParam, MENU_PHONG, MF_GRAYED);
CheckMenuItem((HMENU)wParam, MENU_POINT, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_POINTS ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem((HMENU)wParam, MENU_WIREFRAME, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_WIREFRAME ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem((HMENU)wParam, MENU_SOLID, (myglobs.RenderQuality & D3DRMFILL_MASK) == D3DRMFILL_SOLID ? MF_CHECKED : MF_UNCHECKED);
} else {
EnableMenuItem((HMENU)wParam, MENU_LIGHTING, MF_GRAYED);
EnableMenuItem((HMENU)wParam, MENU_FLAT, MF_GRAYED);
EnableMenuItem((HMENU)wParam, MENU_GOURAUD, MF_GRAYED);
EnableMenuItem((HMENU)wParam, MENU_PHONG, MF_GRAYED);
EnableMenuItem((HMENU)wParam, MENU_POINT, MF_GRAYED);
EnableMenuItem((HMENU)wParam, MENU_WIREFRAME, MF_GRAYED);
EnableMenuItem((HMENU)wParam, MENU_SOLID, MF_GRAYED);
}
if (!myglobs.bNoTextures && d3dapp->ThisDriver.bDoesTextures) {
CheckMenuItem((HMENU)wParam, MENU_POINT_FILTER, (myglobs.TextureQuality == D3DRMTEXTURE_NEAREST) ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem((HMENU)wParam, MENU_LINEAR_FILTER, (myglobs.TextureQuality == D3DRMTEXTURE_LINEAR) ? MF_CHECKED : MF_UNCHECKED);
} else {
EnableMenuItem((HMENU)wParam, MENU_POINT_FILTER, MF_GRAYED);
EnableMenuItem((HMENU)wParam, MENU_LINEAR_FILTER, MF_GRAYED);
}
CheckMenuItem((HMENU)wParam, MENU_DITHERING, (myglobs.bDithering) ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem((HMENU)wParam, MENU_ANTIALIAS, (myglobs.bAntialiasing) ? MF_CHECKED : MF_UNCHECKED);
EnableMenuItem((HMENU)wParam, MENU_ANTIALIAS, MF_GRAYED);
if (d3dapp->bIsPrimary) {
CheckMenuItem((HMENU)wParam, MENU_FULLSCREEN, d3dapp->bFullscreen ? MF_CHECKED : MF_UNCHECKED);
EnableMenuItem((HMENU)wParam, MENU_FULLSCREEN, d3dapp->bFullscreen && !d3dapp->ThisDriver.bCanDoWindow ? MF_GRAYED : MF_ENABLED);
EnableMenuItem((HMENU)wParam, MENU_NEXT_MODE, (!d3dapp->bFullscreen) ? MF_GRAYED : MF_ENABLED);
EnableMenuItem((HMENU)wParam, MENU_PREVIOUS_MODE, (!d3dapp->bFullscreen) ? MF_GRAYED : MF_ENABLED);
} else {
EnableMenuItem((HMENU)wParam, MENU_FULLSCREEN, MF_GRAYED);
EnableMenuItem((HMENU)wParam, MENU_NEXT_MODE, MF_GRAYED);
EnableMenuItem((HMENU)wParam, MENU_PREVIOUS_MODE, MF_GRAYED);
}
for (i = 0; i < d3dapp->NumModes; i++) {
CheckMenuItem((HMENU)wParam, MENU_FIRST_MODE + i, (i == d3dapp->CurrMode) ? MF_CHECKED : MF_UNCHECKED);
EnableMenuItem((HMENU)wParam, MENU_FIRST_MODE + i, (d3dapp->Mode[i].bThisDriverCanDo) ? MF_ENABLED : MF_GRAYED);
}
for (i = 0; i < d3dapp->NumDrivers; i++) {
CheckMenuItem((HMENU)wParam, MENU_FIRST_DRIVER + i, (i == d3dapp->CurrDriver) ? MF_CHECKED : MF_UNCHECKED);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case MENU_ABOUT:
AppPause(TRUE);
DialogBox(myglobs.hInstApp, "AppAbout", myglobs.hWndMain, (DLGPROC)AppAbout);
AppPause(FALSE);
break;
case MENU_EXIT:
CleanUpAndPostQuit();
break;
case MENU_STEP:
/*
* Begin single step more or draw a frame if in single
* step mode
*/
if (!myglobs.bSingleStepMode) {
myglobs.bSingleStepMode = TRUE;
myglobs.bDrawAFrame = TRUE;
} else if (!myglobs.bDrawAFrame) {
myglobs.bDrawAFrame = TRUE;
}
break;
case MENU_GO:
/*
* Exit single step mode
*/
if (myglobs.bSingleStepMode) {
myglobs.bSingleStepMode = FALSE;
ResetFrameRate();
}
break;
case MENU_STATS:
/*
* Toggle output of frame rate and window info
*/
if ((myglobs.bShowFrameRate) && (myglobs.bShowInfo)) {
myglobs.bShowFrameRate = FALSE;
myglobs.bShowInfo = FALSE;
break;
}
if ((!myglobs.bShowFrameRate) && (!myglobs.bShowInfo)) {
myglobs.bShowFrameRate = TRUE;
break;
}
myglobs.bShowInfo = TRUE;
break;
case MENU_FULLSCREEN:
if (d3dapp->bFullscreen) {
/*
* Return to a windowed mode. Let D3DApp decide which
* D3D driver to use in case this one cannot render to
* the Windows display depth
*/
if (!D3DAppWindow(D3DAPP_YOUDECIDE, D3DAPP_YOUDECIDE)) {
ReportD3DAppError();
CleanUpAndPostQuit();
break;
}
} else {
/*
* Enter the current fullscreen mode. D3DApp may
* resort to another mode if this driver cannot do
* the currently selected mode.
*/
if (!D3DAppFullscreen(d3dapp->CurrMode)) {
ReportD3DAppError();
CleanUpAndPostQuit();
break;
}
}
break;
/*
* Lighting toggle
*/
case MENU_LIGHTING:
myglobs.RenderQuality ^= D3DRMLIGHT_ON;
SetRenderState();
break;
/*
* Fill mode selection
*/
case MENU_POINT:
myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_POINTS;
SetRenderState();
break;
case MENU_WIREFRAME:
myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_WIREFRAME;
SetRenderState();
break;
case MENU_SOLID:
myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMFILL_MASK) | D3DRMFILL_SOLID;
SetRenderState();
break;
/*
* Shade mode selection
*/
case MENU_FLAT:
myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_FLAT;
SetRenderState();
break;
case MENU_GOURAUD:
myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_GOURAUD;
SetRenderState();
break;
case MENU_PHONG:
myglobs.RenderQuality = (myglobs.RenderQuality & ~D3DRMSHADE_MASK) | D3DRMSHADE_PHONG;
SetRenderState();
break;
case MENU_DITHERING:
myglobs.bDithering = !myglobs.bDithering;
SetRenderState();
break;
case MENU_ANTIALIAS:
myglobs.bAntialiasing = !myglobs.bAntialiasing;
SetRenderState();
break;
/*
* Texture filter selection
*/
case MENU_POINT_FILTER:
if (myglobs.TextureQuality == D3DRMTEXTURE_NEAREST)
break;
myglobs.TextureQuality = D3DRMTEXTURE_NEAREST;
SetRenderState();
break;
case MENU_LINEAR_FILTER:
if (myglobs.TextureQuality == D3DRMTEXTURE_LINEAR)
break;
myglobs.TextureQuality = D3DRMTEXTURE_LINEAR;
SetRenderState();
break;
case MENU_NEXT_MODE:
/*
* Enter the next usable fullscreen mode
*/
i = d3dapp->CurrMode;
do {
++i;
if (i >= d3dapp->NumModes)
i = 0;
if (!d3dapp->Mode[i].bThisDriverCanDo)
continue;
else {
if (!D3DAppFullscreen(i)) {
ReportD3DAppError();
CleanUpAndPostQuit();
}
break;
}
} while(i != d3dapp->CurrMode);
break;
case MENU_PREVIOUS_MODE:
/*
* Enter the previous usable fullscreen mode
*/
i = d3dapp->CurrMode;
do {
--i;
if (i < 0)
i = d3dapp->NumModes - 1;
if (!d3dapp->Mode[i].bThisDriverCanDo)
continue;
else {
if (!D3DAppFullscreen(i)) {
ReportD3DAppError();
CleanUpAndPostQuit();
}
break;
}
} while(i != d3dapp->CurrMode);
break;
}
if ( LOWORD(wParam) >= MENU_FIRST_DRIVER
&& LOWORD(wParam) < MENU_FIRST_DRIVER + D3DAPP_MAXD3DDRIVERS
&& d3dapp->CurrDriver != LOWORD(wParam) - MENU_FIRST_DRIVER) {
/*
* Change the D3D driver
*/
if (!D3DAppChangeDriver(LOWORD(wParam) - MENU_FIRST_DRIVER,
NULL)) {
ReportD3DAppError();
CleanUpAndPostQuit();
}
}
if ( LOWORD(wParam) >= MENU_FIRST_MODE
&& LOWORD(wParam) < MENU_FIRST_MODE+100) {
/*
* Switch to the selected fullscreen mode
*/
if (!D3DAppFullscreen(LOWORD(wParam) - MENU_FIRST_MODE)) {
ReportD3DAppError();
CleanUpAndPostQuit();
}
}
if ( LOWORD(wParam) >= MENU_FIRST_DDDRIVER
&& LOWORD(wParam) < MENU_FIRST_DDDRIVER + D3DAPP_MAXDDDRIVERS
&& myglobs.CurrDDDriver != LOWORD(wParam) - MENU_FIRST_DDDRIVER) {
/*
* Change the DD driver
*/
DestroyD3DApp();
myglobs.CurrDDDriver = LOWORD(wParam) - MENU_FIRST_DDDRIVER;
SetWindowPos(myglobs.hWndMain, HWND_NOTOPMOST, 0, 0, START_WIN_SIZE, START_WIN_SIZE, SWP_NOMOVE | SWP_SHOWWINDOW);
if (!CreateD3DApp(myglobs.lpCmdLine))
return FALSE;
}
/*
* Whenever we receive a command in single step mode, draw a frame
*/
if (myglobs.bSingleStepMode)
myglobs.bDrawAFrame = TRUE;
return 0L;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
/****************************************************************************/
/* Additional Functions */
/****************************************************************************/
/*
* ReadMouse
* Returns the mouse status for interaction with sample code
*/
void
ReadMouse(int* b, int* x, int* y)
{
*b = myglobs.mouse_buttons;
*x = myglobs.mouse_x;
*y = myglobs.mouse_y;
}
/*
* SetRenderState
* Set the render quality, dither toggle and shade info if any of them has
* changed
*/
BOOL
SetRenderState(void)
{
HRESULT rval;
/*
* Set the number of buffers so D3DRM can keep track of extents properly
*/
rval = myglobs.dev->SetBufferCount(d3dapp->bFullscreen &&
d3dapp->bBackBufferInVideo ? 2 : 1);
if (rval != D3DRM_OK) {
Msg("Setting the buffer count failed.\n%s", D3DAppErrorToString(rval));
return FALSE;
}
/*
* Set the render quality (light toggle, fill mode, shade mode)
*/
if (myglobs.dev->GetQuality() != myglobs.RenderQuality) {
rval = myglobs.dev->SetQuality(myglobs.RenderQuality);
if (rval != D3DRM_OK) {
Msg("Setting the render quality failed.\n%s",
D3DAppErrorToString(rval));
return FALSE;
}
}
/*
* Set dithering toggle
*/
if (myglobs.dev->GetDither() != myglobs.bDithering) {
rval = myglobs.dev->SetDither(myglobs.bDithering);
if (rval != D3DRM_OK) {
Msg("Setting dither mode failed.\n%s", D3DAppErrorToString(rval));
return FALSE;
}
}
/*
* Set the texture quality (point or linear filtering)
*/
if (myglobs.dev->GetTextureQuality() != myglobs.TextureQuality) {
rval = myglobs.dev->SetTextureQuality(myglobs.TextureQuality);
if (rval != D3DRM_OK) {
Msg("Setting texture quality failed.\n%s",
D3DAppErrorToString(rval));
return FALSE;
}
}
/*
* Set shade info based on current bits per pixel
*/
switch (d3dapp->ThisMode.bpp) {
case 1:
if (FAILED(myglobs.dev->SetShades(4)))
goto shades_error;
if (FAILED(lpD3DRM->SetDefaultTextureShades(4)))
goto shades_error;
break;
case 16:
if (FAILED(myglobs.dev->SetShades(32)))
goto shades_error;
if (FAILED(lpD3DRM->SetDefaultTextureColors(64)))
goto shades_error;
if (FAILED(lpD3DRM->SetDefaultTextureShades(32)))
goto shades_error;
break;
case 24:
case 32:
if (FAILED(myglobs.dev->SetShades(256)))
goto shades_error;
if (FAILED(lpD3DRM->SetDefaultTextureColors(64)))
goto shades_error;
if (FAILED(lpD3DRM->SetDefaultTextureShades(256)))
goto shades_error;
break;
}
return TRUE;
shades_error:
Msg("A failure occurred while setting color shade information.\n");
return FALSE;
}
/****************************************************************************/
/* Initialization, error reporting and release functions. */
/****************************************************************************/
/*
* InitGlobals
* Called once at program initialization to initialize global variables.
*/
static void
InitGlobals(void)
{
d3dapp = NULL;
memset(&myglobs, 0, sizeof(myglobs));
myglobs.bShowFrameRate = TRUE;
myglobs.bShowInfo = TRUE;
myglobs.RenderQuality = D3DRMLIGHT_ON | D3DRMFILL_SOLID |
D3DRMSHADE_GOURAUD;
myglobs.TextureQuality = D3DRMTEXTURE_NEAREST;
}
/*
* CleanUpAndPostQuit
* Release all D3D objects, post a quit message and set the bQuit flag
*/
void
CleanUpAndPostQuit(void)
{
if (myglobs.bQuit)
return;
if (!D3DAppDestroy())
ReportD3DAppError();
RELEASE(myglobs.scene);
RELEASE(myglobs.camera);
RELEASE(lpD3DRM);
myglobs.bQuit = TRUE;
PostQuitMessage( 0 );
}
/*
* ReportD3DAppError
* Reports an error during a d3d app call.
*/
void
ReportD3DAppError(void)
{
Msg("%s", D3DAppLastErrorString());
}
/* Msg
* Message output for error notification.
*/
void __cdecl
Msg( LPSTR fmt, ... )
{
char buff[256];
va_list args;
va_start(args, fmt);
wvsprintf(buff, fmt, args);
va_end(args);
lstrcat(buff, "\r\n");
AppPause(TRUE);
if (d3dapp && d3dapp->bFullscreen)
SetWindowPos(myglobs.hWndMain, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE);
MessageBox( NULL, buff, "D3D Example Message", MB_OK );
if (d3dapp && d3dapp->bFullscreen)
SetWindowPos(myglobs.hWndMain, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE);
AppPause(FALSE);
}
/*
* D3DRMErrorToString
* Allows the samples to return error strings.
*/
char*
D3DRMErrorToString(HRESULT error)
{
return D3DAppErrorToString(error);
}