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