RMMAIN.CPP

/* 
* Copyright (C) 1995, 1996 Microsoft Corporation. All Rights Reserved.
*
* File: rmmain.cpp
*
* Each of the Direct3D retained mode (D3DRM) samples must be linked with
* this file. It contains the code which allows them to run in the Windows
* environment.
*
* A window is created using the rmmain.res which allows the user to select
* the Direct3D driver to use and change the render options.
*
* Individual samples are executed through two functions, BuildScene and
* OverrideDefaults, as described in rmdemo.h. Samples can also read
* mouse input via ReadMouse.
*/

#define INITGUID

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <math.h>
#include <direct.h>
#include <d3drmwin.h>
#include "rmdemo.h" /* prototypes for functions to commumicate
with each sample */
#include "rmmain.h" /* defines constants used in rmmain.rc */
#include "rmerror.h" /* prototypes for error reporting: error.c */

#define MAX_DRIVERS 5 /* maximum D3D drivers we ever expect to find */

/*
* GLOBAL VARIABLES
*/
LPDIRECT3DRM lpD3DRM; /* Direct3DRM object */
LPDIRECTDRAWCLIPPER lpDDClipper;/* DirectDrawClipper object */

struct _myglobs {
LPDIRECT3DRMDEVICE dev; /* Direct3DRM device */
LPDIRECT3DRMVIEWPORT view; /* Direct3DRM viewport through which we view
the scene */
LPDIRECT3DRMFRAME scene; /* Master frame in which others are placed */
LPDIRECT3DRMFRAME camera; /* Frame describing the users POV */

GUID DriverGUID[MAX_DRIVERS]; /* GUIDs of the available D3D drivers */
char DriverName[MAX_DRIVERS][50]; /* names of the available D3D drivers */
int NumDrivers; /* number of available D3D drivers */
int CurrDriver; /* number of D3D driver currently
being used */

D3DRMRENDERQUALITY RenderQuality; /* current shade mode, fill mode and
lighting state */
D3DRMTEXTUREQUALITY TextureQuality; /* current texture interpolation */
BOOL bDithering; /* is dithering on? */
BOOL bAntialiasing; /* is antialiasing on? */

BOOL bQuit; /* program is about to terminate */
BOOL bInitialized; /* all D3DRM objects have been initialized */
BOOL bMinimized; /* window is minimized */
BOOL bSingleStepMode; /* render one frame at a time */
BOOL bDrawAFrame; /* render on this pass of the main loop */
BOOL bNoTextures; /* this sample doesn't use any textures */
BOOL bConstRenderQuality; /* this sample is not constructed with
MeshBuilders and so the RenderQuality
cannot be changed */

int BPP; /* bit depth of the current display mode */

int mouse_buttons; /* mouse button state */
int mouse_x; /* mouse cursor x position */
int mouse_y; /* mouse cursor y position */
} myglobs;

/*
* PROTOTYPES
*/
static HWND InitApp(HINSTANCE, int);
static void InitGlobals(void);
long FAR PASCAL WindowProc(HWND, UINT, WPARAM, LPARAM);
static HRESULT CreateDevAndView(LPDIRECTDRAWCLIPPER lpDDClipper, int driver, int width, int height);
static BOOL RenderLoop(void);
static void CleanUpAndPostQuit(void);
static HRESULT SetRenderState(void);
static BOOL EnumDevices(HWND win);
extern "C" void ReadMouse(int*, int*, int*);

