zoukankan      html  css  js  c++  java
  • DXUT 主程序源文件结构分析

    分析文件来自于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 );

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

    部分主要模块执行顺序:

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

    程序退出

    InitApp 1      
    OnCreateDevice 2      
    OnResetDevice 3 2 2  
    OnFrameMove 4      
    OnFrameRender  5      
    MsgProc        
    KeyboardProc        
    OnGUIEvent        
    OnLostDevice 6 1 1 1
    OnDestroyDevice 7     2

    第六部分:程序入口函数

    //--------------------------------------------------------------------------------------
    // 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;
    }
  • 相关阅读:
    html5的键盘事件
    阻止滑屏
    JS 复制到黏贴板上
    最新拖动原理
    方法——<37>
    验证——正则<37>
    《高级程序设计》 9 客户端检测
    《高级程序设计》8 BOM
    《高级程序设计》7 函数表达式
    《高级程序设计》6 面向对象的程序设计
  • 原文地址:https://www.cnblogs.com/moniza/p/3570853.html
Copyright © 2011-2022 走看看