XFactorDev.net Article   XFactorDev.net Article

Prt-10- Load and display 3D Objects.

by Ben_3D@xfactordev.net

 

 

Using the build in DirectX3D "D3DXLoadMeshFromX(..,)" function we can load in a 3D model from a .x file, and render it as our 3D world or as a simble object in our world.  I'm not going to add the code for Collision detect with it, as its a very simple matter of min/max coordinates to generate a cube area....

 

The definition for this function is:

 

HRESULT D3DXLoadMeshFromX(

  char * pFilename,             // filename e.g. "car.x"

  DWORD Options,                // 0 for default

  IDirect3DDevice * pDevice,    // pointer to our screen object

  ID3DXBuffer** ppAdjacency,    // reference to vertices positions

  ID3DXBuffer** ppMaterials,    // materials array

  DWORD *pNumMaterials,         // number of materials in the array

  ID3DXMesh** ppMesh            // our 3d mesh

);

 

 

Here is the code for xloader.h/.cpp...

 

 

/***************************************************************************/

/*                                                                         */

/*  xloader.h                                                              */

/*                                                                         */

/*                                                                         */

/*  Details: CXLoader Class                                                */

/*                                                                         */

/*  Auth:    x-factor development (http://www.xfactordev.net)              */

/*           contact@xfactordev.net                                        */

/*                                                                         */

/***************************************************************************/

/*

Well after much thinking, instead of just having one class do all the

rendering of our world and our characters..it just seemed to put to much

burden on one class.  So the XLoader will simply load our 3D world, or any

other non-animated .x files, and render them to our world.

 

It will hold simple collsion detection and movement.  It will not do any

animation...just simple rendering.

 

How to use? ->

 

<1> One at startup

CXLoader  x;

x.Create(pD3DDevice, "mycar.x", "D://media");

 

<2> Inside our render loop

x.Render();

 

<3> When we've finished and want to tidy up

x.Release()

 

 

*/

/***************************************************************************/

 

#include <xtl.h>

#include <string.h>

 

 

class CXLoader

{

protected:

 

      LPD3DXMESH              m_pMesh           ; // Our mesh object in sysmem

      D3DMATERIAL8*           m_pMeshMaterials  ; // Materials for our mesh

      LPDIRECT3DTEXTURE8*     m_pMeshTextures   ; // Textures for our mesh

      DWORD                   m_dwNumMaterials  ; // Number of mesh materials

 

      IDirect3DDevice8*       m_pD3DDevice        ; // Screen Object

 

public:

      CXLoader()

      {

            m_pMesh          = NULL; // Our mesh object in sysmem

            m_pMeshMaterials = NULL; // Materials for our mesh

            m_pMeshTextures  = NULL; // Textures for our mesh

            m_dwNumMaterials = 0L;   // Number of mesh materials

 

            m_pD3DDevice      = NULL;

      }

 

 

public:

      void Create(IDirect3DDevice8** pD3DDevice, char *szFilename, char *TexturePath = ".\\")

      {

            m_pD3DDevice = *pD3DDevice;

 

            LPD3DXBUFFER pD3DXMtrlBuffer;

 

            // Load the mesh from the specified file

            D3DXLoadMeshFromX( szFilename, D3DXMESH_SYSTEMMEM,

                                                         m_pD3DDevice, NULL,

                                                         &pD3DXMtrlBuffer, &m_dwNumMaterials,

                                                         &m_pMesh );

 

            // We need to extract the material properties and texture names from the

            // pD3DXMtrlBuffer

            D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();

            m_pMeshMaterials = new D3DMATERIAL8[m_dwNumMaterials];

            m_pMeshTextures  = new LPDIRECT3DTEXTURE8[m_dwNumMaterials];

 

           

            for( DWORD i=0; i<m_dwNumMaterials; i++ )

            {

                  // Copy the material

                  m_pMeshMaterials[i] = d3dxMaterials[i].MatD3D;

 

                  // Set the ambient color for the material (D3DX does not do this)

                  m_pMeshMaterials[i].Ambient = m_pMeshMaterials[i].Diffuse;

    

                  m_pMeshTextures[i] = NULL;

 

                  if(d3dxMaterials[i].pTextureFilename != NULL)

                  {

                        char szTextureFile[256];

                        strcpy(szTextureFile, TexturePath);

                        strcat(szTextureFile, d3dxMaterials[i].pTextureFilename);

 

                        // Create the texture

                        if( FAILED( D3DXCreateTextureFromFile( m_pD3DDevice,

                                                               szTextureFile, &m_pMeshTextures[i] ) ) )

                        {

                              m_pMeshTextures[i] = NULL;

                        }

                  }

            }

            // Done with the material buffer

            pD3DXMtrlBuffer->Release();

      }

 

 

      void Render()

