您的位置:首页 > 其它

DXUT 主程序源文件结构分析

2014-02-27 10:05 309 查看
分析文件来自于DirectX Sample Browser下的 Pick例程:

第一部分:头文件及帮助编译的宏定义

//--------------------------------------------------------------------------------------
// File: Pick.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include "DXUT.h"
#include "DXUTcamera.h"
#include "DXUTsettingsdlg.h"
#include "SDKmesh.h"
#include "SDKmisc.h"
#include "resource.h"

//#define DEBUG_VS   // Uncomment this line to debug vertex shaders
//#define DEBUG_PS   // Uncomment this line to debug pixel shaders


这一部分出现的宏定义是帮助帮助编译器进行某些操作的,此处两个宏定义被注释了。没有被注释时的功能是对vertex shader 和pixel shader进行debug。这两个过程究竟是怎么进行的,暂时还没查到相关资料。

//TODO

//#define DEBUG_VS   // Uncomment this line to debug vertex shaders
//#define DEBUG_PS   // Uncomment this line to debug pixel shaders


第二部分:定义和声明用户自定义的结构体以及用户预设宏定义

//--------------------------------------------------------------------------------------
// Vertex format
//--------------------------------------------------------------------------------------
struct D3DVERTEX
{
D3DXVECTOR3 p;
D3DXVECTOR3 n;
FLOAT tu, tv;

static const DWORD FVF;
};
const DWORD                 D3DVERTEX::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;

struct INTERSECTION
{
DWORD dwFace;                 // mesh face that was intersected
FLOAT fBary1, fBary2;         // barycentric coords of intersection
FLOAT fDist;                  // distance from ray origin to intersection
FLOAT tu, tv;                 // texture coords of intersection
};

// For simplicity's sake, we limit the number of simultaneously intersected
// triangles to 16
#define MAX_INTERSECTIONS 16
#define CAMERA_DISTANCE 3.5f


在这部分定义和声明游湖自定义的相关简单的结构体,如例程中声明了一个灵活的定点格式的结构体和一个焦点结构体。

用户在这部分声明的宏定义带有自定性。

第三部分:全局变量声明区

//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
ID3DXFont*                  g_pFont = NULL;         // Font for drawing text
ID3DXSprite*                g_pTextSprite = NULL;   // Sprite for batching draw text calls
ID3DXEffect*                g_pEffect = NULL;       // D3DX effect interface
CDXUTXFileMesh              g_Mesh;                 // The mesh to be rendered
CModelViewerCamera          g_Camera;               // A model viewing camera
DWORD                       g_dwNumIntersections;   // Number of faces intersected
INTERSECTION g_IntersectionArray[MAX_INTERSECTIONS]; // Intersection info
LPDIRECT3DVERTEXBUFFER9     g_pVB;                  // VB for Picked triangles
bool                        g_bShowHelp = true;     // If true, it renders the UI control text
bool                        g_bUseD3DXIntersect = true;      // Whether to use D3DXIntersect
bool                        g_bAllHits = true;      // Whether to just get the first "hit" or all "hits"
CDXUTDialogResourceManager  g_DialogResourceManager; // manager for shared resources of dialogs
CD3DSettingsDlg             g_SettingsDlg;          // Device settings dialog
CDXUTDialog                 g_HUD;                  // dialog for standard controls
CDXUTDialog                 g_SampleUI;             // dialog for sample specific controls


第四部分:UI控件 ID声明区

//--------------------------------------------------------------------------------------
// UI control IDs
//--------------------------------------------------------------------------------------
#define IDC_TOGGLEFULLSCREEN    1
#define IDC_TOGGLEREF           2
#define IDC_CHANGEDEVICE        3
#define IDC_USED3DX             4
#define IDC_ALLHITS             5


关于UI:思考了下自定义UI的设计方法,而且还看了看DXUT中自定义控件的设计文档,感觉学到了很多。比如控件一定是依附于对话框,设计控件类时从最基础的控件原型开始,其他它控件继承父类控件最终形成所需的控件。后面会写一个关于自定义控件写法的随笔。

第五部分:函数声明区

//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed,
void* pUserContext );
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext );
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext );
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext );
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext );
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing,
void* pUserContext );
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext );
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext );
void CALLBACK OnLostDevice( void* pUserContext );
void CALLBACK OnDestroyDevice( void* pUserContext );

