Tutorial08 Dx10

Tutorial 08 - DXSDK - Introdução ao DXUT

Este tutorial aborda uma introdução ao DXUT. Nele são vistos quais as principais funções de callback que devem ser configuradas para que uma aplicação use das facilidades fornecidas por esta biblioteca utilitária. Ps: A funcionalidade é a mesma do tutorial 07.

// Introdução básica ao DXUT
 
#include <windows.h>
#include "DXUT\Core\DXUT.h"
#include "DXUT\Core\DXUTmisc.h"
 
#define DEG2RAD( a ) ( a * D3DX_PI / 180.0f )
 
struct SimpleVertex{
    D3DXVECTOR3 Pos;
    D3DXVECTOR2 Tex;
};
 
ID3D10Effect*    g_pEffect = NULL;
ID3D10InputLayout*    g_pVertexLayout = NULL;
ID3D10EffectTechnique*    g_pTechnique = NULL;
ID3D10Buffer*    g_pVertexBuffer = NULL;
ID3D10Buffer*    g_pIndexBuffer = NULL;
ID3D10ShaderResourceView*    g_pTextureRV = NULL;
ID3D10EffectMatrixVariable* g_pWorldVariable = NULL;
ID3D10EffectMatrixVariable* g_pViewVariable = NULL;
ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL;
ID3D10EffectVectorVariable* g_pMeshColorVariable = NULL;
ID3D10EffectShaderResourceVariable* g_pDiffuseVariable = NULL;
D3DXMATRIX    g_World;
D3DXMATRIX    g_View;
D3DXMATRIX    g_Projection;
D3DXVECTOR4    g_vMeshColor( 0.7f, 0.7f, 0.7f, 1.0f );
 
// Protótipos das funções
bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType,
                                      DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext );
HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, 
                                     void* pUserContext);
HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain,
                    const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext);
void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
void CALLBACK OnD3D10ReleasingSwapChain( void* pUserContext );
void CALLBACK OnD3D10DestroyDevice( void* pUserContext );
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing,
                         void* pUserContext);
void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext );
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUserContext );
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void *pUserContext );
 
// Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de
// mensagem. Tempo ocioso é usado para renderizar a cena
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){
#if defined( DEBUG ) | defined( _DEBUG )
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
 
    // DXUT criará e usará o melhor equipamento disponível (ou D3D9 ou D3D10)
    // isto é dependente do sistema disponível no qual os CALLBACKS do D3D são configurados abaixo
 
    // Configure callbacks DXUT
    DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable );
    DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice );
    DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizeSwapChain );
    DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain );
    DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice );
    DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender );
 
    DXUTSetCallbackMsgProc( MsgProc );
    DXUTSetCallbackKeyboard( OnKeyboard );
    DXUTSetCallbackFrameMove( OnFrameMove );
    DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
 
    DXUTInit( true, true, NULL );    // Parse da linha de comando, mostra caixas de mensagem no erro, sem parâmetros de linha de comando extra
    DXUTSetCursorSettings(true, true );    // Mostre o cursor e recorte ele (clip) quando em modo de tela cheia
    DXUTCreateWindow( L"Tutorial08" );
    DXUTCreateDevice( true, 640, 480 );
    DXUTMainLoop();    // Entra dentro do loop de renderização DXUT
 
    return DXUTGetExitCode();
}
 
// Rejeita qualquer equipamento D3D10 que não é aceitável por retornar falso
bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType,
                                      DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ){
      return true;
}
 
