mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
948 lines
30 KiB
948 lines
30 KiB
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
//-----------------------------------------------------------------------------
|
|
// File: D3DApp.cpp
|
|
//
|
|
// Desc: Application class for the Direct3D samples framework library.
|
|
//
|
|
// Copyright (c) 1998-1999 Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
#define STRICT
|
|
#include <windows.h>
|
|
#include <pbt.h>
|
|
#include <mmsystem.h>
|
|
#include <stdio.h>
|
|
#include <tchar.h>
|
|
#include "D3DApp.h"
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Internal function prototypes and variables
|
|
//-----------------------------------------------------------------------------
|
|
enum APPMSGTYPE { MSG_NONE, MSGERR_APPMUSTEXIT, MSGWARN_SWITCHEDTOSOFTWARE };
|
|
|
|
static INT CALLBACK AboutProc(HWND, UINT, WPARAM, LPARAM);
|
|
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
static CD3DApplication* g_pD3DApp;
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CD3DApplication()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
CD3DApplication::CD3DApplication()
|
|
{
|
|
m_pFramework = NULL;
|
|
m_hWnd = NULL;
|
|
m_pDD = NULL;
|
|
m_pD3D = NULL;
|
|
m_pd3dDevice = NULL;
|
|
|
|
m_pddsRenderTarget = NULL;
|
|
m_pddsRenderTargetLeft = NULL;
|
|
|
|
m_bActive = FALSE;
|
|
m_bReady = FALSE;
|
|
m_bFrameMoving = TRUE;
|
|
m_bSingleStep = FALSE;
|
|
|
|
m_strWindowTitle = TEXT("Direct3D Application");
|
|
m_bAppUseZBuffer = FALSE;
|
|
m_bAppUseStereo = FALSE;
|
|
m_bShowStats = FALSE;
|
|
m_fnConfirmDevice = NULL;
|
|
|
|
g_pD3DApp = this;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Create()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CD3DApplication::Create(HINSTANCE hInst, TCHAR* strCmdLine)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Enumerate available D3D devices. The callback is used so the app can
|
|
// confirm/reject each enumerated device depending on its capabilities.
|
|
if (FAILED(hr = D3DEnum_EnumerateDevices(m_fnConfirmDevice)))
|
|
{
|
|
DisplayFrameworkError(hr, MSGERR_APPMUSTEXIT);
|
|
return hr;
|
|
}
|
|
|
|
// Select a device. Ask for a hardware device that renders in a window.
|
|
if (FAILED(hr = D3DEnum_SelectDefaultDevice(&m_pDeviceInfo)))
|
|
{
|
|
DisplayFrameworkError(hr, MSGERR_APPMUSTEXIT);
|
|
return hr;
|
|
}
|
|
|
|
// Initialize the app's custom scene stuff
|
|
if (FAILED(hr = OneTimeSceneInit()))
|
|
{
|
|
DisplayFrameworkError(hr, MSGERR_APPMUSTEXIT);
|
|
return hr;
|
|
}
|
|
|
|
// Create a new CD3DFramework class. This class does all of our D3D
|
|
// initialization and manages the common D3D objects.
|
|
if (NULL == (m_pFramework = new CD3DFramework7()))
|
|
{
|
|
DisplayFrameworkError(E_OUTOFMEMORY, MSGERR_APPMUSTEXIT);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Register the window class
|
|
WNDCLASS wndClass = { 0, WndProc, 0, 0, hInst,
|
|
LoadIcon(hInst, MAKEINTRESOURCE(IDI_MAIN_ICON)),
|
|
LoadCursor(NULL, IDC_ARROW),
|
|
(HBRUSH)GetStockObject(WHITE_BRUSH),
|
|
NULL, TEXT("D3D Window") };
|
|
RegisterClass(&wndClass);
|
|
|
|
// Create the render window
|
|
m_hWnd = CreateWindow(TEXT("D3D Window"), m_strWindowTitle,
|
|
WS_OVERLAPPEDWINDOW|WS_VISIBLE,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0L,
|
|
LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU)),
|
|
hInst, 0L);
|
|
UpdateWindow(m_hWnd);
|
|
|
|
// Initialize the 3D environment for the app
|
|
if (FAILED(hr = Initialize3DEnvironment()))
|
|
{
|
|
DisplayFrameworkError(hr, MSGERR_APPMUSTEXIT);
|
|
Cleanup3DEnvironment();
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Setup the app so it can support single-stepping
|
|
m_dwBaseTime = timeGetTime();
|
|
|
|
// The app is ready to go
|
|
m_bReady = TRUE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Run()
|
|
// Desc: Message-processing loop. Idle time is used to render the scene.
|
|
//-----------------------------------------------------------------------------
|
|
INT CD3DApplication::Run()
|
|
{
|
|
// Load keyboard accelerators
|
|
HACCEL hAccel = LoadAccelerators(NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL));
|
|
|
|
// Now we're ready to recieve and process Windows messages.
|
|
BOOL bGotMsg;
|
|
MSG msg;
|
|
PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);
|
|
|
|
while(WM_QUIT != msg.message)
|
|
{
|
|
// Use PeekMessage() if the app is active, so we can use idle time to
|
|
// render the scene. Else, use GetMessage() to avoid eating CPU time.
|
|
if (m_bActive)
|
|
bGotMsg = PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE);
|
|
else
|
|
bGotMsg = GetMessage(&msg, NULL, 0U, 0U);
|
|
|
|
if (bGotMsg)
|
|
{
|
|
// Translate and dispatch the message
|
|
if (0 == TranslateAccelerator(m_hWnd, hAccel, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Render a frame during idle time (no messages are waiting)
|
|
if (m_bActive && m_bReady)
|
|
{
|
|
if (FAILED(Render3DEnvironment()))
|
|
DestroyWindow(m_hWnd);
|
|
}
|
|
}
|
|
}
|
|
|
|
return msg.wParam;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: WndProc()
|
|
// Desc: Static msg handler which passes messages to the application class.
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (g_pD3DApp)
|
|
return g_pD3DApp->MsgProc(hWnd, uMsg, wParam, lParam);
|
|
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: AboutProc()
|
|
// Desc: Minimal message proc function for the about box
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CALLBACK AboutProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM)
|
|
{
|
|
if (WM_COMMAND == uMsg)
|
|
if (IDOK == LOWORD(wParam) || IDCANCEL == LOWORD(wParam))
|
|
EndDialog(hWnd, TRUE);
|
|
|
|
return WM_INITDIALOG == uMsg ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: MsgProc()
|
|
// Desc: Message handling function.
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT CD3DApplication::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
HRESULT hr;
|
|
|
|
switch(uMsg)
|
|
{
|
|
case WM_PAINT:
|
|
// Handle paint messages when the app is not ready
|
|
if (m_pFramework && !m_bReady)
|
|
{
|
|
if (m_pDeviceInfo->bWindowed)
|
|
m_pFramework->ShowFrame();
|
|
else
|
|
m_pFramework->FlipToGDISurface(TRUE);
|
|
}
|
|
break;
|
|
|
|
case WM_MOVE:
|
|
// If in windowed mode, move the Framework's window
|
|
if (m_pFramework && m_bActive && m_bReady && m_pDeviceInfo->bWindowed)
|
|
m_pFramework->Move((SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
// Check to see if we are losing our window...
|
|
if (SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam)
|
|
m_bActive = FALSE;
|
|
else
|
|
m_bActive = TRUE;
|
|
|
|
// A new window size will require a new backbuffer
|
|
// size, so the 3D structures must be changed accordingly.
|
|
if (m_bActive && m_bReady && m_pDeviceInfo->bWindowed)
|
|
{
|
|
m_bReady = FALSE;
|
|
|
|
if (FAILED(hr = Change3DEnvironment()))
|
|
return 0;
|
|
|
|
m_bReady = TRUE;
|
|
}
|
|
break;
|
|
|
|
case WM_SETCURSOR:
|
|
// Prevent a cursor in fullscreen mode
|
|
if (m_bActive && m_bReady && !m_pDeviceInfo->bWindowed)
|
|
{
|
|
SetCursor(NULL);
|
|
return 1;
|
|
}
|
|
break;
|
|
|
|
case WM_ENTERMENULOOP:
|
|
// Pause the app when menus are displayed
|
|
Pause(TRUE);
|
|
break;
|
|
case WM_EXITMENULOOP:
|
|
Pause(FALSE);
|
|
break;
|
|
|
|
case WM_ENTERSIZEMOVE:
|
|
// Halt frame movement while the app is sizing or moving
|
|
if (m_bFrameMoving)
|
|
m_dwStopTime = timeGetTime();
|
|
break;
|
|
case WM_EXITSIZEMOVE:
|
|
if (m_bFrameMoving)
|
|
m_dwBaseTime += timeGetTime() - m_dwStopTime;
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
// Handle the app's context menu (via right mouse click)
|
|
TrackPopupMenuEx(
|
|
GetSubMenu(LoadMenu(0, MAKEINTRESOURCE(IDR_POPUP)), 0),
|
|
TPM_VERTICAL, LOWORD(lParam), HIWORD(lParam), hWnd, NULL);
|
|
break;
|
|
|
|
case WM_NCHITTEST:
|
|
// Prevent the user from selecting the menu in fullscreen mode
|
|
if (!m_pDeviceInfo->bWindowed)
|
|
return HTCLIENT;
|
|
|
|
break;
|
|
|
|
case WM_POWERBROADCAST:
|
|
switch(wParam)
|
|
{
|
|
case PBT_APMQUERYSUSPEND:
|
|
// At this point, the app should save any data for open
|
|
// network connections, files, etc.., and prepare to go into
|
|
// a suspended mode.
|
|
return OnQuerySuspend((DWORD)lParam);
|
|
|
|
case PBT_APMRESUMESUSPEND:
|
|
// At this point, the app should recover any data, network
|
|
// connections, files, etc.., and resume running from when
|
|
// the app was suspended.
|
|
return OnResumeSuspend((DWORD)lParam);
|
|
}
|
|
break;
|
|
|
|
case WM_SYSCOMMAND:
|
|
// Prevent moving/sizing and power loss in fullscreen mode
|
|
switch(wParam)
|
|
{
|
|
case SC_MOVE:
|
|
case SC_SIZE:
|
|
case SC_MAXIMIZE:
|
|
case SC_MONITORPOWER:
|
|
if (FALSE == m_pDeviceInfo->bWindowed)
|
|
return 1;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDM_TOGGLESTART:
|
|
// Toggle frame movement
|
|
m_bFrameMoving = !m_bFrameMoving;
|
|
|
|
if (m_bFrameMoving)
|
|
m_dwBaseTime += timeGetTime() - m_dwStopTime;
|
|
else
|
|
m_dwStopTime = timeGetTime();
|
|
break;
|
|
|
|
case IDM_SINGLESTEP:
|
|
// Single-step frame movement
|
|
if (FALSE == m_bFrameMoving)
|
|
m_dwBaseTime += timeGetTime() - (m_dwStopTime + 100);
|
|
|
|
m_dwStopTime = timeGetTime();
|
|
m_bFrameMoving = FALSE;
|
|
m_bSingleStep = TRUE;
|
|
break;
|
|
|
|
case IDM_CHANGEDEVICE:
|
|
// Display the device-selection dialog box.
|
|
if (m_bActive && m_bReady)
|
|
{
|
|
Pause(TRUE);
|
|
|
|
if (SUCCEEDED(D3DEnum_UserChangeDevice(&m_pDeviceInfo)))
|
|
{
|
|
if (FAILED(hr = Change3DEnvironment()))
|
|
return 0;
|
|
}
|
|
Pause(FALSE);
|
|
}
|
|
return 0;
|
|
|
|
case IDM_TOGGLEFULLSCREEN:
|
|
// Toggle the fullscreen/window mode
|
|
if (m_bActive && m_bReady)
|
|
{
|
|
m_bReady = FALSE;
|
|
|
|
m_pDeviceInfo->bWindowed = !m_pDeviceInfo->bWindowed;
|
|
|
|
if (FAILED(hr = Change3DEnvironment()))
|
|
return 0;
|
|
|
|
m_bReady = TRUE;
|
|
}
|
|
return 0;
|
|
|
|
case IDM_ABOUT:
|
|
// Display the About box
|
|
Pause(TRUE);
|
|
DialogBox((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
|
|
MAKEINTRESOURCE(IDD_ABOUT), hWnd, AboutProc);
|
|
Pause(FALSE);
|
|
return 0;
|
|
|
|
case IDM_EXIT:
|
|
// Recieved key/menu command to exit app
|
|
SendMessage(hWnd, WM_CLOSE, 0, 0);
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case WM_GETMINMAXINFO:
|
|
((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
|
|
((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
DestroyWindow(hWnd);
|
|
return 0;
|
|
|
|
case WM_DESTROY:
|
|
Cleanup3DEnvironment();
|
|
PostQuitMessage(0);
|
|
return 0;
|
|
}
|
|
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Initialize3DEnvironment()
|
|
// Desc: Initializes the sample framework, then calls the app-specific function
|
|
// to initialize device specific objects. This code is structured to
|
|
// handled any errors that may occur duing initialization
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CD3DApplication::Initialize3DEnvironment()
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwFrameworkFlags = 0L;
|
|
dwFrameworkFlags |= (!m_pDeviceInfo->bWindowed ? D3DFW_FULLSCREEN : 0L);
|
|
dwFrameworkFlags |= (m_pDeviceInfo->bStereo ? D3DFW_STEREO : 0L);
|
|
dwFrameworkFlags |= (m_bAppUseZBuffer ? D3DFW_ZBUFFER : 0L);
|
|
|
|
// Initialize the D3D framework
|
|
if (SUCCEEDED(hr = m_pFramework->Initialize(m_hWnd,
|
|
m_pDeviceInfo->pDriverGUID, m_pDeviceInfo->pDeviceGUID,
|
|
&m_pDeviceInfo->ddsdFullscreenMode, dwFrameworkFlags)))
|
|
{
|
|
m_pDD = m_pFramework->GetDirectDraw();
|
|
m_pD3D = m_pFramework->GetDirect3D();
|
|
m_pd3dDevice = m_pFramework->GetD3DDevice();
|
|
|
|
m_pddsRenderTarget = m_pFramework->GetRenderSurface();
|
|
m_pddsRenderTargetLeft = m_pFramework->GetRenderSurfaceLeft();
|
|
|
|
m_ddsdRenderTarget.dwSize = sizeof(m_ddsdRenderTarget);
|
|
m_pddsRenderTarget->GetSurfaceDesc(&m_ddsdRenderTarget);
|
|
|
|
// Let the app run its startup code which creates the 3d scene.
|
|
if (SUCCEEDED(hr = InitDeviceObjects()))
|
|
return S_OK;
|
|
else
|
|
{
|
|
DeleteDeviceObjects();
|
|
m_pFramework->DestroyObjects();
|
|
}
|
|
}
|
|
|
|
// If we get here, the first initialization passed failed. If that was with a
|
|
// hardware device, try again using a software rasterizer instead.
|
|
if (m_pDeviceInfo->bHardware)
|
|
{
|
|
// Try again with a software rasterizer
|
|
DisplayFrameworkError(hr, MSGWARN_SWITCHEDTOSOFTWARE);
|
|
D3DEnum_SelectDefaultDevice(&m_pDeviceInfo, D3DENUM_SOFTWAREONLY);
|
|
return Initialize3DEnvironment();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Change3DEnvironment()
|
|
// Desc: Handles driver, device, and/or mode changes for the app.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CD3DApplication::Change3DEnvironment()
|
|
{
|
|
HRESULT hr;
|
|
static BOOL bOldWindowedState = TRUE;
|
|
static DWORD dwSavedStyle;
|
|
static RECT rcSaved;
|
|
|
|
// Release all scene objects that will be re-created for the new device
|
|
DeleteDeviceObjects();
|
|
|
|
// Release framework objects, so a new device can be created
|
|
if (FAILED(hr = m_pFramework->DestroyObjects()))
|
|
{
|
|
DisplayFrameworkError(hr, MSGERR_APPMUSTEXIT);
|
|
SendMessage(m_hWnd, WM_CLOSE, 0, 0);
|
|
return hr;
|
|
}
|
|
|
|
// Check if going from fullscreen to windowed mode, or vice versa.
|
|
if (bOldWindowedState != m_pDeviceInfo->bWindowed)
|
|
{
|
|
if (m_pDeviceInfo->bWindowed)
|
|
{
|
|
// Coming from fullscreen mode, so restore window properties
|
|
SetWindowLong(m_hWnd, GWL_STYLE, dwSavedStyle);
|
|
SetWindowPos(m_hWnd, HWND_NOTOPMOST, rcSaved.left, rcSaved.top,
|
|
(rcSaved.right - rcSaved.left),
|
|
(rcSaved.bottom - rcSaved.top), SWP_SHOWWINDOW);
|
|
}
|
|
else
|
|
{
|
|
// Going to fullscreen mode, save/set window properties as needed
|
|
dwSavedStyle = GetWindowLong(m_hWnd, GWL_STYLE);
|
|
GetWindowRect(m_hWnd, &rcSaved);
|
|
SetWindowLong(m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE);
|
|
}
|
|
|
|
bOldWindowedState = m_pDeviceInfo->bWindowed;
|
|
}
|
|
|
|
// Inform the framework class of the driver change. It will internally
|
|
// re-create valid surfaces, a d3ddevice, etc.
|
|
if (FAILED(hr = Initialize3DEnvironment()))
|
|
{
|
|
DisplayFrameworkError(hr, MSGERR_APPMUSTEXIT);
|
|
SendMessage(m_hWnd, WM_CLOSE, 0, 0);
|
|
return hr;
|
|
}
|
|
|
|
// If the app is paused, trigger the rendering of the current frame
|
|
if (FALSE == m_bFrameMoving)
|
|
{
|
|
m_bSingleStep = TRUE;
|
|
m_dwBaseTime += timeGetTime() - m_dwStopTime;
|
|
m_dwStopTime = timeGetTime();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Render3DEnvironment()
|
|
// Desc: Draws the scene.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CD3DApplication::Render3DEnvironment()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Check the cooperative level before rendering
|
|
if (FAILED(hr = m_pDD->TestCooperativeLevel()))
|
|
{
|
|
switch(hr)
|
|
{
|
|
case DDERR_EXCLUSIVEMODEALREADYSET:
|
|
case DDERR_NOEXCLUSIVEMODE:
|
|
// Do nothing because some other app has exclusive mode
|
|
return S_OK;
|
|
|
|
case DDERR_WRONGMODE:
|
|
// The display mode changed on us. Resize accordingly
|
|
if (m_pDeviceInfo->bWindowed)
|
|
return Change3DEnvironment();
|
|
break;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// Get the relative time, in seconds
|
|
FLOAT fTime = (timeGetTime() - m_dwBaseTime) * 0.001f;
|
|
|
|
// FrameMove (animate) the scene
|
|
if (m_bFrameMoving || m_bSingleStep)
|
|
{
|
|
if (FAILED(hr = FrameMove(fTime)))
|
|
return hr;
|
|
|
|
m_bSingleStep = FALSE;
|
|
}
|
|
|
|
// If the display is in a stereo mode, render the scene from the left eye
|
|
// first, then the right eye.
|
|
if (m_bAppUseStereo && m_pDeviceInfo->bStereo && !m_pDeviceInfo->bWindowed)
|
|
{
|
|
// Render the scene from the left eye
|
|
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matLeftView);
|
|
if (FAILED(hr = m_pd3dDevice->SetRenderTarget(m_pddsRenderTargetLeft, 0)))
|
|
return hr;
|
|
if (FAILED(hr = Render()))
|
|
return hr;
|
|
|
|
//Render the scene from the right eye
|
|
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matRightView);
|
|
if (FAILED(hr = m_pd3dDevice->SetRenderTarget(m_pddsRenderTarget, 0)))
|
|
return hr;
|
|
if (FAILED(hr = Render()))
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
// Set center viewing matrix if app is stereo-enabled
|
|
if (m_bAppUseStereo)
|
|
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matView);
|
|
|
|
// Render the scene as normal
|
|
if (FAILED(hr = Render()))
|
|
return hr;
|
|
}
|
|
|
|
// Show the frame rate, etc.
|
|
if (m_bShowStats)
|
|
ShowStats();
|
|
|
|
// Show the frame on the primary surface.
|
|
if (FAILED(hr = m_pFramework->ShowFrame()))
|
|
{
|
|
if (DDERR_SURFACELOST != hr)
|
|
return hr;
|
|
|
|
m_pFramework->RestoreSurfaces();
|
|
RestoreSurfaces();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Cleanup3DEnvironment()
|
|
// Desc: Cleanup scene objects
|
|
//-----------------------------------------------------------------------------
|
|
VOID CD3DApplication::Cleanup3DEnvironment()
|
|
{
|
|
m_bActive = FALSE;
|
|
m_bReady = FALSE;
|
|
|
|
if (m_pFramework)
|
|
{
|
|
DeleteDeviceObjects();
|
|
SAFE_DELETE(m_pFramework);
|
|
|
|
FinalCleanup();
|
|
}
|
|
|
|
D3DEnum_FreeResources();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Pause()
|
|
// Desc: Called in to toggle the pause state of the app. This function
|
|
// brings the GDI surface to the front of the display, so drawing
|
|
// output like message boxes and menus may be displayed.
|
|
//-----------------------------------------------------------------------------
|
|
VOID CD3DApplication::Pause(BOOL bPause)
|
|
{
|
|
static DWORD dwAppPausedCount = 0L;
|
|
|
|
dwAppPausedCount += (bPause ? +1 : -1);
|
|
m_bReady = (dwAppPausedCount ? FALSE : TRUE);
|
|
|
|
// Handle the first pause request (of many, nestable pause requests)
|
|
if (bPause && (1 == dwAppPausedCount))
|
|
{
|
|
// Get a surface for the GDI
|
|
if (m_pFramework)
|
|
m_pFramework->FlipToGDISurface(TRUE);
|
|
|
|
// Stop the scene from animating
|
|
if (m_bFrameMoving)
|
|
m_dwStopTime = timeGetTime();
|
|
}
|
|
|
|
if (0 == dwAppPausedCount)
|
|
{
|
|
// Restart the scene
|
|
if (m_bFrameMoving)
|
|
m_dwBaseTime += timeGetTime() - m_dwStopTime;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: OnQuerySuspend()
|
|
// Desc: Called when the app receives a PBT_APMQUERYSUSPEND message, meaning
|
|
// the computer is about to be suspended. At this point, the app should
|
|
// save any data for open network connections, files, etc.., and prepare
|
|
// to go into a suspended mode.
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT CD3DApplication::OnQuerySuspend(DWORD dwFlags)
|
|
{
|
|
Pause(TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: OnResumeSuspend()
|
|
// Desc: Called when the app receives a PBT_APMRESUMESUSPEND message, meaning
|
|
// the computer has just resumed from a suspended state. At this point,
|
|
// the app should recover any data, network connections, files, etc..,
|
|
// and resume running from when the app was suspended.
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT CD3DApplication::OnResumeSuspend(DWORD dwData)
|
|
{
|
|
Pause(FALSE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: ShowStats()
|
|
// Desc: Shows frame rate and dimensions of the rendering device.
|
|
//-----------------------------------------------------------------------------
|
|
VOID CD3DApplication::ShowStats()
|
|
{
|
|
static FLOAT fFPS = 0.0f;
|
|
static FLOAT fLastTime = 0.0f;
|
|
static DWORD dwFrames = 0L;
|
|
|
|
// Keep track of the time lapse and frame count
|
|
FLOAT fTime = timeGetTime() * 0.001f; // Get current time in seconds
|
|
++dwFrames;
|
|
|
|
// Update the frame rate once per second
|
|
if (fTime - fLastTime > 1.0f)
|
|
{
|
|
fFPS = dwFrames / (fTime - fLastTime);
|
|
fLastTime = fTime;
|
|
dwFrames = 0L;
|
|
}
|
|
|
|
// Setup the text buffer to write out dimensions
|
|
TCHAR buffer[80];
|
|
sprintf(buffer, TEXT("%7.02f fps (%dx%dx%d)"), fFPS,
|
|
m_ddsdRenderTarget.dwWidth, m_ddsdRenderTarget.dwHeight,
|
|
m_ddsdRenderTarget.ddpfPixelFormat.dwRGBBitCount);
|
|
OutputText(0, 0, buffer);
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: OutputText()
|
|
// Desc: Draws text on the window.
|
|
//-----------------------------------------------------------------------------
|
|
VOID CD3DApplication::OutputText(DWORD x, DWORD y, TCHAR* str)
|
|
{
|
|
HDC hDC;
|
|
|
|
// Get a DC for the surface. Then, write out the buffer
|
|
if (m_pddsRenderTarget)
|
|
{
|
|
if (SUCCEEDED(m_pddsRenderTarget->GetDC(&hDC)))
|
|
{
|
|
SetTextColor(hDC, RGB(255,255,0));
|
|
SetBkMode(hDC, TRANSPARENT);
|
|
ExtTextOut(hDC, x, y, 0, NULL, str, lstrlen(str), NULL);
|
|
m_pddsRenderTarget->ReleaseDC(hDC);
|
|
}
|
|
}
|
|
|
|
// Do the same for the left surface (in case of stereoscopic viewing).
|
|
if (m_pddsRenderTargetLeft)
|
|
{
|
|
if (SUCCEEDED(m_pddsRenderTargetLeft->GetDC(&hDC)))
|
|
{
|
|
// Use a different color to help distinguish left eye view
|
|
SetTextColor(hDC, RGB(255,0,255));
|
|
SetBkMode(hDC, TRANSPARENT);
|
|
ExtTextOut(hDC, x, y, 0, NULL, str, lstrlen(str), NULL);
|
|
m_pddsRenderTargetLeft->ReleaseDC(hDC);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DisplayFrameworkError()
|
|
// Desc: Displays error messages in a message box
|
|
//-----------------------------------------------------------------------------
|
|
VOID CD3DApplication::DisplayFrameworkError(HRESULT hr, DWORD dwType)
|
|
{
|
|
TCHAR strMsg[512];
|
|
|
|
switch(hr)
|
|
{
|
|
case D3DENUMERR_NODIRECTDRAW:
|
|
lstrcpy(strMsg, TEXT("Could not create DirectDraw!"));
|
|
break;
|
|
case D3DENUMERR_NOCOMPATIBLEDEVICES:
|
|
lstrcpy(strMsg, TEXT("Could not find any compatible Direct3D\n"
|
|
"devices."));
|
|
break;
|
|
case D3DENUMERR_SUGGESTREFRAST:
|
|
lstrcpy(strMsg, TEXT("Could not find any compatible devices.\n\n"
|
|
"Try enabling the reference rasterizer using\n"
|
|
"EnableRefRast.reg."));
|
|
break;
|
|
case D3DENUMERR_ENUMERATIONFAILED:
|
|
lstrcpy(strMsg, TEXT("Enumeration failed. Your system may be in an\n"
|
|
"unstable state and need to be rebooted"));
|
|
break;
|
|
case D3DFWERR_INITIALIZATIONFAILED:
|
|
lstrcpy(strMsg, TEXT("Generic initialization error.\n\nEnable "
|
|
"debug output for detailed information."));
|
|
break;
|
|
case D3DFWERR_NODIRECTDRAW:
|
|
lstrcpy(strMsg, TEXT("No DirectDraw"));
|
|
break;
|
|
case D3DFWERR_NODIRECT3D:
|
|
lstrcpy(strMsg, TEXT("No Direct3D"));
|
|
break;
|
|
case D3DFWERR_INVALIDMODE:
|
|
lstrcpy(strMsg, TEXT("This sample requires a 16-bit (or higher) "
|
|
"display mode\nto run in a window.\n\nPlease "
|
|
"switch your desktop settings accordingly."));
|
|
break;
|
|
case D3DFWERR_COULDNTSETCOOPLEVEL:
|
|
lstrcpy(strMsg, TEXT("Could not set Cooperative Level"));
|
|
break;
|
|
case D3DFWERR_NO3DDEVICE:
|
|
lstrcpy(strMsg, TEXT("Could not create the Direct3DDevice object."));
|
|
|
|
if (MSGWARN_SWITCHEDTOSOFTWARE == dwType)
|
|
lstrcat(strMsg, TEXT("\nThe 3D hardware chipset may not support"
|
|
"\nrendering in the current display mode."));
|
|
break;
|
|
case D3DFWERR_NOZBUFFER:
|
|
lstrcpy(strMsg, TEXT("No ZBuffer"));
|
|
break;
|
|
case D3DFWERR_INVALIDZBUFFERDEPTH:
|
|
lstrcpy(strMsg, TEXT("Invalid Z-buffer depth. Try switching modes\n"
|
|
"from 16- to 32-bit (or vice versa)"));
|
|
break;
|
|
case D3DFWERR_NOVIEWPORT:
|
|
lstrcpy(strMsg, TEXT("No Viewport"));
|
|
break;
|
|
case D3DFWERR_NOPRIMARY:
|
|
lstrcpy(strMsg, TEXT("No primary"));
|
|
break;
|
|
case D3DFWERR_NOCLIPPER:
|
|
lstrcpy(strMsg, TEXT("No Clipper"));
|
|
break;
|
|
case D3DFWERR_BADDISPLAYMODE:
|
|
lstrcpy(strMsg, TEXT("Bad display mode"));
|
|
break;
|
|
case D3DFWERR_NOBACKBUFFER:
|
|
lstrcpy(strMsg, TEXT("No backbuffer"));
|
|
break;
|
|
case D3DFWERR_NONZEROREFCOUNT:
|
|
lstrcpy(strMsg, TEXT("A DDraw object has a non-zero reference\n"
|
|
"count (meaning it was not properly cleaned up)."));
|
|
break;
|
|
case D3DFWERR_NORENDERTARGET:
|
|
lstrcpy(strMsg, TEXT("No render target"));
|
|
break;
|
|
case E_OUTOFMEMORY:
|
|
lstrcpy(strMsg, TEXT("Not enough memory!"));
|
|
break;
|
|
case DDERR_OUTOFVIDEOMEMORY:
|
|
lstrcpy(strMsg, TEXT("There was insufficient video memory "
|
|
"to use the\nhardware device."));
|
|
break;
|
|
default:
|
|
lstrcpy(strMsg, TEXT("Generic application error.\n\nEnable "
|
|
"debug output for detailed information."));
|
|
}
|
|
|
|
if (MSGERR_APPMUSTEXIT == dwType)
|
|
{
|
|
lstrcat(strMsg, TEXT("\n\nThis sample will now exit."));
|
|
MessageBox(NULL, strMsg, m_strWindowTitle, MB_ICONERROR|MB_OK);
|
|
}
|
|
else
|
|
{
|
|
if (MSGWARN_SWITCHEDTOSOFTWARE == dwType)
|
|
lstrcat(strMsg, TEXT("\n\nSwitching to software rasterizer."));
|
|
MessageBox(NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: SetViewParams()
|
|
// Desc: Sets the parameters to be used by the SetViewMatrix() function. You
|
|
// must call this function rather than setting the D3D view matrix
|
|
// yourself in order for stereo modes to work properly.
|
|
//-----------------------------------------------------------------------------
|
|
VOID CD3DApplication::SetViewParams(D3DVECTOR* vEyePt, D3DVECTOR* vLookatPt,
|
|
D3DVECTOR* vUpVec, FLOAT fEyeDistance)
|
|
{
|
|
// Adjust camera position for left or right eye along the axis
|
|
// perpendicular to the view direction vector and the up vector.
|
|
D3DVECTOR vView = (*vLookatPt) - (*vEyePt);
|
|
vView = CrossProduct(vView, (*vUpVec));
|
|
vView = Normalize(vView) * fEyeDistance;
|
|
|
|
D3DVECTOR vLeftEyePt = (*vEyePt) + vView;
|
|
D3DVECTOR vRightEyePt = (*vEyePt) - vView;
|
|
|
|
// Set the view matrices
|
|
D3DUtil_SetViewMatrix(m_matLeftView, vLeftEyePt, *vLookatPt, *vUpVec);
|
|
D3DUtil_SetViewMatrix(m_matRightView, vRightEyePt, *vLookatPt, *vUpVec);
|
|
D3DUtil_SetViewMatrix(m_matView, *vEyePt, *vLookatPt, *vUpVec);
|
|
}
|
|
|
|
|
|
#endif
|