void InitApp();
void RenderText();
HRESULT Pick();
bool IntersectTriangle( const D3DXVECTOR3& orig, const D3DXVECTOR3& dir,
D3DXVECTOR3& v0, D3DXVECTOR3& v1, D3DXVECTOR3& v2,
FLOAT* t, FLOAT* u, FLOAT* v );


后面有各函数的详细定义。

部分主要模块执行顺序:

函数名称正常执行顺序改变窗口大小显示设备对话框程序退出

InitApp1
OnCreateDevice2
OnResetDevice322
OnFrameMove4
OnFrameRender 5
MsgProc
KeyboardProc
OnGUIEvent
OnLostDevice6111
OnDestroyDevice72

第六部分:程序入口函数

//--------------------------------------------------------------------------------------
// Entry point to the program. Initializes everything and goes into a message processing
// loop. Idle time is used to render the scene.
//--------------------------------------------------------------------------------------
INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
{
// Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

// Set the callback functions. These functions allow DXUT to notify
// the application about device changes, user input, and windows messages.  The
// callbacks are optional so you need only set callbacks for events you're interested
// in. However, if you don't handle the device reset/lost callbacks then the sample
// framework won't be able to reset your device since the application must first
// release all device resources before resetting.  Likewise, if you don't handle the
// device created/destroyed callbacks then DXUT won't be able to
// recreate your device resources.
DXUTSetCallbackD3D9DeviceAcceptable( IsDeviceAcceptable );
DXUTSetCallbackD3D9DeviceCreated( OnCreateDevice );
DXUTSetCallbackD3D9DeviceReset( OnResetDevice );
DXUTSetCallbackD3D9FrameRender( OnFrameRender );
DXUTSetCallbackD3D9DeviceLost( OnLostDevice );
DXUTSetCallbackD3D9DeviceDestroyed( OnDestroyDevice );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackKeyboard( KeyboardProc );
DXUTSetCallbackFrameMove( OnFrameMove );
DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );

// Show the cursor and clip it when in full screen
DXUTSetCursorSettings( true, true );

InitApp();

// Initialize DXUT and create the desired Win32 window and Direct3D
// device for the application. Calling each of these functions is optional, but they
// allow you to set several options which control the behavior of the framework.
DXUTInit( true, true ); // Parse the command line and show msgboxes
DXUTSetHotkeyHandling( true, true, true );  // handle the defaul hotkeys
DXUTCreateWindow( L"Pick" );
DXUTCreateDevice( true, 640, 480 );

// Pass control to DXUT for handling the message pump and
// dispatching render calls. DXUT will call your FrameMove
// and FrameRender callback when there is idle time between handling window messages.
DXUTMainLoop();

// Perform any application-level cleanup here. Direct3D device resources are released within the
// appropriate callback functions and therefore don't require any cleanup code here.

return DXUTGetExitCode();
}


程序中注释的翻译:

  设置回调函数。这些函数允许DXUT通知设备的变化,用户输入的应用程序,和windows消息。回调是可选的,你只需要为你感兴趣的事件设置回调函数。然而,如果你不处理设备的复位/失去(reset和lost)回调函数的话,框架会无法复位你的设备,因为应用程序在复位前必须释放所有的设备资源。同样的,如果你不处理设备创建/销毁回调函数,DXUT不能重建你的设备资源。

这些函数的基本描述:

OnCreateDevice()用于初始化应用程序资源,如装载模型、纹理和效果文件的变异等,程序只执行一次

OnResetDevice()用于复位设备,在窗口调整时会调用,多次。

OnFrameMove()根据时间设置变换矩阵,使场景具有动画效果。

OnFrameRender()用于渲染。

OnLostDevice()在检测到设备丢失时释放部分资源。

OnDestroyDevice()释放相关资源,如字体等以组件方式释放

第七部分:应用程序初始化InitApp()

//--------------------------------------------------------------------------------------
// Initialize the app
//--------------------------------------------------------------------------------------
void InitApp()
{
// Initialize dialogs
g_SettingsDlg.Init( &g_DialogResourceManager );
g_HUD.Init( &g_DialogResourceManager );
g_SampleUI.Init( &g_DialogResourceManager );

g_HUD.SetCallback( OnGUIEvent ); int iY = 10;
g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22, VK_F2 );
g_HUD.AddCheckBox( IDC_USED3DX, L"Use D3DXIntersect", 35, iY += 24, 125, 22, g_bUseD3DXIntersect, VK_F4 );
g_HUD.AddCheckBox( IDC_ALLHITS, L"Show All Hits", 35, iY += 24, 125, 22, g_bAllHits, VK_F5 );

