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;
    }
  • 相关阅读:
    【Nginx】ngx_event_core_module模块
    ELMAH--Using HTTP Modules and Handlers to Create Pluggable ASP.NET Components 77 out of 90 rated th
    nyist oj 214 单调递增子序列(二) (动态规划经典)
    java 入门书籍(java7)
    ARCGIS将WGS84坐标投影到高斯平面
    【linux】linux下对java程序生成dump文件,并使用IBM Heap Analyzer进行分析,查找定位内存泄漏的问题代码
    【springboot】【socket】spring boot整合socket,实现服务器端两种消息推送
    【linux】linux修改open file 大小
    【docker】docker限制日志文件大小的方法+查看日志文件的方法
    【docker】docker部署spring boot服务,但是docker logs查看容器输出控制台日志,没有日志打印,日志未打印,docker logs不打印容器日志
  • 原文地址:https://www.cnblogs.com/moniza/p/3570853.html
Copyright © 2011-2022 走看看