// Crie quaisquer recursos que não são dependentes do buffer de trás
HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc,
                                     void *pUserContext ){
    HRESULT hr = S_OK;
 
    // Lê o arquivo de efeito D3DX
    DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
#if defined(DEBUG) || defined(_DEBUG)
    // Coloque a opção D3D10_SHADER_DEBUG para embutir informação de debug nos shaders.
    // Colocar estaopção melhora a experiência de debugação dos shaders, mas ainda permite
    // os shaders serem otimizados e executarem apropriadamente da maneira que eles
    // executarão na configuração release deste programa
    dwShaderFlags |= D3D10_SHADER_DEBUG;
#endif
 
    hr = D3DX10CreateEffectFromFile( L"..\\Tutorial08.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL,
        NULL, &g_pEffect, NULL, NULL );
 
    if( FAILED( hr ) ){
        MessageBox( NULL, L"O arquivo fx não pôde ser localizado. Por favor execute este executável do diretório que contém o arquivo FX", 
            L"Erro", MB_OK );
 
        V_RETURN( hr );
    }
 
    // Obtem as técnicas
    g_pTechnique = g_pEffect->GetTechniqueByName( "Render" );
 
    // Obtém as variáveis
    g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix();
    g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix();
    g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix();
    g_pMeshColorVariable = g_pEffect->GetVariableByName( "vMeshColor" )->AsVector();
    g_pDiffuseVariable = g_pEffect->GetVariableByName( "txDiffuse" )->AsShaderResource();
 
    // Defina o leiaute de entrada
    D3D10_INPUT_ELEMENT_DESC layout[] = {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA,0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA,0 },
    };
    UINT numElements = sizeof( layout ) / sizeof( layout[0] );
 
    // Cria o leiaute de entrada
    D3D10_PASS_DESC PassDesc;
    g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    hr = pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature,
        PassDesc.IAInputSignatureSize, &g_pVertexLayout );
 
    if( FAILED( hr ) )
        return hr;
 
    // Configure o leiaute de entrada
    pd3dDevice->IASetInputLayout( g_pVertexLayout );
 
    // Crie o buffer de vértice
    SimpleVertex vertices[] =
    {
        { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) },
        { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) },
        { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) },
 
        { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) },
        { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) },
        { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) },
 
        { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) },
        { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) },
        { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) },
 
        { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) },
        { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) },
        { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) },
        { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) },
 
        { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) },
        { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) },
        { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) },
 
        { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) },
        { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) },
        { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) },
    };
 
    D3D10_BUFFER_DESC bd;
    bd.Usage = D3D10_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( SimpleVertex ) * 24;
    bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = 0;
    bd.MiscFlags = 0;
    D3D10_SUBRESOURCE_DATA InitData;
    InitData.pSysMem = vertices;
    hr = pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
 
    if( FAILED( hr ) )
        return hr;
 
    // Configure o buffer de vértice
    UINT stride = sizeof( SimpleVertex );
    UINT offset = 0;
    pd3dDevice->IASetVertexBuffers( 0,1, &g_pVertexBuffer, &stride, &offset );
 
    // Cria o buffer de índice
    // Cria o buffer de vértice
    DWORD indices[] =
    {
        3,1,0,
        2,1,3,
 
        6,4,5,
        7,4,6,
 
        11,9,8,
        10,9,11,
 
        14,12,13,
        15,12,14,
 
        19,17,16,
        18,17,19,
 
        22,20,21,
        23,20,22
    };
 
    bd.Usage = D3D10_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( DWORD ) * 36;    
    bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
    bd.CPUAccessFlags = bd.MiscFlags = 0;
    InitData.pSysMem = indices;
    V_RETURN( pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer ) );
 
    // Configura o buffer de índice
    pd3dDevice->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );
 
    // Configura a topologia primitiva
    pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
 
    // Carrega a textura
    hr = D3DX10CreateShaderResourceViewFromFile( pd3dDevice, L"..\\seafloor.dds", NULL, NULL,
        &g_pTextureRV, NULL );
 
    // Inicializa a matriz do mundo
    D3DXMatrixIdentity( &g_World );
 
    // Inicializa a matriz visão
    D3DXVECTOR3 Eye( 0.0f, 3.0f, -6.0f );
    D3DXVECTOR3 At( 0.0f, 1.0f, 0.0f );
    D3DXVECTOR3 Up( 0.0f, 1.0f, 0.0f );
    D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up );
 
    // Atualize variáveis que nunca mudarão
    g_pViewVariable->SetMatrix( (float*) &g_View );
    g_pDiffuseVariable->SetResource( g_pTextureRV );
 
    return S_OK;
}
 
// Crie quaisquer recursos D3D10 que dependam do buffer de trás
// Crie e configure a textura stencial de profundidade se necessário
HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain *pSwapChain,
                                        const DXGI_SURFACE_DESC *pBufferSurfaceDesc, void *pUserContext){
    // Configura os parâmetros de projeção de novo
    float fAspect = static_cast<float>( pBufferSurfaceDesc->Width) / static_cast<float>( pBufferSurfaceDesc->Height );
    D3DXMatrixPerspectiveFovLH( &g_Projection, (float) D3DX_PI * 0.25f, fAspect, 0.1f, 100.0f );
    g_pProjectionVariable->SetMatrix( (float*) &g_Projection );
 
    return S_OK;
}
 