g_SampleUI.SetCallback( OnGUIEvent ); iY = 10;
}


对用户UI进参数填充。HUD

第八部分:回调函数IsDeviceAcceptable()

//--------------------------------------------------------------------------------------
// Called during device initialization, this code checks the device for some
// minimum set of capabilities, and rejects those that don't pass by returning false.
//--------------------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
{
// Skip backbuffer formats that don't support alpha blending
IDirect3D9* pD3D = DXUTGetD3D9Object();
if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
return false;

// No fallback defined by this app, so reject any device that
// doesn't support at least ps2.0
if( pCaps->PixelShaderVersion < D3DPS_VERSION( 2, 0 ) )
return false;

return true;
}


第九部分:回调函数ModifyDeviceSettings()

//--------------------------------------------------------------------------------------
// This callback function is called immediately before a device is created to allow the
// application to modify the device settings. The supplied pDeviceSettings parameter
// contains the settings that the framework has selected for the new device, and the
// application can make any desired changes directly to this structure.  Note however that
// DXUT will not correct invalid device settings so care must be taken
// to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
{
assert( DXUT_D3D9_DEVICE == pDeviceSettings->ver );

HRESULT hr;
IDirect3D9* pD3D = DXUTGetD3D9Object();
D3DCAPS9 caps;

V( pD3D->GetDeviceCaps( pDeviceSettings->d3d9.AdapterOrdinal,
pDeviceSettings->d3d9.DeviceType,
&caps ) );

// If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW
// then switch to SWVP.
if( ( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) == 0 ||
caps.VertexShaderVersion < D3DVS_VERSION( 1, 1 ) )
{
pDeviceSettings->d3d9.BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}

// Debugging vertex shaders requires either REF or software vertex processing
// and debugging pixel shaders requires REF.
#ifdef DEBUG_VS
if( pDeviceSettings->d3d9.DeviceType != D3DDEVTYPE_REF )
{
pDeviceSettings->d3d9.BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
pDeviceSettings->d3d9.BehaviorFlags &= ~D3DCREATE_PUREDEVICE;
pDeviceSettings->d3d9.BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
#endif
#ifdef DEBUG_PS
pDeviceSettings->d3d9.DeviceType = D3DDEVTYPE_REF;
#endif

// For the first device created if its a REF device, optionally display a warning dialog box
static bool s_bFirstTime = true;
if( s_bFirstTime )
{
s_bFirstTime = false;
if( pDeviceSettings->d3d9.DeviceType == D3DDEVTYPE_REF )
DXUTDisplaySwitchingToREFWarning( pDeviceSettings->ver );
}

return true;
}


第十部分:回调函数OnCreateDevice()

//--------------------------------------------------------------------------------------
// This callback function will be called immediately after the Direct3D device has been
// created, which will happen during application initialization and windowed/full screen
// toggles. This is the best location to create D3DPOOL_MANAGED resources since these
// resources need to be reloaded whenever the device is destroyed. Resources created
// here should be released in the OnDestroyDevice callback.
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext )
{
WCHAR str[MAX_PATH];
HRESULT hr;

V_RETURN( g_DialogResourceManager.OnD3D9CreateDevice( pd3dDevice ) );
V_RETURN( g_SettingsDlg.OnD3D9CreateDevice( pd3dDevice ) );

// Initialize the font
V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
L"Arial", &g_pFont ) );

// Load the mesh with D3DX and get back a ID3DXMesh*.  For this
// sample we'll ignore the X file's embedded materials since we know
// exactly the model we're loading.  See the mesh samples such as
// "OptimizedMesh" for a more generic mesh loading example.
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, TEXT( "scanner\\scannerarm.x" ) ) );

V_RETURN( g_Mesh.Create( pd3dDevice, str ) );
V_RETURN( g_Mesh.SetFVF( pd3dDevice, D3DVERTEX::FVF ) );

// Create the vertex buffer
if( FAILED( pd3dDevice->CreateVertexBuffer( 3 * MAX_INTERSECTIONS * sizeof( D3DVERTEX ),
D3DUSAGE_WRITEONLY, D3DVERTEX::FVF,
D3DPOOL_MANAGED, &g_pVB, NULL ) ) )
{
return E_FAIL;
}

// Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the
// shader debugger. Debugging vertex shaders requires either REF or software vertex
// processing, and debugging pixel shaders requires REF.  The
// D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the
// shader debugger.  It enables source level debugging, prevents instruction
// reordering, prevents dead code elimination, and forces the compiler to compile
// against the next higher available software target, which ensures that the
// unoptimized shaders do not exceed the shader model limitations.  Setting these
// flags will cause slower rendering since the shaders will be unoptimized and
// forced into software.  See the DirectX documentation for more information about
// using the shader debugger.
DWORD dwShaderFlags = D3DXFX_NOT_CLONEABLE;

#if defined( DEBUG ) || defined( _DEBUG )
// Set the D3DXSHADER_DEBUG flag to embed debug information in the shaders.
// Setting this flag improves the shader debugging experience, but still allows
// the shaders to be optimized and to run exactly the way they will run in
// the release configuration of this program.
dwShaderFlags |= D3DXSHADER_DEBUG;
#endif

#ifdef DEBUG_VS
dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
#endif
#ifdef DEBUG_PS
dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
#endif

// Read the D3DX effect file
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"Pick.fx" ) );

// If this fails, there should be debug output as to
// they the .fx file failed to compile
V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags,
NULL, &g_pEffect, NULL ) );

// Set effect variables as needed
D3DXCOLOR colorMtrl( 1.0f, 1.0f, 1.0f, 1.0f );
D3DXVECTOR3 vLightDir( 0.1f, -1.0f, 0.1f );
D3DXCOLOR vLightDiffuse( 1,1,1,1 );

V_RETURN( g_pEffect->SetValue( "g_MaterialAmbientColor", &colorMtrl, sizeof( D3DXCOLOR ) ) );
V_RETURN( g_pEffect->SetValue( "g_MaterialDiffuseColor", &colorMtrl, sizeof( D3DXCOLOR ) ) );

V_RETURN( g_pEffect->SetValue( "g_LightDir", &vLightDir, sizeof( D3DXVECTOR3 ) ) );
V_RETURN( g_pEffect->SetValue( "g_LightDiffuse", &vLightDiffuse, sizeof( D3DXVECTOR4 ) ) );

V_RETURN( g_pEffect->SetTexture( "g_MeshTexture", g_Mesh.m_pTextures[0] ) );

// Setup the camera's view parameters
D3DXVECTOR3 vecEye( -CAMERA_DISTANCE, 0.0f, 0.0f );
D3DXVECTOR3 vecAt ( 0.0f, 0.0f, 0.0f );
g_Camera.SetViewParams( &vecEye, &vecAt );

// Setup the world matrix of the camera
// Change this to see how Picking works with a translated object
D3DXMATRIX mWorld;
D3DXMatrixTranslation( &mWorld, 0.0f, -1.7f, 0.0f );
g_Camera.SetWorldMatrix( mWorld );

return S_OK;
}


第十一部分:回调函数OnFrameMove()

//--------------------------------------------------------------------------------------
// This callback function will be called once at the beginning of every frame. This is the
// best location for your application to handle updates to the scene, but is not
// intended to contain actual rendering calls, which should instead be placed in the
// OnFrameRender callback.
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
{
// Rotate the camera about the y-axis
D3DXVECTOR3 vFromPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );

vFromPt.x = -cosf( ( float )fTime / 3.0f ) * CAMERA_DISTANCE;
vFromPt.y = 1.0f;
vFromPt.z = sinf( ( float )fTime / 3.0f ) * CAMERA_DISTANCE;

// Update the camera's position based on time
g_Camera.SetViewParams( &vFromPt, &vLookatPt );
}


第十二部分:回调函数OnFrameRender()

//--------------------------------------------------------------------------------------
// This callback function will be called at the end of every frame to perform all the
// rendering calls for the scene, and it will also be called if the window needs to be
// repainted. After this function has returned, DXUT will call
// IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
HRESULT hr;
D3DXMATRIXA16 mWorld;
D3DXMATRIXA16 mView;
D3DXMATRIXA16 mProj;
D3DXMATRIXA16 mWorldViewProjection;

// If the settings dialog is being shown, then
// render it instead of rendering the app's scene
if( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.OnRender( fElapsedTime );
return;
}

