www.xbdev.net xbdev - software development
Monday December 10, 2018
home | about | contact | Donations

     
 

XBOX Programming..

More than just a toy...

 

Prt7 - A Complex Bunny Shape...

by Ben_3D@xfactordev.net

 

 

Hehehehe, a bunny shape and more... well to keep things simple and to introduce the concept of how 3D file systems worked, I came across a very simple file system called .plg.  Its a text based file system and you can open it with notepad.  Let me show you a snippet of what lies inside (Oct.plg:

Oct-Shape 6 8

1.0 0.0 0.0
-1.0 0.0 0.0
0.0 1.0 0.0
0.0 -1.0 0.0
0.0 0.0 1.0
0.0 0.0 -1.0

109 3 4 1 3
109 3 4 3 0
109 3 4 0 2
109 3 4 2 1
109 3 5 0 3
109 3 5 3 1
109 3 5 1 2
109 3 5 2 0

 

We have the shape name followed by the number of vertices and then the number of sides, e.g. 6 vertices and 8 triangles.  Now what follows might be a bit wobbly to a new 3D programmer, but its a list of all the vertices once, for example a cube would have 8 vertices ... one for each corner.

So after that, we have the index of each face, so "109 3 4 1 3", 109 is the colour (0-255), 3 is the number of sides for this shape (3 for a triangle), followed by the index into the vertice list, so we would have 4th joined to the 1st then joined to the 3rd vertices and closing it would make our triangle.

Now believe it or not, this is how nearly all 3D formats work, .md2 (quake format), .3ds (3d studio max format) all use this format... and many many more.

Keeping my code simple, I've put the DirectX initialisation and cleanup functions in a separate file "init.cpp" and the main code in main.cpp.  It makes things simpler to follow, and well its rare that you'll ever need to change init.cpp.

 

Grab hold of your chair.... in we go....

 

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

/*                                                                         */

/* FileName: init.cpp                                                      */

/*                                                                         */

/* Details: shapes from files.                                             */

/*                                                                         */

/* Author: Ben_3D@xbdev.net                                           */

/*                                                                         */

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

 

//Main header file for the XDK

#include <xtl.h>

 

LPDIRECT3D8 g_pD3D = NULL;                      // DirectX Object

LPDIRECT3DDEVICE8 g_pD3DDevice = NULL;          // Screen Object

 

void InitialiseD3D()

{

    g_pD3D = Direct3DCreate8(D3D_SDK_VERSION);

    D3DPRESENT_PARAMETERS d3dpp;

    ZeroMemory(&d3dpp, sizeof(d3dpp));

      d3dpp.BackBufferWidth = 640;

      d3dpp.BackBufferHeight = 480;

      d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;

      d3dpp.BackBufferCount = 1;

      d3dpp.EnableAutoDepthStencil = TRUE;

      d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;

      d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

    g_pD3D->CreateDevice(0, D3DDEVTYPE_HAL, NULL,

                                   D3DCREATE_HARDWARE_VERTEXPROCESSING,

                                                   &d3dpp, &g_pD3DDevice);

 

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

      //Our 3D shapes are going to use a colour defined by us, and we don't have

      //any lighting so we set the lighting to false.

      g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, false);

      //Turn on z-buffering

      g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);

     

      g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);

}

 

void CleanUp()

{

    g_pD3DDevice->Release();

    g_pD3D->Release();

}

 

Well if you look at the above code is should be boring and repetaive...so don't worry about it...all your exciting and wonderful directX code has it in :)

Now for the sticky slimmy code that makes you wanna queez...

 

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

/*                                                                         */

/* FileName: main.cpp                                                      */

/*                                                                         */

/* Details: shapes from files.                                             */

/*                                                                         */

/* Author: Ben_3D@xbdev.net                                           */

/*                                                                         */

/*                                                                         */

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

 

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

 

char shapefilename[] = "D:\\Rabbit.plg";

 

// Main header file for the XDK

#include <xtl.h>

 

// Standard librarys used to read in our data from file. 3D object.