/****************************************************************************/
/* WinMain */
/****************************************************************************/
/*
* Initializes the application then enters a message loop which renders the
* scene until a quit message is received.
*/
int PASCAL
WinMain (HINSTANCE this_inst, HINSTANCE prev_inst, LPSTR cmdline, int cmdshow)
{
HWND hwnd;
MSG msg;
HACCEL accel;
int failcount = 0; /* number of times RenderLoop has failed */

prev_inst;
cmdline;

/*
* Create the window and initialize all objects needed to begin rendering
*/
if (!(hwnd = InitApp(this_inst, cmdshow)))
return 1;

accel = LoadAccelerators(this_inst, "AppAccel");

while (!myglobs.bQuit) {
/*
* Monitor the message queue until there are no pressing
* messages
*/
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
CleanUpAndPostQuit();
break;
}
if (!TranslateAccelerator(msg.hwnd, accel, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
if (myglobs.bQuit)
break;
/*
* If the app is not minimized, not about to quit and D3DRM has
* been initialized, we can render
*/
if (!myglobs.bMinimized && !myglobs.bQuit && myglobs.bInitialized) {
/*
* 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 > 2) {
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(hwnd);
return msg.wParam;
}

/****************************************************************************/
/* Initialization and object creation */
/****************************************************************************/
/*
* InitApp
* Creates window and initializes all objects neccessary to begin rendering
*/
static HWND
InitApp(HINSTANCE this_inst, int cmdshow)
{
HWND win;
HDC hdc;
DWORD flags;
WNDCLASS wc;
Defaults defaults;
HRESULT rval;
RECT rc;

/*
* set up and registers the window class
*/
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(DWORD);
wc.hInstance = this_inst;
wc.hIcon = LoadIcon(this_inst, "AppIcon");
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = "AppMenu";
wc.lpszClassName = "D3DRM Example";
if (!RegisterClass(&wc))
return FALSE;
/*
* Initialize the global variables and allow the sample code to override
* some of these default settings.
*/
InitGlobals();
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;
/*
* Create the window
*/
if (defaults.bResizingDisabled)
flags = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
else
flags = WS_OVERLAPPEDWINDOW;
win =
CreateWindow
( "D3DRM Example", /* class */
defaults.Name, /* caption */
flags, /* style */
CW_USEDEFAULT, /* init. x pos */
CW_USEDEFAULT, /* init. y pos */
300, /* init. x size */
300, /* init. y size */
NULL, /* parent window */
NULL, /* menu handle */
this_inst, /* program handle */
NULL /* create parms */
);
if (!win)
return FALSE;
/*
* Record the current display BPP
*/
hdc = GetDC(win);
myglobs.BPP = GetDeviceCaps(hdc, BITSPIXEL);
ReleaseDC(win, hdc);
/*
* Enumerate the D3D drivers and select one
*/
if (!EnumDevices(win))
return FALSE;
/*
* Create the D3DRM object and the D3DRM window object
*/
rval = Direct3DRMCreate(&lpD3DRM);
if (rval != D3DRM_OK) {
Msg("Failed to create Direct3DRM.\n%s", D3DRMErrorToString(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", D3DRMErrorToString(rval));
return FALSE;
}
rval = lpD3DRM->CreateFrame(myglobs.scene, &myglobs.camera);
if (rval != D3DRM_OK) {
Msg("Failed to create the camera's frame.\n%s", D3DRMErrorToString(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", D3DRMErrorToString(rval));
return FALSE;
}
/*
* Create a clipper and associate the window with it
*/
rval = DirectDrawCreateClipper(0, &lpDDClipper, NULL);
if (rval != DD_OK) {
Msg("Failed to create DirectDrawClipper");
return FALSE;
}
rval = lpDDClipper->SetHWnd(0, win);
if (rval != DD_OK) {
Msg("Failed to set hwnd on the clipper");
return FALSE;
}
/*
* Created the D3DRM device with the selected D3D driver
*/
GetClientRect(win, &rc);
if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver, rc.right, rc.bottom)) {
myglobs.CurrDriver = 0;
if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver, rc.right, rc.bottom)) {
Msg("Failed to create the D3DRM device.\n%s", D3DRMErrorToString(rval));
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;
/*
* Display the window
*/
ShowWindow(win, cmdshow);
UpdateWindow(win);
/*
* Now we are ready to render
*/
myglobs.bInitialized = TRUE;

return win;
}

/*
* CreateDevAndView
* Create the D3DRM device and viewport with the given D3D driver and of the
* specified size.
*/
static HRESULT
CreateDevAndView(LPDIRECTDRAWCLIPPER lpDDClipper, int driver, int width, int height)
{
HRESULT rval;

if (!width || !height)
return D3DRMERR_BADVALUE;
/*
* Create the D3DRM device from this window and using the specified D3D
* driver.
*/
rval = lpD3DRM->CreateDeviceFromClipper(lpDDClipper, &myglobs.DriverGUID[driver],
width, height, &myglobs.dev);
if (rval != D3DRM_OK)
return rval;
/*
* 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.
*/
width = myglobs.dev->GetWidth();
height = myglobs.dev->GetHeight();
rval = lpD3DRM->CreateViewport(myglobs.dev, myglobs.camera, 0, 0, width,
height, &myglobs.view);
if (rval != D3DRM_OK) {
myglobs.bInitialized = FALSE;
RELEASE(myglobs.dev);
return rval;
}
rval = myglobs.view->SetBack(D3DVAL(5000.0));
if (rval != D3DRM_OK) {
myglobs.bInitialized = FALSE;
RELEASE(myglobs.dev);
RELEASE(myglobs.view);
return rval;
}
/*
* Set the render quality, fill mode, lighting state and color shade info
*/
if (rval = SetRenderState()) {
myglobs.bInitialized = FALSE;
RELEASE(myglobs.dev);
RELEASE(myglobs.view);
return rval;
}

return D3DRM_OK;
}

/****************************************************************************/
/* D3D Device Enumeration */
/****************************************************************************/
/*
* BPPToDDBD
* Converts bits per pixel to a DirectDraw bit depth flag
*/
static DWORD
BPPToDDBD(int bpp)
{
switch(bpp) {
case 1:
return DDBD_1;
case 2:
return DDBD_2;
case 4:
return DDBD_4;
case 8:
return DDBD_8;
case 16:
return DDBD_16;
case 24:
return DDBD_24;
case 32:
return DDBD_32;
default:
return 0;
}
}

/*
* enumDeviceFunc
* Callback function which records each usable D3D driver's name and GUID
* Chooses a driver to begin with and sets *lpContext to this starting driver
*/
static HRESULT
WINAPI enumDeviceFunc(LPGUID lpGuid, LPSTR lpDeviceDescription, LPSTR lpDeviceName,
LPD3DDEVICEDESC lpHWDesc, LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext)
{
static BOOL hardware = FALSE; /* current start driver is hardware */
static BOOL mono = FALSE; /* current start driver is mono light */
LPD3DDEVICEDESC lpDesc;
int *lpStartDriver = (int *)lpContext;
/*
* Decide which device description we should consult
*/
lpDesc = lpHWDesc->dcmColorModel ? lpHWDesc : lpHELDesc;
/*
* If this driver cannot render in the current display bit depth skip
* it and continue with the enumeration.
*/
if (!(lpDesc->dwDeviceRenderBitDepth & BPPToDDBD(myglobs.BPP)))
return D3DENUMRET_OK;
/*
* Record this driver's info
*/
memcpy(&myglobs.DriverGUID[myglobs.NumDrivers], lpGuid, sizeof(GUID));
lstrcpy(&myglobs.DriverName[myglobs.NumDrivers][0], lpDeviceName);
/*
* Choose hardware over software, RGB lights over mono lights
*/
if (*lpStartDriver == -1) {
/*
* this is the first valid driver
*/
*lpStartDriver = myglobs.NumDrivers;
hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
} else if (lpDesc == lpHWDesc && !hardware) {
/*
* this driver is hardware and start driver is not
*/
*lpStartDriver = myglobs.NumDrivers;
hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
} else if ((lpDesc == lpHWDesc && hardware ) || (lpDesc == lpHELDesc
&& !hardware)) {
if (lpDesc->dcmColorModel == D3DCOLOR_MONO && !mono) {
/*
* this driver and start driver are the same type and this
* driver is mono while start driver is not
*/
*lpStartDriver = myglobs.NumDrivers;
hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
}
}
myglobs.NumDrivers++;
if (myglobs.NumDrivers == MAX_DRIVERS)
return (D3DENUMRET_CANCEL);
return (D3DENUMRET_OK);
}

/*
* EnumDevices
* Enumerate the available D3D drivers, add them to the file menu, and choose
* one to use.
*/
static BOOL
EnumDevices(HWND win)
{
LPDIRECTDRAW lpDD;
LPDIRECT3D lpD3D;
HRESULT rval;
HMENU hmenu;
int i;

/*
* Create a DirectDraw object and query for the Direct3D interface to use
* to enumerate the drivers.
*/
rval = DirectDrawCreate(NULL, &lpDD, NULL);
if (rval != DD_OK) {
Msg("Creation of DirectDraw HEL failed.\n%s", D3DRMErrorToString(rval));
return FALSE;
}
rval = lpDD->QueryInterface(IID_IDirect3D, (void**) &lpD3D);
if (rval != DD_OK) {
Msg("Creation of Direct3D interface failed.\n%s", D3DRMErrorToString(rval));
lpDD->Release();
return FALSE;
}
/*
* Enumerate the drivers, setting CurrDriver to -1 to initialize the
* driver selection code in enumDeviceFunc
*/
myglobs.CurrDriver = -1;
rval = lpD3D->EnumDevices(enumDeviceFunc, &myglobs.CurrDriver);
if (rval != DD_OK) {
Msg("Enumeration of drivers failed.\n%s", D3DRMErrorToString(rval));
return FALSE;
}
/*
* Make sure we found at least one valid driver
*/
if (myglobs.NumDrivers == 0) {
Msg("Could not find a D3D driver which is compatible with this display depth");
return FALSE;
}
lpD3D->Release();
lpDD->Release();
/*
* Add the driver names to the File menu
*/
hmenu = GetSubMenu(GetMenu(win), 0);
for (i = 0; i < myglobs.NumDrivers; i++) {
InsertMenu(hmenu, 5 + i, MF_BYPOSITION | MF_STRING, MENU_FIRST_DRIVER + i,
myglobs.DriverName[i]);
}
return TRUE;
}

/****************************************************************************/
/* Render Loop */
/****************************************************************************/
/*
* Clear the viewport, render the next frame and update the window
*/
static BOOL
RenderLoop()
{
HRESULT rval;
/*
* Tick the scene
*/
rval = myglobs.scene->Move(D3DVAL(1.0));
if (rval != D3DRM_OK) {
Msg("Moving scene failed.\n%s", D3DRMErrorToString(rval));
return FALSE;
}
/*
* Clear the viewport
*/
rval = myglobs.view->Clear();
if (rval != D3DRM_OK) {
Msg("Clearing viewport failed.\n%s", D3DRMErrorToString(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", D3DRMErrorToString(rval));
return FALSE;
}
/*
* Update the window
*/
rval = myglobs.dev->Update();
if (rval != D3DRM_OK) {
Msg("Updating device failed.\n%s", D3DRMErrorToString(rval));
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 win, UINT msg, WPARAM wparam, LPARAM lparam)
{
int i;
HRESULT rval;
RECT rc;

if (!myglobs.bInitialized) {
return DefWindowProc(win, msg, wparam, lparam);
}

switch (msg) {
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_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);
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) {
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);
for (i = 0; i < myglobs.NumDrivers; i++) {
CheckMenuItem((HMENU)wparam, MENU_FIRST_DRIVER + i,
(i == myglobs.CurrDriver) ? MF_CHECKED : MF_UNCHECKED);
}
break;
case WM_COMMAND:
switch(LOWORD(wparam)) {
case MENU_ABOUT:
DialogBox((HINSTANCE)GetWindowLong(win, GWL_HINSTANCE),
"AppAbout", win, (DLGPROC)AppAbout);
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
*/
myglobs.bSingleStepMode = FALSE;
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;
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;
}
/*
* Changing the D3D Driver
*/
if (LOWORD(wparam) >= MENU_FIRST_DRIVER &&
LOWORD(wparam) < MENU_FIRST_DRIVER + MAX_DRIVERS &&
myglobs.CurrDriver != LOWORD(wparam) - MENU_FIRST_DRIVER)
{
/*
* Release the current viewport and device and create
* the new one
*/
int LastDriver = myglobs.CurrDriver;
myglobs.bInitialized = FALSE;
RELEASE(myglobs.view);
RELEASE(myglobs.dev);
myglobs.CurrDriver = LOWORD(wparam)-MENU_FIRST_DRIVER;
GetClientRect(win, &rc);
if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
rc.right, rc.bottom))
{
myglobs.CurrDriver = LastDriver;
if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
rc.right, rc.bottom))
{
Msg("Failed to create the D3DRM device.\n%s", D3DRMErrorToString(rval));
CleanUpAndPostQuit();
}
else
{
Msg("There was not enough video memory available to use the 3D accelerated hardware device.\nRestoring old software device.");
myglobs.bInitialized = TRUE;
}
}
else
{
myglobs.bInitialized = TRUE;
}
}
/*
* Draw a frame in single step mode after ever command
*/
myglobs.bDrawAFrame = TRUE;
break;
case WM_DESTROY:
CleanUpAndPostQuit();
break;
case WM_SIZE:
/*
* Handle resizing of the window
*/
{
int width = LOWORD(lparam);
int height = HIWORD(lparam);
if (width && height && myglobs.view && myglobs.dev) {
int view_width = myglobs.view->GetWidth();
int view_height = myglobs.view->GetHeight();
int dev_width = myglobs.dev->GetWidth();

int dev_height = myglobs.dev->GetHeight(); 
/*
* If the window hasn't changed size and we aren't returning from
* a minimize, there is nothing to do
*/
if (view_width == width && view_height == height &&
!myglobs.bMinimized)
break;
if (width <= dev_width && height <= dev_height) {
/*
* If the window has shrunk, we can use the same device with a
* new viewport
*/
myglobs.bInitialized = FALSE;
RELEASE(myglobs.view);
rval = lpD3DRM->CreateViewport(myglobs.dev, myglobs.camera,
0, 0, width, height,
&myglobs.view);
if (rval != D3DRM_OK) {
Msg("Failed to resize the viewport.\n%s",
D3DRMErrorToString(rval));
CleanUpAndPostQuit();
break;
}
rval = myglobs.view->SetBack(D3DVAL(5000.0));
if (rval != D3DRM_OK) {
Msg("Failed to set background depth after viewport resize.\n%s",
D3DRMErrorToString(rval));
CleanUpAndPostQuit();
break;
}
myglobs.bInitialized = TRUE;
} else {
/*
* If the window got larger than the current device, create a
* new device.
*/
myglobs.bInitialized = FALSE;
RELEASE(myglobs.view);
RELEASE(myglobs.dev);
if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
width, height))
{
myglobs.CurrDriver = 0;
if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
width, height))
{
Msg("Failed to create the D3DRM device.\n%s", D3DRMErrorToString(rval));
CleanUpAndPostQuit();
}
else
{
Msg("There was not enough video memory available to use the 3D accelerated hardware device.\nUsing software rendering instead.");
myglobs.bInitialized = TRUE;
}
}
else
{
myglobs.bInitialized = TRUE;
}
myglobs.bInitialized = TRUE;
}
/*
* We must not longer be minimized
*/
myglobs.bMinimized = FALSE;
} else {
/*
* This is a minimize message
*/
myglobs.bMinimized = TRUE;
}
}
myglobs.bDrawAFrame = TRUE;
break;
case WM_ACTIVATE:
{
/*
* Create a Windows specific D3DRM window device to handle this
* message
*/
LPDIRECT3DRMWINDEVICE windev;
if (!myglobs.dev)
break;
if (SUCCEEDED(myglobs.dev->QueryInterface(IID_IDirect3DRMWinDevice,
(void **) &windev))) {
if (FAILED(windev->HandleActivate(wparam)))
Msg("Failed to handle WM_ACTIVATE.\n");
windev->Release();
} else {
Msg("Failed to create Windows device to handle WM_ACTIVATE.\n");
}
}
break;
case WM_PAINT:
if (!myglobs.bInitialized || !myglobs.dev)
return DefWindowProc(win, msg, wparam, lparam);
/*
* Create a Windows specific D3DRM window device to handle this
* message
*/
RECT r;
PAINTSTRUCT ps;
LPDIRECT3DRMWINDEVICE windev;

if (GetUpdateRect(win, &r, FALSE)) {
BeginPaint(win, &ps);
if (SUCCEEDED(myglobs.dev->QueryInterface(IID_IDirect3DRMWinDevice,
(void **) &windev))) {
if (FAILED(windev->HandlePaint(ps.hdc)))
Msg("Failed to handle WM_PAINT.\n");
windev->Release();
} else {
Msg("Failed to create Windows device to handle WM_PAINT.\n");
}
EndPaint(win, &ps);
}
break;
case WM_DISPLAYCHANGE:
{
/*
* If this display change message was generated because another application
* has gone exclusive, ignore it.
*/
LPDIRECTDRAW lpDD;
LPDIRECTDRAWSURFACE lpDDS;
DDSURFACEDESC ddsd;
HRESULT err;

if (DirectDrawCreate(NULL, &lpDD, NULL))
break;
err = lpDD->SetCooperativeLevel(win, DDSCL_NORMAL);
if (err) {
lpDD->Release();
break;
}
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
err = lpDD->CreateSurface(&ddsd, &lpDDS, NULL);
if (err == DDERR_NOEXCLUSIVEMODE) {
// This exclusive mode generated WM_DISPLAYCHANGE, ignoring
lpDD->Release();
break;
}
if (!err)
lpDDS->Release();
lpDD->Release();
}
GetClientRect(win, &rc);
myglobs.bInitialized = FALSE;
if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
rc.right, rc.bottom)) {
myglobs.CurrDriver = 0;
if (rval = CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
rc.right, rc.bottom))
{
Msg("Failed to create the D3DRM device.\n%s", D3DRMErrorToString(rval));
CleanUpAndPostQuit();
}
else
{
// Don't bother the user with an error message here
//Msg("There was not enough video memory available to use the 3D accelerated hardware device.\nUsing software rendering instead.");
myglobs.bInitialized = TRUE;
}
}
else
{
myglobs.bInitialized = TRUE;
}
break;
default:
return DefWindowProc(win, msg, wparam, lparam);
}
return 0L;
}

