GameProgrammer.org
tutorials for dummies bug source let me google it for you my blog all about me
Loading DirectX Meshes
In this tutorial I will demonstrate how to do DirectX Mesh loading from Microsofts .x format in Direct3d this will include displaying and rotating the mesh. First I'll show you the code from the second tutorial written by me with the required changes to allow for the creation, rendering and rotating of a mesh file called tiger.x with textures stored in the same directory.

#include <windows.h>
#include <d3d8.h>
#include <d3dx8.h>

HWND hWnd;
LPDIRECT3D8 pD3D;
LPDIRECT3DDEVICE8 pDevice;

LPD3DXMESH pMesh = NULL; // Our mesh object in sysmem
D3DMATERIAL8* pMeshMaterials = NULL; // Materials for our mesh
LPDIRECT3DTEXTURE8* pMeshTextures = NULL; // Textures for our mesh
DWORD dwNumMaterials = 0L; // Number of mesh materials

HRESULT LoadD3DMesh();                             //Reference to the function to load an D3D Mesh

LRESULT CALLBACK WndProc( HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam){
    switch(message){
    case WM_CLOSE:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hWnd,message,wParam,lParam);
}

bool CreateSimpWindow(int width, int height){

    // Create A Window Class Structure
    WNDCLASSEX wc;
    wc.cbClsExtra = 0;
    wc.cbSize = sizeof(wc);
    wc.cbWndExtra = 0;
    wc.hbrBackground = NULL;
    wc.hCursor = NULL;
    wc.hIcon = NULL;
    wc.hIconSm = NULL;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpfnWndProc = WndProc;
    wc.lpszClassName = "VK3D";
    wc.lpszMenuName = NULL;
    wc.style = CS_VREDRAW|CS_HREDRAW|CS_OWNDC;

    // Register Window Class
    RegisterClassEx(&wc);

    // Create Window
    hWnd = CreateWindowEx(0,
        "VK3D", "VK3D Direct3D Tutorial 3",
        WS_OVERLAPPEDWINDOW|WS_VISIBLE, 100,100,width,height,
        NULL,NULL,wc.hInstance,0);

    return true;
}

bool InitD3D(){
    if((pD3D = Direct3DCreate8(D3D_SDK_VERSION))==NULL){
        return false;
    }
    D3DDISPLAYMODE d3ddm;
    pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);

    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = d3ddm.Format;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
    if(FAILED(pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp,
        &pDevice))){
            return false;
        }

        pDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
        pDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );


        LoadD3DMesh();

        return true;
}

HRESULT LoadD3DMesh()
{
    LPD3DXBUFFER pD3DXMtrlBuffer;

    // Load the mesh from the specified file
    if( FAILED( D3DXLoadMeshFromX( "Tiger.x", D3DXMESH_SYSTEMMEM,
        pDevice, NULL,
        &pD3DXMtrlBuffer, &dwNumMaterials,
        &pMesh ) ) )
    {
        return E_FAIL;
    }

    // We need to extract the material properties and texture names from the
    // pD3DXMtrlBuffer
    D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
    pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
    pMeshTextures = new LPDIRECT3DTEXTURE8[dwNumMaterials];

    for( DWORD i=0; i<dwNumMaterials; i++ )
    {
        // Copy the material
        pMeshMaterials[i] = d3dxMaterials[i].MatD3D;

        // Set the ambient color for the material (D3DX does not do this)
        pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;

        // Create the texture
        if( FAILED( D3DXCreateTextureFromFile( pDevice,
            d3dxMaterials[i].pTextureFilename,
            &pMeshTextures[i] ) ) )
        {
            pMeshTextures[i] = NULL;
        }
    }

    // Done with the material buffer
    pD3DXMtrlBuffer->Release();

    return S_OK;
}

void RenderD3DScene(){
    pDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
        D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
    pDevice->BeginScene();

    D3DXMATRIX matView;
    D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 3.0f,-10.0f ),
        &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
        &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
    pDevice->SetTransform( D3DTS_VIEW, &matView );

    D3DXMATRIX matProj;
    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
    pDevice->SetTransform( D3DTS_PROJECTION, &matProj );

    D3DXMATRIX matWorld;
    D3DXMatrixRotationY( &matWorld, timeGetTime()/1000.0f );
    pDevice->SetTransform( D3DTS_WORLD, &matWorld );

    for( DWORD i=0; i<dwNumMaterials; i++ )
    {
        // Set the material and texture for this subset
        pDevice->SetMaterial( &pMeshMaterials[i] );
        pDevice->SetTexture( 0, pMeshTextures[i] );

        // Draw the mesh subset
        pMesh->DrawSubset( i );
    }

    pDevice->EndScene();

    pDevice->Present(NULL,NULL,NULL,NULL);


}