#include <stdio.h>

#include <fstream.h>

 

#include "init.cpp"

 

// Here are a couple of structures to store our data, its so much tidier to use

// structures, as we can store an XYZ value in the stXYZ stucture, an if we need

// to access it we can just go stXYZ myP;  myP.x = 0;  etc.

struct stXYZ

{

      float x, y, z;

};

 

struct stFace

{

      int p1;

      int p2;

      int p3;

};

// These are our global variables, I'm going to load the 3D object in, and put

// them in here.

 

// Global variables.  These will hold the data that contains our shapes.

stXYZ*      pVerts;

stFace*           pFaces;

int iNum_vectors  = 0;

int iNum_polys          = 0;

 

// Our wonderful wonderful loader function, if you look at this funciton you'll

// notice that it works on either the xdk and windows, and would even work

// on linux as it uses the standard librarys.

int loadshape(char *filename)

{

      long        int    colour;

    int         i;

    char        temp[16];

 

    // Error if iNum_vectors = 0 when returning from function

      int iNum_points         = 0; // Temp used to determine if the side is made up

                               // of 3 sides (triangle or more).

     

    ifstream fin(filename);

 

    if(!fin) {

        // If where in here, and error occured opening the file.

        return 0;

    }

 

    // read in number of points and polygons in object

    fin >> temp >> iNum_vectors >> iNum_polys;

    // Initialize our arrays

    pVerts        = new stXYZ[iNum_vectors];

 

    pFaces        = new stFace[iNum_polys];

 

 

    // read in all the vectors used in this object

    for (i=0; i<iNum_vectors; i++)

    {

        fin >> pVerts[i].x >> pVerts[i].y >> pVerts[i].z;

    }

 

    // now read in all of the polygon data

    for (i=0; i<iNum_polys; i++)

    {

        fin >> colour;

        // We could use the colour in some way.. but I'm just going to set

            // all the faces to the same colour... keep it nice and simple :)

 

        fin >> iNum_points;

 

            if( iNum_points > 3 )

            {

                  return 0; // Our code only supports triangles.

            }

 

        fin >> pFaces[i].p1 >> pFaces[i].p2 >> pFaces[i].p3;

   

      }

    fin.close();

}

 

// Now upto now there's been "No" directX used, only knowledge of the 3d file,

// and the c and c++ standard librarys.  So what I'm going to do, is load the

// vertex points into the directX buffers and display it.  This isn't very

// efficent... but its simple to follow :)

void DrawShape()

{

     

      struct CUSTOMVERTEX

      {

            FLOAT x, y, z;

            DWORD colour;

      };

 

      CUSTOMVERTEX *myVertices = new CUSTOMVERTEX[iNum_polys*3];

      // Total number of triangles is iNum_polys

      int index=0;

      for (int i=0; i<iNum_polys; i++)

      {

            myVertices[index].x = pVerts[pFaces[i].p1].x;

            myVertices[index].y = pVerts[pFaces[i].p1].y;

            myVertices[index].z = pVerts[pFaces[i].p1].z;

            myVertices[index].colour = 0xff00ffff;

 

            index++;

            myVertices[index].x = pVerts[pFaces[i].p2].x;

            myVertices[index].y = pVerts[pFaces[i].p2].y;

            myVertices[index].z = pVerts[pFaces[i].p2].z;

            myVertices[index].colour = 0xff0ff00f;

 

            index++;

            myVertices[index].x = pVerts[pFaces[i].p3].x;

            myVertices[index].y = pVerts[pFaces[i].p3].y;

            myVertices[index].z = pVerts[pFaces[i].p3].z;

            myVertices[index].colour = 0xff00ffff;

 

            index++;

      }

     

     

      LPDIRECT3DVERTEXBUFFER8 pVertexBuffer = NULL;

      UINT D3DFVF_CUSTOMVERTEX =  (D3DFVF_XYZ|D3DFVF_DIFFUSE);

     

      g_pD3DDevice->CreateVertexBuffer(3 * iNum_polys * sizeof(CUSTOMVERTEX),

                                               0, D3DFVF_CUSTOMVERTEX,

                                               D3DPOOL_DEFAULT, &pVertexBuffer);

      VOID* pV;

      pVertexBuffer->Lock(0,0, (BYTE**)&pV, 0);

      memcpy(pV, myVertices, sizeof(CUSTOMVERTEX)*iNum_polys*3);

      pVertexBuffer->Unlock();

 

      g_pD3DDevice->SetStreamSource(0, pVertexBuffer, sizeof(CUSTOMVERTEX));

      g_pD3DDevice->SetVertexShader(D3DFVF_CUSTOMVERTEX);

      g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, iNum_polys);

 

 

      pVertexBuffer->Release();

      delete myVertices;

     

}

 

 