// Renderiza a cena usando o dispositivo D3D10
void CALLBACK OnD3D10FrameRender( ID3D10Device *pd3dDevice, double fTime, float fElapsedTime, void *pUserContext )
{
    // Limpa o buffer de trás
    float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f };    // vermelho, verde, azul, alfa
    ID3D10RenderTargetView *pRTV = DXUTGetD3D10RenderTargetView();
    pd3dDevice->ClearRenderTargetView(pRTV, ClearColor );
 
    // limpa o stencil de profundidade
    ID3D10DepthStencilView *pDSV = DXUTGetD3D10DepthStencilView();
    pd3dDevice->ClearDepthStencilView( pDSV, D3D10_CLEAR_DEPTH, 1.0, 0 );
 
    // Atualiza as variáveis que mudam uma vez por quadro
    g_pWorldVariable->SetMatrix( (float* )&g_World );
    g_pMeshColorVariable->SetFloatVector( (float*) g_vMeshColor);
 
    // Renderiza o cubo
    D3D10_TECHNIQUE_DESC techDesc;    
    g_pTechnique->GetDesc( &techDesc );
    for( UINT p = 0; p < techDesc.Passes; ++p ){
        g_pTechnique->GetPassByIndex( p )->Apply( 0 );
        pd3dDevice->DrawIndexed( 36, 0, 0 );    // 36 vértices necessários para 12 triângulos em uma lista de triângulos
    }
}
 
// Libera recursos D3D10 criados em OnD3D10ResizedSwapChain 
void CALLBACK OnD3D10ReleasingSwapChain( void *pUserContext ){
}
 
// Libera recursos D3D10 criados em OnD3D10CreateDevice 
void CALLBACK OnD3D10DestroyDevice( void *pUserContext ){
    SAFE_RELEASE( g_pVertexBuffer );
    SAFE_RELEASE( g_pIndexBuffer );
    SAFE_RELEASE( g_pVertexLayout );
    SAFE_RELEASE( g_pTextureRV );
    SAFE_RELEASE( g_pEffect );
}
 
// Chamado imediatamente antes de criar um dispositivo D3D9 oy D3D10, permitindo o aplicativo modificar
// as configurações do dispositivo como necessário
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings *pDeviceSettings, void *pUserContext ){
    return true;
}
 
// Trata das atualizações na cena. Isto é chamado indiferentemente de qual API D3D é usada
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUsetContex ){
    // Rotaciona p cubo ao redor da origem
    D3DXMatrixRotationY( &g_World, 60.0f * DEG2RAD( (float) fTime ) );
 
    // Modifique a cor
    g_vMeshColor.x = ( sinf( (float) fTime *1.0f ) + 1.0f) * 0.5f;
    g_vMeshColor.y = ( cosf( (float) fTime *3.0f ) + 1.0f) * 0.5f;
    g_vMeshColor.z = ( sinf( (float) fTime *5.0f ) + 1.0f) * 0.5f;
}
 
// Manuseia as mensagens para a aplicação
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 
                         bool *pbNoFurtherProcessing, void *pUserContext )
{
    return 0;
}
 
// Manuseia pressionamentos do teclado
void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext  ){
    if( bKeyDown ){
        switch( nChar ){
            case VK_F1:    // Change as needed
                break;
        }
    }
}

O shader relacionado (Tutorial08.fx) é igual ao apresentado no Tutorial 07.

//--------------------------------------------------------------------------------------
// File: Tutorial08.fx
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
 
//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
Texture2D txDiffuse;
SamplerState samLinear
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};
 
cbuffer cbNeverChanges
{
    matrix View;
};
 
cbuffer cbChangeOnResize
{
    matrix Projection;
};
 
cbuffer cbChangesEveryFrame
{
    matrix World;
    float4 vMeshColor;
};
 
struct VS_INPUT
{
    float4 Pos : POSITION;
    float2 Tex : TEXCOORD;
};
 
struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float2 Tex : TEXCOORD0;
};
 
//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = mul( input.Pos, World );
    output.Pos = mul( output.Pos, View );
    output.Pos = mul( output.Pos, Projection );
    output.Tex = input.Tex;
 
    return output;
}
 
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( PS_INPUT input) : SV_Target
{
    return txDiffuse.Sample( samLinear, input.Tex ) * vMeshColor;
}
 
//--------------------------------------------------------------------------------------
technique10 Render
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, PS() ) );
    }
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-Share Alike 2.5 License.