// Check for Picked triangles
Pick();

// Clear the render target and the zbuffer
V( pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB( 0, 45, 50, 170 ), 1.0f, 0 ) );

// Render the scene
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
// Get the projection & view matrix from the camera class
mWorld = *g_Camera.GetWorldMatrix();
mProj = *g_Camera.GetProjMatrix();
mView = *g_Camera.GetViewMatrix();

mWorldViewProjection = mWorld * mView * mProj;

V( g_pEffect->SetTechnique( "RenderScene" ) );

// Update the effect's variables.  Instead of using strings, it would
// be more efficient to cache a handle to the parameter by calling
// ID3DXEffect::GetParameterByName
V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
V( g_pEffect->SetMatrix( "g_mWorld", &mWorld ) );
V( g_pEffect->SetFloat( "g_fTime", ( float )fTime ) );

UINT uPasses;
V( g_pEffect->Begin( &uPasses, 0 ) );

// Set render mode to lit, solid triangles
pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );

// If a triangle is Picked, draw it
if( g_dwNumIntersections > 0 )
{
for( UINT uPass = 0; uPass < uPasses; ++uPass )
{
V( g_pEffect->BeginPass( uPass ) );

// Draw the Picked triangle
pd3dDevice->SetFVF( D3DVERTEX::FVF );
pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( D3DVERTEX ) );
pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, g_dwNumIntersections );

V( g_pEffect->EndPass() );
}

// Set render mode to unlit, wireframe triangles
pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
}

V( g_pEffect->End() );

// Render the mesh
V( g_Mesh.Render( g_pEffect ) );

DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L"HUD / Stats" ); // These events are to help PIX identify what the code is doing
RenderText();
V( g_HUD.OnRender( fElapsedTime ) );
V( g_SampleUI.OnRender( fElapsedTime ) );
DXUT_EndPerfEvent();

V( pd3dDevice->EndScene() );
}
}


第十三部分:函数RenderText()

//--------------------------------------------------------------------------------------
// Render the help and statistics text. This function uses the ID3DXFont interface for
// efficient text rendering.
//--------------------------------------------------------------------------------------
void RenderText()
{
// The helper object simply helps keep track of text position, and color
// and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
// If NULL is passed in as the sprite object, then it will work however the
// pFont->DrawText() will not be batched together.  Batching calls will improves performance.
CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );

// Output statistics
txtHelper.Begin();
txtHelper.SetInsertionPos( 5, 5 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
txtHelper.DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) );
txtHelper.DrawTextLine( DXUTGetDeviceStats() );

txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );

if( g_dwNumIntersections < 1 )
{
txtHelper.DrawTextLine( L"Use mouse to Pick a polygon" );
}
else
{
WCHAR wstrHitStat[256];

for( DWORD dwIndex = 0; dwIndex < g_dwNumIntersections; dwIndex++ )
{
swprintf_s( wstrHitStat, 256,
L"Face=%d, tu=%3.02f, tv=%3.02f",
g_IntersectionArray[dwIndex].dwFace,
g_IntersectionArray[dwIndex].tu,
g_IntersectionArray[dwIndex].tv );

txtHelper.DrawTextLine( wstrHitStat );
}
}

txtHelper.End();
}


第十四部分:消息处理函数MsgProc

//--------------------------------------------------------------------------------------
// Before handling window messages, DXUT passes incoming windows
// messages to the application through this callback function. If the application sets
// *pbNoFurtherProcessing to TRUE, then DXUT will not process this message.
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing,
void* pUserContext )
{
// Always allow dialog resource manager calls to handle global messages
// so GUI state is updated correctly
*pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;

if( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
return 0;
}

// Give the dialogs a chance to handle the message first
*pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;
*pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;

// Pass all remaining windows messages to camera so it can respond to user input
//g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );

switch( uMsg )
{
case WM_LBUTTONDOWN:
{
// Capture the mouse, so if the mouse button is
// released outside the window, we'll get the WM_LBUTTONUP message
DXUTGetGlobalTimer()->Stop();
SetCapture( hWnd );
return TRUE;
}

case WM_LBUTTONUP:
{
ReleaseCapture();
DXUTGetGlobalTimer()->Start();
break;
}

case WM_CAPTURECHANGED:
{
if( ( HWND )lParam != hWnd )
{
ReleaseCapture();
DXUTGetGlobalTimer()->Start();
}
break;
}
}

return 0;
}