void Render()

{

                  //Clear the backbuffer to black

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

            //Begin the scene

            g_pD3DDevice->BeginScene();

 

 

                  //camera camera camera camera camera camera camera camera camera camera

                  D3DXMATRIX view_matrix, matProj;

                  D3DXMatrixLookAtLH(&view_matrix,&D3DXVECTOR3( 0.0f, 0.0f,-4.0f ),

                                   &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),

                                   &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ));

                  g_pD3DDevice->SetTransform(D3DTS_VIEW,&view_matrix);

                  D3DXMatrixPerspectiveFovLH(&matProj, //Result Matrix

                              D3DX_PI/4,//Field of View, in radians. (PI/4) is typical

                              ((float)600 / (float)400),     //Aspect ratio

                              1.0f,     //Near view plane

                              1000.0f ); // Far view plane

                  g_pD3DDevice->SetTransform( D3DTS_PROJECTION, &matProj );

                  //end camera end camera end camera end camera end camera end camera end

 

                  //Okay this all may seem scary for someone new to matrix's
//but these few lines

                  //of code rotate our sphere so that we can make sure its round :)

                  D3DXMATRIX matWorld;

                  D3DXMATRIX trans_matrix;   //Our translation matrix

                  D3DXMATRIX y_rot_matrix;

                  static float y_rot=0;

                  y_rot-=0.005f;

                  //Set up the rotation matrix for the triangle

                  D3DXMatrixRotationY(&y_rot_matrix,y_rot);

                  //Set up the translation matrix (move it over to the left a bit)

                  D3DXMatrixTranslation(&trans_matrix,-1.0,0.0f,0.0f);

                  //Combine out matrices

                  D3DXMatrixMultiply(&matWorld,&y_rot_matrix,&trans_matrix);

                  //Set our World Matrix

                  g_pD3DDevice->SetTransform(D3DTS_WORLD,&matWorld );

 

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

                  DrawShape();

 

            //End the scene

            g_pD3DDevice->EndScene();

 

            //Filp the back and front buffers so that whatever has been rendered on
//the back buffer

            //will now be visible on screen (front buffer).

 

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

}

 

/////////////////////////////////////////////////////////////////////////////////////////

//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 NEW NEW

 

//Application entry point

void __cdecl main()

{

        InitialiseD3D();

       

        loadshape(shapefilename);

 

      while(true)

      {

         Render();  

      }    

 

      CleanUp();

}

 

There's a lot of code there, I hope some of it is easy to follow the main pieces of code you should be chewing up slowly is "loadshape(..)" and the "DrawShape()" functions.  We call "loadshape(..)" once at the start which loads our data in from the file, then in our main loop we call "DrawShape()" over and over again and it takes our vertices and face data that we loaded in and puts it into a list of triangle faces and puts it to the screen.

Looking at the first part of this code you might realise that its standard C... no DirectX or anthing special...just C...hmmm...I know what your thinking... well you can use other C functions and load in other file formats such as .3ds for .md3 etc...yup.. .its as easy as that.

 

(Back Tutorials Page)

 

 

 

 

 
 Visitor: 9534626  { 209.237.238.175 } Copyright (c) 2002-2017 xbdev.net - All rights reserved.
Designated tutorial and software are the property of their respective owners.