|
![]()
Direct3D Retained Mode Sample
// File: hello.cpp
// Simple Direct3D Retained-Mode example
// Must precede other defines and includes
#define INITGUID
#include <windows.h>
#include <malloc.h>
#include <d3drmwin.h>
#define MAXDRV 5 // Maximum D3D drivers expected
// Global variables
LPDIRECT3DRM lpD3DRM; // Direct3DRM object
// DirectDrawClipper object
LPDIRECTDRAWCLIPPER lpDDClipper;
struct _gInfo {
LPDIRECT3DRMDEVICE dev; // Direct3DRM device
LPDIRECT3DRMVIEWPORT view; // Direct3DRM viewport through which
// scene is viewed
LPDIRECT3DRMFRAME scene; // Master frame
LPDIRECT3DRMFRAME camera; // Frame describing user's POV
GUID drvGUID[MAXDRV]; // GUIDs of available D3D drivers
char drvName[MAXDRV][50]; // Names of available D3D drivers
int numDrv; // available D3D drivers
int curr; // D3D driver currently used
BOOL bQuit; // Program is about to terminate
BOOL bInit; // All D3DRM objects are initialized
BOOL bMin; // Window is minimized
int bpp; // Bit depth of current display mode
} gInfo;
// Function prototypes.
BOOL InitApp(HINSTANCE, int);
long FAR PASCAL WindowProc(HWND, UINT, WPARAM, LPARAM);
BOOL EnumDrivers(HWND win);
HRESULT WINAPI enumDeviceFunc(LPGUID lpGuid,
LPSTR lpDevDesc, LPSTR lpDevName, LPD3DDEVICEDESC lpHWDesc,
LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext);
DWORD bppToDDBD(int bpp);
BOOL CreateDevAndView(LPDIRECTDRAWCLIPPER lpDDClipper,
int driver, int width, int height);
BOOL SetRenderState(void);
BOOL RenderLoop(void);
BOOL MyScene(LPDIRECT3DRMDEVICE dev, LPDIRECT3DRMVIEWPORT view,
LPDIRECT3DRMFRAME scene, LPDIRECT3DRMFRAME camera);
void MakeMyFrames(LPDIRECT3DRMFRAME lpScene, LPDIRECT3DRMFRAME lpCam,
LPDIRECT3DRMFRAME *lplpLtFr1, LPDIRECT3DRMFRAME *lplpWorldF);
void MakeMyLights(LPDIRECT3DRMFRAME lpScene, LPDIRECT3DRMFRAME lpCam,
LPDIRECT3DRMFRAME lpLtFr1, LPDIRECT3DRMLIGHT *lplpLt1,
LPDIRECT3DRMLIGHT *lplpLt2);
void SetMyPositions(LPDIRECT3DRMFRAME lpScene,
LPDIRECT3DRMFRAME lpCam, LPDIRECT3DRMFRAME lpLtFr1,
LPDIRECT3DRMFRAME lpWorldF);
void MakeMyMesh(LPDIRECT3DRMMESHBUILDER *lplpMesh);
void MakeMyWrap(LPDIRECT3DRMMESHBUILDER mesh,
LPDIRECT3DRMWRAP *lpWrap);
void AddMyTexture(LPDIRECT3DRMMESHBUILDER lpMesh,
LPDIRECT3DRMTEXTURE *lplpTex);
void CleanUp(void);
// Initializes the application and enters a message loop.
// Message loop renders scene until quit message is received.
int PASCAL WinMain (HINSTANCE hInst, HINSTANCE hPrevInst,
LPSTR cmdline, int cmdshow) {
MSG msg;
HACCEL accel = NULL;
int failcount = 0; // Number of times RenderLoop has failed
hPrevInst;
cmdline;
if ( !InitApp(hInst, cmdshow) ) return 1;
while ( !gInfo.bQuit ) {
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (!TranslateAccelerator(msg.hwnd, accel, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// If app is not minimized, not about to quit, and D3DRM
// has been initialized, begin rendering.
if ( !gInfo.bMin && !gInfo.bQuit && gInfo.bInit ) {
if ( !RenderLoop() ) ++failcount;
if (failcount > 2) {
CleanUp(); break;
}
}
}
return msg.wParam;
}
// Creates window and initializes all objects necessary to begin
// rendering.
BOOL InitApp(HINSTANCE hInst, int cmdshow) {
HWND win;
HDC hdc;
WNDCLASS wc;
RECT rc;
// Set up and register the window class.
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(DWORD);
wc.hInstance = hInst;
wc.hIcon = LoadIcon(hInst, "AppIcon");
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "D3DRM Example";
if (!RegisterClass(&wc)) return FALSE;
// Initialize the global variables.
memset(&gInfo, 0, sizeof(gInfo));
// Create the window.
win = CreateWindow("D3DRM Example",
"Hello World (Direct3DRM)",
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 500, NULL, NULL, hInst, NULL);
if ( !win ) return FALSE;
// Record the current display bits-per-pixel.
hdc = GetDC(win);
gInfo.bpp = GetDeviceCaps(hdc, BITSPIXEL);
ReleaseDC(win, hdc);
// Enumerate the D3D drivers and select one.
if ( !EnumDrivers(win) ) return FALSE;
// Create the D3DRM object and the D3DRM window object.
lpD3DRM = NULL;
Direct3DRMCreate(&lpD3DRM);
// Create the master scene frame and camera frame.
lpD3DRM->CreateFrame(NULL, &gInfo.scene);
lpD3DRM->CreateFrame(gInfo.scene, &gInfo.camera);
gInfo.camera->SetPosition(gInfo.scene,
D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0));
// Create a DirectDrawClipper object and associate the
// window with it.
DirectDrawCreateClipper(0, &lpDDClipper, NULL);
lpDDClipper->SetHWnd(0, win);
// Create the D3DRM device by using the selected D3D driver.
GetClientRect(win, &rc);
CreateDevAndView(lpDDClipper, gInfo.curr, rc.right, rc.bottom);
// Create the scene to be rendered.
MyScene(gInfo.dev, gInfo.view, gInfo.scene, gInfo.camera);
gInfo.bInit = TRUE; // Initialization completed
// Display the window.
ShowWindow(win, cmdshow);
UpdateWindow(win);
return TRUE;
}
// Main window message handler.
LONG FAR PASCAL WindowProc(HWND win, UINT msg,
WPARAM wparam, LPARAM lparam) {
RECT r; PAINTSTRUCT ps;
LPDIRECT3DRMWINDEVICE lpD3DRMWinDev;
switch (msg) {
case WM_DESTROY:
CleanUp(); break;
case WM_ACTIVATE: {
// Create a Windows-specific D3DRM window device to handle this
// message.
LPDIRECT3DRMWINDEVICE lpD3DRMWinDev;
if (!gInfo.dev) break;
gInfo.dev->QueryInterface(IID_IDirect3DRMWinDevice,
(void **) &lpD3DRMWinDev);
lpD3DRMWinDev->HandleActivate((WORD) wparam);
lpD3DRMWinDev->Release();
}
break;
case WM_PAINT:
if (!gInfo.bInit || !gInfo.dev)
return DefWindowProc(win, msg, wparam, lparam);
// Create a Windows-specific D3DRM window device to handle this
// message.
if (GetUpdateRect(win, &r, FALSE)) {
BeginPaint(win, &ps);
gInfo.dev->QueryInterface(IID_IDirect3DRMWinDevice,
(void **) &lpD3DRMWinDev);
if (FAILED(lpD3DRMWinDev->HandlePaint(ps.hdc)))
lpD3DRMWinDev->Release();
EndPaint(win, &ps);
}
break;
default:
return DefWindowProc(win, msg, wparam, lparam);
}
return 0L;
}
// Enumerate the available D3D drivers and choose one.
BOOL EnumDrivers(HWND win) {
LPDIRECTDRAW lpDD; LPDIRECT3D lpD3D; HRESULT rval;
// Create a DirectDraw object and query for the Direct3D interface
// to use to enumerate the drivers.
DirectDrawCreate(NULL, &lpDD, NULL);
rval = lpDD->QueryInterface(IID_IDirect3D, (void**) &lpD3D);
if (rval != DD_OK) {
lpDD->Release();
return FALSE;
}
// Enumerate the drivers, setting curr to -1 to initialize the
// driver selection code in enumDeviceFunc.
gInfo.curr = -1;
lpD3D->EnumDevices(enumDeviceFunc, &gInfo.curr);
// Ensure at least one valid driver was found.
if (gInfo.numDrv == 0) return FALSE;
lpD3D->Release();
lpDD->Release();
return TRUE;
}
// Callback function that records each usable D3D driver's name
// and GUID. Chooses a driver and sets *lpContext to this driver.
HRESULT WINAPI enumDeviceFunc(LPGUID lpGuid, LPSTR lpDevDesc,
LPSTR lpDevName, 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 should be consulted.
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(gInfo.BPP)))
return D3DENUMRET_OK;
// Record this driver's name and GUID.
memcpy(&gInfo.drvGUID[gInfo.numDrv], lpGuid, sizeof(GUID));
lstrcpy(&gInfo.drvName[gInfo.numDrv][0], lpDevName);
// Choose hardware over software, RGB lights over mono lights.
if (*lpStartDriver == -1) {
// This is the first valid driver.
*lpStartDriver = gInfo.numDrv;
hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
} else if (lpDesc == lpHWDesc && !hardware) {
// This driver is hardware and the start driver is not.
*lpStartDriver = gInfo.numDrv;
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 the start driver are the same type, and
// this driver is mono whereas the start driver is not.
*lpStartDriver = gInfo.numDrv;
hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
}
}
gInfo.numDrv++;
if (gInfo.numDrv == MAXDRV) return (D3DENUMRET_CANCEL);
return (D3DENUMRET_OK);
}
// Converts bits-per-pixel to a DirectDraw bit-depth flag.
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;
}
}
// Create the D3DRM device and viewport with the given D3D driver and
// with the specified size.
BOOL CreateDevAndView(LPDIRECTDRAWCLIPPER lpDDClipper, int driver,
int width, int height) {
HRESULT rval;
// Create the D3DRM device from this window by using the specified
// D3D driver.
lpD3DRM->CreateDeviceFromClipper(lpDDClipper,
&gInfo.drvGUID[driver], width, height, &gInfo.dev);
// Create the D3DRM viewport by using the camera frame. Set the
// background depth to a large number. The width and height
// might have been slightly adjusted, so get them from the device.
width = gInfo.dev->GetWidth();
height = gInfo.dev->GetHeight();
rval = lpD3DRM->CreateViewport(gInfo.dev, gInfo.camera,
0, 0, width, height, &gInfo.view);
if (rval != D3DRM_OK) {
gInfo.dev->Release();
return FALSE;
}
rval = gInfo.view->SetBack(D3DVAL(5000.0));
if (rval != D3DRM_OK) {
gInfo.dev->Release();
gInfo.view->Release();
return FALSE;
}
// Set the render quality, fill mode, lighting state,
// and color shade info.
if (!SetRenderState()) return FALSE;
return TRUE;
}
// Set the render quality and shade information.
BOOL SetRenderState(void) {
HRESULT rval;
// Set the render quality (light toggle, fill mode, shade mode).
rval = gInfo.dev->SetQuality(D3DRMLIGHT_ON |
D3DRMFILL_SOLID | D3DRMSHADE_GOURAUD);
if (rval != D3DRM_OK) return FALSE;
switch (gInfo.bpp) {
case 1:
if (FAILED(gInfo.dev->SetShades(4)))
goto shades_error;
if (FAILED(lpD3DRM->SetDefaultTextureShades(4)))
goto shades_error;
break;
case 16:
if (FAILED(gInfo.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(gInfo.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:
return FALSE;
}
// Clear the viewport, render the next frame, and update the window.
BOOL RenderLoop() {
HRESULT rval;
// Tick the scene.
rval = gInfo.scene->Move(D3DVAL(1.0));
if (rval != D3DRM_OK) return FALSE;
// Clear the viewport.
rval = gInfo.view->Clear();
if (rval != D3DRM_OK) return FALSE;
// Render the scene to the viewport.
rval = gInfo.view->Render(gInfo.scene);
if (rval != D3DRM_OK) return FALSE;
// Update the window.
rval = gInfo.dev->Update();
if (rval != D3DRM_OK) return FALSE;
return TRUE;
}
// Calls the functions that create the frames, lights, mesh, and
// texture. Releases all interfaces on completion.
BOOL MyScene(LPDIRECT3DRMDEVICE dev, LPDIRECT3DRMVIEWPORT view,
LPDIRECT3DRMFRAME lpScene, LPDIRECT3DRMFRAME lpCam) {
LPDIRECT3DRMFRAME lpLtframe1, lpWorldF;
LPDIRECT3DRMLIGHT lpLt1, lpLt2; LPDIRECT3DRMTEXTURE lpTex;
LPDIRECT3DRMWRAP lpWrap; LPDIRECT3DRMMESHBUILDER lpMesh;
lpLtframe1 = lpWorldF = NULL; lpLt1 = lpLt2 = NULL;
lpTex = NULL; lpWrap = NULL; lpMesh = NULL;
MakeMyFrames(lpScene, lpCam, &lpLtframe1, &lpWorldF);
MakeMyLights(lpScene, lpCam, lpLtframe1, &lpLt1, &lpLt2);
SetMyPositions(lpScene, lpCam, lpLtframe1, lpWorldF);
MakeMyMesh(&lpMesh);
MakeMyWrap(lpMesh, &lpWrap);
AddMyTexture(lpMesh, &lpTex);
// Now that the visual object has been created, add it
// to the world frame.
lpWorldF->AddVisual((LPDIRECT3DRMVISUAL) lpMesh);
lpLtframe1->Release(); lpWorldF->Release(); lpMesh->Release();
lpLt1->Release(); lpLt2->Release(); lpTex->Release();
lpWrap->Release();
return TRUE;
}
// Create frames used in the scene.
void MakeMyFrames(LPDIRECT3DRMFRAME lpScene, LPDIRECT3DRMFRAME lpCam,
LPDIRECT3DRMFRAME * lplpLtFr1, LPDIRECT3DRMFRAME * lplpWorldF)
{
lpD3DRM->CreateFrame(lpScene, lplpLtFr1);
lpD3DRM->CreateFrame(lpScene, lplpWorldF);
}
// MakeMyLights
// Create lights used in the scene.
void MakeMyLights(LPDIRECT3DRMFRAME lpScene, LPDIRECT3DRMFRAME lpCam,
LPDIRECT3DRMFRAME lpLtFr1, LPDIRECT3DRMLIGHT * lplpLt1,
LPDIRECT3DRMLIGHT * lplpLt2) {
lpD3DRM->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL,
D3DVAL(0.9), D3DVAL(0.9), D3DVAL(0.9), lplpLt1);
lpLtFr1->AddLight(*lplpLt1);
lpD3DRM->CreateLightRGB(D3DRMLIGHT_AMBIENT,
D3DVAL(0.1), D3DVAL(0.1), D3DVAL(0.1), lplpLt2);
lpScene->AddLight(*lplpLt2);
}
// Set the positions and orientations of the light, camera, and
// world frames. Establish a rotation for the globe.
void SetMyPositions(LPDIRECT3DRMFRAME lpScene,
LPDIRECT3DRMFRAME lpCam, LPDIRECT3DRMFRAME lpLtFr1,
LPDIRECT3DRMFRAME lpWorldF) {
lpLtFr1->SetPosition(lpScene, D3DVAL(2), D3DVAL(0.0), D3DVAL(22));
lpCam->SetPosition(lpScene, D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0));
lpCam->SetOrientation(lpScene,
D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1),
D3DVAL(0.0), D3DVAL(1), D3DVAL(0.0));
lpWorldF->SetPosition(lpScene, D3DVAL(0.0), D3DVAL(0.0), D3DVAL(15));
lpWorldF->SetOrientation(lpScene,
D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1),
D3DVAL(0.0), D3DVAL(1), D3DVAL(0.0));
lpWorldF->SetRotation(lpScene,
D3DVAL(0.0), D3DVAL(0.1), D3DVAL(0.0), D3DVAL(0.05));
}
// Create MeshBuilder object, load, scale, and color the mesh.
void MakeMyMesh(LPDIRECT3DRMMESHBUILDER * lplpMesh) {
lpD3DRM->CreateMeshBuilder(lplpMesh);
(*lplpMesh)->Load("sphere4.x", NULL, D3DRMLOAD_FROMFILE, NULL, NULL);
(*lplpMesh)->Scale(D3DVAL(2), D3DVAL(2), D3DVAL(2));
// Set sphere to white to avoid unexpected texture-blending results.
(*lplpMesh)->SetColorRGB(D3DVAL(1), D3DVAL(1), D3DVAL(1));
}
// Creates and applies wrap for texture.
void MakeMyWrap(LPDIRECT3DRMMESHBUILDER mesh, LPDIRECT3DRMWRAP * lpWrap)
{
D3DVALUE miny, maxy, height; D3DRMBOX box;
mesh->GetBox(&box);
maxy = box.max.y; miny = box.min.y; height = maxy - miny;
lpD3DRM->CreateWrap(D3DRMWRAP_CYLINDER, NULL,
D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0),
D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0),
D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1.0),
D3DVAL(0.0), D3DDivide(miny, height),
D3DVAL(1.0), D3DDivide(-D3DVAL(1.0), height),
lpWrap);
(*lpWrap)->Apply((LPDIRECT3DRMOBJECT)mesh);
}
// Creates and applies wrap for texture.
void AddMyTexture(LPDIRECT3DRMMESHBUILDER lpMesh,
LPDIRECT3DRMTEXTURE * lplpTex) {
lpD3DRM->LoadTexture("hello.bmp", lplpTex);
lpMesh->SetTexture(*lplpTex);
}
// Release all D3DRM objects and set the bQuit flag.
void CleanUp(void) {
gInfo.scene->Release(); gInfo.camera->Release();
gInfo.view->Release(); gInfo.dev->Release();
lpD3DRM->Release(); lpDDClipper->Release();
gInfo.bInit = FALSE; gInfo.bQuit = TRUE;
}
|
| ®1998 Adam Perer. All rights reserved. This site was designed by Adam Perer, head of The DirectX Developer Page This site is hosted by Geocities |