the DirectX eXperience Site News Articles Cheap Bookstore (20% Off!) DirectX Resources Tips Contribute here! About this Site Feedback Our Nifty Sponsors Become a Sponsor

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