void MessageLoop(){
    MSG msg;
    while(true){
        RenderD3DScene();
        if(PeekMessage(&msg,hWnd,0,0,PM_REMOVE)){
            if(msg.message==WM_QUIT)return;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
}

INT WINAPI WinMain( HINSTANCE , HINSTANCE , LPSTR , INT ){

    if(!CreateSimpWindow(400, 400))return 1;

    if(!InitD3D())return 2;

    MessageLoop();

    return 0;
}

The first difference you should note is the additional global variables

LPD3DXMESH pMesh = NULL; // Our mesh object in sysmem
D3DMATERIAL8* pMeshMaterials = NULL; // Materials for our mesh
LPDIRECT3DTEXTURE8* pMeshTextures = NULL; // Textures for our mesh
DWORD dwNumMaterials = 0L; // Number of mesh materials

HRESULT LoadD3DMesh();                             //Reference to the function to load an D3D Mesh

Which are used to store the mesh and it's materials. We also declared the function LoadD3DMesh() which we will use to load the mesh from the disk. The changes to InitD3D are in the present parameters and the RenderState.

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

The changes to the present parameters are to enable the stencil buffer with is required with Zbuffering to decide what to clear otherwise it will never clear the screen.

pDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
pDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );

The render state changes are the enable the Zbuffer which is required for any true 3d processing and to set the ambient light so we can see everything.

LoadD3DMesh();

We then run the LoadD3DMesh instead of creating the Vertex Buffer. The LoadD3Dmesh function is the next difference. It will be explained in sequence.

LPD3DXBUFFER pD3DXMtrlBuffer;

We declare a Buffer to hold the Materials temporarily

// Load the mesh from the specified file
if( FAILED( D3DXLoadMeshFromX( "Tiger.x", D3DXMESH_SYSTEMMEM,
pDevice, NULL,
&pD3DXMtrlBuffer, &dwNumMaterials,
&pMesh ) ) ){
    return E_FAIL;
}

We load the mesh from "Tiger.x", into System Memory, storing the Materials in the Temporary buffer, the number of materials in the appropriate variable and the mesh in stored in pMesh.

// We need to extract the material properties and texture names from the
// pD3DXMtrlBuffer
D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
pMeshTextures = new LPDIRECT3DTEXTURE8[dwNumMaterials];

We prepare for extraction of the textures and materials by first creating the arrays to store them.

for( DWORD i=0; i<dwNumMaterials; i++ )
{
    // Copy the material
    pMeshMaterials[i] = d3dxMaterials[i].MatD3D;

    // Set the ambient color for the material (D3DX does not do this)
    pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;

    // Create the texture
    if( FAILED( D3DXCreateTextureFromFile( pDevice,      d3dxMaterials[i].pTextureFilename, &pMeshTextures[i] ) ) )
    {
        pMeshTextures[i] = NULL;
    }
}

We create the materials by loading the textures from files, copying the loaded values and creating the ambient color value, which DirectX doesn't store.

// Done with the material buffer
pD3DXMtrlBuffer->Release();

We then delete the temporary buffer and exit the function.

pDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

One of the first differences you'll note in the Render function is that the clear function now clears both the Target and the Zbuffer this is required when using z-buffering with stencil buffers.

for( DWORD i=0; i<dwNumMaterials; i++ )
{
    // Set the material and texture for this subset
    pDevice->SetMaterial( &pMeshMaterials[i] );
    pDevice->SetTexture( 0, pMeshTextures[i] );

    // Draw the mesh subset
    pMesh->DrawSubset( i );
}

The only other difference is that for the mesh we have to load it by subsets where each subset has the same material and texture. We first setup the current Material and Texture to be the correct one and then use DrawSubset to render that subset. Included in the .zip file are the example Tiger.x and Tiger.bmp that are required to render the mesh. If you have any comment or need any information email me by clicking my name below or contact me at the yahoo group real-game-programming.

Download Source File

Posted on : 31 May 2004
Darren Foster

Copyright © 2003-2010 Vahid Kazemi, GameProgrammer.org

iPhone Games