第十五部分:键盘响应函数

//--------------------------------------------------------------------------------------
// As a convenience, DXUT inspects the incoming windows messages for
// keystroke messages and decodes the message parameters to pass relevant keyboard
// messages to the application.  The framework does not remove the underlying keystroke
// messages, which are still passed to the application's MsgProc callback.
//--------------------------------------------------------------------------------------
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext )
{
if( bKeyDown )
{
switch( nChar )
{
case VK_F1:
g_bShowHelp = !g_bShowHelp; break;
}
}
}


第十六部分:GUI事件处理函数

//--------------------------------------------------------------------------------------
// Handles the GUI events
//--------------------------------------------------------------------------------------
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext )
{
switch( nControlID )
{
case IDC_TOGGLEFULLSCREEN:
DXUTToggleFullScreen(); break;
case IDC_TOGGLEREF:
DXUTToggleREF(); break;
case IDC_CHANGEDEVICE:
g_SettingsDlg.SetActive( !g_SettingsDlg.IsActive() ); break;
case IDC_USED3DX:
g_bUseD3DXIntersect = !g_bUseD3DXIntersect; break;
case IDC_ALLHITS:
g_bAllHits = !g_bAllHits; break;
}
}


第十七部分:回调函数OnLostDevice()

//--------------------------------------------------------------------------------------
// This callback function will be called immediately after the Direct3D device has
// entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
// in the OnResetDevice callback should be released here, which generally includes all
// D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for
// information about lost devices.
//--------------------------------------------------------------------------------------
void CALLBACK OnLostDevice( void* pUserContext )
{
g_DialogResourceManager.OnD3D9LostDevice();
g_SettingsDlg.OnD3D9LostDevice();
if( g_pFont )
g_pFont->OnLostDevice();
if( g_pEffect )
g_pEffect->OnLostDevice();
SAFE_RELEASE( g_pTextSprite );
}


第十八部分:回调函数OnDestroyDevice()

//--------------------------------------------------------------------------------------
// This callback function will be called immediately after the Direct3D device has
// been destroyed, which generally happens as a result of application termination or
// windowed/full screen toggles. Resources created in the OnCreateDevice callback
// should be released here, which generally includes all D3DPOOL_MANAGED resources.
//--------------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void* pUserContext )
{
g_DialogResourceManager.OnD3D9DestroyDevice();
g_SettingsDlg.OnD3D9DestroyDevice();
g_Mesh.Destroy();
SAFE_RELEASE( g_pVB );
SAFE_RELEASE( g_pEffect );
SAFE_RELEASE( g_pFont );
}


第十九部分:主功能函数pick()