/*
* SetRenderState
* Set the render quality, dither toggle and shade info if any of them has
* changed
*/
HRESULT
SetRenderState(void)
{
HRESULT rval;
/*
* 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)
return rval;
}
/*
* Set dithering toggle
*/
if (myglobs.dev->GetDither() != myglobs.bDithering) {
rval = myglobs.dev->SetDither(myglobs.bDithering);
if (rval != D3DRM_OK)
return rval;
}
/*
* Set the texture quality (point or linear filtering)
*/
if (myglobs.dev->GetTextureQuality() != myglobs.TextureQuality) {
rval = myglobs.dev->SetTextureQuality(myglobs.TextureQuality);
if (rval != D3DRM_OK)
return rval;
}
/*
* Set shade info based on current bits per pixel
*/
switch (myglobs.BPP) {
case 1:
if (rval = myglobs.dev->SetShades(4))
return rval;
if (rval = lpD3DRM->SetDefaultTextureShades(4))
return rval;
break;
case 16:
if (rval = myglobs.dev->SetShades(32))
return rval;
if (rval = lpD3DRM->SetDefaultTextureColors(64))
return rval;
if (rval = lpD3DRM->SetDefaultTextureShades(32))
return rval;
break;
case 24:
case 32:
if (rval = myglobs.dev->SetShades(256))
return rval;
if (rval = lpD3DRM->SetDefaultTextureColors(64))
return rval;
if (rval = lpD3DRM->SetDefaultTextureShades(256))
return rval;
break;
}
return D3DRM_OK;
}

/****************************************************************************/
/* 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;
}

/*
* InitGlobals
* Initialize the global variables
*/
void
InitGlobals(void)
{
lpD3DRM = NULL;
memset(&myglobs, 0, sizeof(myglobs));
myglobs.RenderQuality = D3DRMLIGHT_ON | D3DRMFILL_SOLID |
D3DRMSHADE_GOURAUD;
myglobs.TextureQuality = D3DRMTEXTURE_NEAREST;
}

/*
* CleanUpAndPostQuit
* Release all D3DRM objects, post a quit message and set the bQuit flag
*/
void
CleanUpAndPostQuit(void)
{
myglobs.bInitialized = FALSE;
RELEASE(myglobs.scene);
RELEASE(myglobs.camera);
RELEASE(myglobs.view);
RELEASE(myglobs.dev);
RELEASE(lpD3DRM);
RELEASE(lpDDClipper);
myglobs.bQuit = TRUE;
}