      {

            D3DXMATRIX matWorld;

            D3DXMatrixTranslation(&matWorld, 0.0f, 0.0f, 0.0f);

            m_pD3DDevice->SetTransform( D3DTS_WORLD, &matWorld);

 

            // Turn on ambient lighting

            m_pD3DDevice->SetRenderState( D3DRS_AMBIENT, 0x00606060 );

 

            // Meshes are divided into subsets, one for each material. Render them in

            // a loop

           

            m_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

 

            m_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

 

           

            for( DWORD i=0; i<m_dwNumMaterials; i++ )

            {

                  // Set the material and texture for this subset

                  m_pD3DDevice->SetMaterial( &m_pMeshMaterials[i] );

 

                  if( m_pMeshTextures[i] != NULL )

                  {

                        m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);

                        m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);

                        m_pD3DDevice->SetTexture( 0, m_pMeshTextures[i] );

                  }

                  else

                  {

                        m_pD3DDevice->SetTexture( 0, NULL );

                        m_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

                        m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);

                        m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );//D3DTA_SPECULAR); //D3DTA_DIFFUSE

                  }

       

                        // Draw the mesh subset

                        m_pMesh->DrawSubset( i );

            }

 

            m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);

            m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);

      }

 

 

      void Release()

      {

            if( m_pMeshMaterials != NULL )

                  delete[] m_pMeshMaterials;

 

            if( m_pMeshTextures )

            {

                  for( DWORD i = 0; i < m_dwNumMaterials; i++ )

                  {

                        if( m_pMeshTextures[i] )

                              m_pMeshTextures[i]->Release();

                  }

                  delete[] m_pMeshTextures;

            }

            if( m_pMesh != NULL )

                  m_pMesh->Release();

      }

};

 

 

 

 

Also so you can see how it was used in the gameengine code to demonstarate it usability....I've included the game.cpp/.h below...

 

 

// game.h

 

class CGame

{

protected:

      // Lets create an instance of our CGraphics class!...m for member, and

      // I chose g for graphics.....not a very descriptive name but I like it.

      CGraphics m_g;

 

      CCamera m_camera;

 

      // not forgetting "D:\\media\\font\\Arial18Normal.bmf"

      CText textA;

 

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

 

      CXLoader x;

 

public:

      // Initilisation called only once in the constructor

      CGame();

 

      // GameLoop, gets called repeatedly while it returns 1;

      bool GameLoop();

 

      // Cleanup process, all done in our destructor

      ~CGame();

};

 

 

 

// game.cpp

 

// Initilisation called only once in the constructor

CGame::CGame()

{

      m_g.Create();

 

      IDirect3DDevice8 *pD3DDevice = NULL;

      m_g.GetScreen( &pD3DDevice );

 

      m_camera.Create( &pD3DDevice );

      textA.Create( pD3DDevice );

 

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

 

      x.Create( &pD3DDevice, "D:\\media\\world\\world1.x", "D:\\media\\world\\");

}

 

 

 

// GameLoop, gets called repeatedly while it returns 1;

bool CGame::GameLoop()

{

 

      IDirect3DDevice8 *pD3DDevice = NULL;

      m_g.GetScreen( &pD3DDevice );

 

      textA.TextOut(L"X-Factor Development - www.xfactordev.net", 50, 50, 0, 255, 255);

 

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

 

      pD3DDevice->BeginScene();

 

      m_camera.Move(0.0f, 0.0f, -100.0f);

      m_camera.UpdateCamera();

 

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      x.Render();

 

      pD3DDevice->EndScene();

 

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

     

 

      // Return 1 for the game to continue, 0 to terminate.

      return 1;

}

 

// Cleanup process, all done in our destructor

CGame::~CGame()

{

      m_g.Release();

      textA.Release();

      m_camera.Release();

}

 

 

See its simply a matter of loading the .x file in and using it in your code.

 

A small note, as its probably vital that you do some collision detection with your objects...as before you know it you'll have them flying all over the place bumping into each other....with this in mind it is very easy to calculate bounding box's and sphere's and do simple collision detection with the following code snippet:

 

 

            BYTE**p;

 

            D3DXVECTOR3 min;

            D3DXVECTOR3 max;

 

            D3DXComputeBoundingBox((void*)p,

                                                m_pMesh->GetNumVertices(),

                                                m_pMesh->GetFVF(),

                                                &min,

                                                &max);

 

            float radius;

            D3DXVECTOR3 vCenter(0.0f, 0.0f, 0.0f);

 

            D3DXComputeBoundingSphere((void*)p,

                                                  m_pMesh->GetNumVertices(),

                                                  m_pMesh->GetFVF(),

                                                  &vCenter,

                                                  &radius);

 

 

Happy Coding...

  XFactorDev.net Article



      
webmaster@xfactordev.net