//--------------------------------------------------------------------------------------
// Checks if mouse point hits geometry the scene.
//--------------------------------------------------------------------------------------
HRESULT Pick()
{
HRESULT hr;
D3DXVECTOR3 vPickRayDir;
D3DXVECTOR3 vPickRayOrig;
IDirect3DDevice9* pD3Device = DXUTGetD3D9Device();
const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetD3D9BackBufferSurfaceDesc();

g_dwNumIntersections = 0L;

// Get the Pick ray from the mouse position
if( GetCapture() )
{
const D3DXMATRIX* pmatProj = g_Camera.GetProjMatrix();

POINT ptCursor;
GetCursorPos( &ptCursor );
ScreenToClient( DXUTGetHWND(), &ptCursor );

// Compute the vector of the Pick ray in screen space
D3DXVECTOR3 v;
v.x = ( ( ( 2.0f * ptCursor.x ) / pd3dsdBackBuffer->Width ) - 1 ) / pmatProj->_11;
v.y = -( ( ( 2.0f * ptCursor.y ) / pd3dsdBackBuffer->Height ) - 1 ) / pmatProj->_22;
v.z = 1.0f;

// Get the inverse view matrix
const D3DXMATRIX matView = *g_Camera.GetViewMatrix();
const D3DXMATRIX matWorld = *g_Camera.GetWorldMatrix();
D3DXMATRIX mWorldView = matWorld * matView;
D3DXMATRIX m;
D3DXMatrixInverse( &m, NULL, &mWorldView );

// Transform the screen space Pick ray into 3D space
vPickRayDir.x = v.x * m._11 + v.y * m._21 + v.z * m._31;
vPickRayDir.y = v.x * m._12 + v.y * m._22 + v.z * m._32;
vPickRayDir.z = v.x * m._13 + v.y * m._23 + v.z * m._33;
vPickRayOrig.x = m._41;
vPickRayOrig.y = m._42;
vPickRayOrig.z = m._43;
}

// Get the Picked triangle
if( GetCapture() )
{
LPD3DXMESH pMesh;

g_Mesh.GetMesh()->CloneMeshFVF( D3DXMESH_MANAGED,
g_Mesh.GetMesh()->GetFVF(), pD3Device, &pMesh );

LPDIRECT3DVERTEXBUFFER9 pVB;
LPDIRECT3DINDEXBUFFER9 pIB;

pMesh->GetVertexBuffer( &pVB );
pMesh->GetIndexBuffer( &pIB );

WORD* pIndices;
D3DVERTEX* pVertices;

pIB->Lock( 0, 0, ( void** )&pIndices, 0 );
pVB->Lock( 0, 0, ( void** )&pVertices, 0 );

if( g_bUseD3DXIntersect )
{
// When calling D3DXIntersect, one can get just the closest intersection and not
// need to work with a D3DXBUFFER.  Or, to get all intersections between the ray and
// the mesh, one can use a D3DXBUFFER to receive all intersections.  We show both
// methods.
if( !g_bAllHits )
{
// Collect only the closest intersection
BOOL bHit;
DWORD dwFace;
FLOAT fBary1, fBary2, fDist;
D3DXIntersect( pMesh, &vPickRayOrig, &vPickRayDir, &bHit, &dwFace, &fBary1, &fBary2, &fDist,
NULL, NULL );
if( bHit )
{
g_dwNumIntersections = 1;
g_IntersectionArray[0].dwFace = dwFace;
g_IntersectionArray[0].fBary1 = fBary1;
g_IntersectionArray[0].fBary2 = fBary2;
g_IntersectionArray[0].fDist = fDist;
}
else
{
g_dwNumIntersections = 0;
}
}
else
{
// Collect all intersections
BOOL bHit;
LPD3DXBUFFER pBuffer = NULL;
D3DXINTERSECTINFO* pIntersectInfoArray;
if( FAILED( hr = D3DXIntersect( pMesh, &vPickRayOrig, &vPickRayDir, &bHit, NULL, NULL, NULL, NULL,
&pBuffer, &g_dwNumIntersections ) ) )
{
SAFE_RELEASE( pMesh );
SAFE_RELEASE( pVB );
SAFE_RELEASE( pIB );

return hr;
}
if( g_dwNumIntersections > 0 )
{
pIntersectInfoArray = ( D3DXINTERSECTINFO* )pBuffer->GetBufferPointer();
if( g_dwNumIntersections > MAX_INTERSECTIONS )
g_dwNumIntersections = MAX_INTERSECTIONS;
for( DWORD iIntersection = 0; iIntersection < g_dwNumIntersections; iIntersection++ )
{
g_IntersectionArray[iIntersection].dwFace = pIntersectInfoArray[iIntersection].FaceIndex;
g_IntersectionArray[iIntersection].fBary1 = pIntersectInfoArray[iIntersection].U;
g_IntersectionArray[iIntersection].fBary2 = pIntersectInfoArray[iIntersection].V;
g_IntersectionArray[iIntersection].fDist = pIntersectInfoArray[iIntersection].Dist;
}
}
SAFE_RELEASE( pBuffer );
}

}
else
{
// Not using D3DX
DWORD dwNumFaces = g_Mesh.GetMesh()->GetNumFaces();
FLOAT fBary1, fBary2;
FLOAT fDist;
for( DWORD i = 0; i < dwNumFaces; i++ )
{
D3DXVECTOR3 v0 = pVertices[pIndices[3 * i + 0]].p;
D3DXVECTOR3 v1 = pVertices[pIndices[3 * i + 1]].p;
D3DXVECTOR3 v2 = pVertices[pIndices[3 * i + 2]].p;

// Check if the Pick ray passes through this point
if( IntersectTriangle( vPickRayOrig, vPickRayDir, v0, v1, v2,
&fDist, &fBary1, &fBary2 ) )
{
if( g_bAllHits || g_dwNumIntersections == 0 || fDist < g_IntersectionArray[0].fDist )
{
if( !g_bAllHits )
g_dwNumIntersections = 0;
g_IntersectionArray[g_dwNumIntersections].dwFace = i;
g_IntersectionArray[g_dwNumIntersections].fBary1 = fBary1;
g_IntersectionArray[g_dwNumIntersections].fBary2 = fBary2;
g_IntersectionArray[g_dwNumIntersections].fDist = fDist;
g_dwNumIntersections++;
if( g_dwNumIntersections == MAX_INTERSECTIONS )
break;
}
}
}
}

// Now, for each intersection, add a triangle to g_pVB and compute texture coordinates
if( g_dwNumIntersections > 0 )
{
D3DVERTEX* v;
D3DVERTEX* vThisTri;
WORD* iThisTri;
D3DVERTEX v1, v2, v3;
INTERSECTION* pIntersection;

g_pVB->Lock( 0, 0, ( void** )&v, 0 );

for( DWORD iIntersection = 0; iIntersection < g_dwNumIntersections; iIntersection++ )
{
pIntersection = &g_IntersectionArray[iIntersection];

vThisTri = &v[iIntersection * 3];
iThisTri = &pIndices[3 * pIntersection->dwFace];
// get vertices hit
vThisTri[0] = pVertices[iThisTri[0]];
vThisTri[1] = pVertices[iThisTri[1]];
vThisTri[2] = pVertices[iThisTri[2]];

// If all you want is the vertices hit, then you are done.  In this sample, we
// want to show how to infer texture coordinates as well, using the BaryCentric
// coordinates supplied by D3DXIntersect
FLOAT dtu1 = vThisTri[1].tu - vThisTri[0].tu;
FLOAT dtu2 = vThisTri[2].tu - vThisTri[0].tu;
FLOAT dtv1 = vThisTri[1].tv - vThisTri[0].tv;
FLOAT dtv2 = vThisTri[2].tv - vThisTri[0].tv;
pIntersection->tu = vThisTri[0].tu + pIntersection->fBary1 * dtu1 + pIntersection->fBary2 * dtu2;
pIntersection->tv = vThisTri[0].tv + pIntersection->fBary1 * dtv1 + pIntersection->fBary2 * dtv2;
}

g_pVB->Unlock();
}

pVB->Unlock();
pIB->Unlock();

SAFE_RELEASE( pMesh );
SAFE_RELEASE( pVB );
SAFE_RELEASE( pIB );
}

return S_OK;
}


