1000 lines
35 KiB
C++
1000 lines
35 KiB
C++
/*
|
|
* 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 BOOL CreateDevAndView(LPDIRECTDRAWCLIPPER lpDDClipper, int driver, int width, int height);
|
|
static BOOL RenderLoop(void);
|
|
static void CleanUpAndPostQuit(void);
|
|
static BOOL 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 (!CreateDevAndView(lpDDClipper, myglobs.CurrDriver, rc.right, rc.bottom)) {
|
|
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;
|
|
/*
|
|
* Now we are ready to render
|
|
*/
|
|
myglobs.bInitialized = TRUE;
|
|
/*
|
|
* Display the window
|
|
*/
|
|
ShowWindow(win, cmdshow);
|
|
UpdateWindow(win);
|
|
|
|
return win;
|
|
}
|
|
|
|
/*
|
|
* CreateDevAndView
|
|
* Create the D3DRM device and viewport with the given D3D driver and of the
|
|
* specified size.
|
|
*/
|
|
static BOOL
|
|
CreateDevAndView(LPDIRECTDRAWCLIPPER lpDDClipper, int driver, int width, int height)
|
|
{
|
|
HRESULT rval;
|
|
|
|
if (!width || !height) {
|
|
Msg("Cannot create a D3DRM device with invalid window dimensions.");
|
|
return FALSE;
|
|
}
|
|
/*
|
|
* 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) {
|
|
Msg("Failed to create the D3DRM device from the clipper.\n%s",
|
|
D3DRMErrorToString(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.
|
|
*/
|
|
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) {
|
|
Msg("Failed to create the D3DRM viewport.\n%s",
|
|
D3DRMErrorToString(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",
|
|
D3DRMErrorToString(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 TRUE;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* 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;
|
|
|
|
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
|
|
*/
|
|
RELEASE(myglobs.view);
|
|
RELEASE(myglobs.dev);
|
|
myglobs.CurrDriver = LOWORD(wparam)-MENU_FIRST_DRIVER;
|
|
GetClientRect(win, &rc);
|
|
if (!CreateDevAndView(lpDDClipper, myglobs.CurrDriver,
|
|
rc.right, rc.bottom)) {
|
|
CleanUpAndPostQuit();
|
|
}
|
|
}
|
|
/*
|
|
* 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) {
|
|
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
|
|
*/
|
|
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;
|
|
}
|
|
} else {
|
|
/*
|
|
* If the window got larger than the current device, create a
|
|
* new device.
|
|
*/
|
|
RELEASE(myglobs.view);
|
|
RELEASE(myglobs.dev);
|
|
if (!CreateDevAndView(lpDDClipper, myglobs.CurrDriver, width,
|
|
height)) {
|
|
CleanUpAndPostQuit();
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* We must not longer be minimized
|
|
*/
|
|
myglobs.bMinimized = FALSE;
|
|
} else {
|
|
/*
|
|
* This is a minimize message
|
|
*/
|
|
myglobs.bMinimized = 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;
|
|
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
|
|
*/
|
|
BOOL
|
|
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) {
|
|
Msg("Setting the render quality failed.\n%s",
|
|
D3DRMErrorToString(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", D3DRMErrorToString(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",
|
|
D3DRMErrorToString(rval));
|
|
return FALSE;
|
|
}
|
|
}
|
|
/*
|
|
* Set shade info based on current bits per pixel
|
|
*/
|
|
switch (myglobs.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;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* 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;
|
|
}
|