第二十部分:主功能函数IntersectTriangle()

//--------------------------------------------------------------------------------------
// Given a ray origin (orig) and direction (dir), and three vertices of a triangle, this
// function returns TRUE and the interpolated texture coordinates if the ray intersects
// the triangle
//--------------------------------------------------------------------------------------
bool IntersectTriangle( const D3DXVECTOR3& orig, const D3DXVECTOR3& dir,
D3DXVECTOR3& v0, D3DXVECTOR3& v1, D3DXVECTOR3& v2,
FLOAT* t, FLOAT* u, FLOAT* v )
{
// Find vectors for two edges sharing vert0
D3DXVECTOR3 edge1 = v1 - v0;
D3DXVECTOR3 edge2 = v2 - v0;

// Begin calculating determinant - also used to calculate U parameter
D3DXVECTOR3 pvec;
D3DXVec3Cross( &pvec, &dir, &edge2 );

// If determinant is near zero, ray lies in plane of triangle
FLOAT det = D3DXVec3Dot( &edge1, &pvec );

D3DXVECTOR3 tvec;
if( det > 0 )
{
tvec = orig - v0;
}
else
{
tvec = v0 - orig;
det = -det;
}

if( det < 0.0001f )
return FALSE;

// Calculate U parameter and test bounds
*u = D3DXVec3Dot( &tvec, &pvec );
if( *u < 0.0f || *u > det )
return FALSE;

// Prepare to test V parameter
D3DXVECTOR3 qvec;
D3DXVec3Cross( &qvec, &tvec, &edge1 );

// Calculate V parameter and test bounds
*v = D3DXVec3Dot( &dir, &qvec );
if( *v < 0.0f || *u + *v > det )
return FALSE;

// Calculate t, scale parameters, ray intersects triangle
*t = D3DXVec3Dot( &edge2, &qvec );
FLOAT fInvDet = 1.0f / det;
*t *= fInvDet;
*u *= fInvDet;
*v *= fInvDet;

return TRUE;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: