Sign in to follow this  
  • entries
    132
  • comments
    99
  • views
    88618

And Now For Something Completely Different

Sign in to follow this  
Driv3MeFar

144 views

At the end of my last entry I promised I'd have something to show by the weekend, and here it is:


I've started a simple little isometric tile renderer, because it's something I've always wanted to do and shouldn't be too hard or time consuming. It's fully 3D, I just have a fixed camera set up to give the isometric look to the rectangles I'm rendering, which comes in handy for things like lighting (not yet implemented) and z buffering.

Here's some of the relevant code:
Hacky rendering code

#include
#include
#include
#include "../Header Files/Renderer.h"
#include "../Header Files/GeometryBuffer.h"
#include "../Header Files/Tile.h"

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

ISO::Graphics::Renderer::Renderer(HWND hWnd)
: m_D3D(NULL),
m_D3DDevice(NULL)
{
m_D3D = ::Direct3DCreate9(D3D_SDK_VERSION);
if (!m_D3D)
{
return;
}

D3DPRESENT_PARAMETERS params = {0};
params.Windowed = TRUE;
params.SwapEffect = D3DSWAPEFFECT_DISCARD;
params.BackBufferFormat = D3DFMT_UNKNOWN;
params.EnableAutoDepthStencil = TRUE;
params.AutoDepthStencilFormat = D3DFMT_D16;


m_D3D->CreateDevice( D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
¶ms,
&m_D3DDevice );
if (!m_D3DDevice)
{
m_D3D->Release();
}


m_D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
m_D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
//m_D3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
//m_D3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
//hack: fixed iso camera
D3DXMATRIX view;
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXVECTOR3 at(100.f, 0.f, 100.f);
D3DXVECTOR3 eye(-100.f, 200.f, -100.f);
D3DXMatrixLookAtLH(&view, &eye, &at, &up );
m_D3DDevice->SetTransform(D3DTS_VIEW, &view);
m_D3DDevice->SetFVF(ISO::Graphics::D3DFVF_CUSTOMVERTEX);
//end hack
}

ISO::Graphics::Renderer::~Renderer()
{
for (unsigned i = 0; i < m_GeometryBuffers.size(); ++i)
{
delete m_GeometryBuffers;
}

if (m_D3DDevice)
{
m_D3DDevice->Release();
m_D3DDevice = NULL;
}

if (m_D3D)
{
m_D3D->Release();
m_D3D = NULL;
}

}

void ISO::Graphics::Renderer::Render()
{
if( NULL == m_D3DDevice )
return;

// Clear the backbuffer to a blue color
m_D3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );

// Begin the scene
if( SUCCEEDED( m_D3DDevice->BeginScene() ) )
{
m_D3DDevice->SetTransform(D3DTS_PROJECTION, &m_MatProj);
// Rendering of scene objects can happen here
for(unsigned i = 0; i < m_GeometryBuffers.size(); ++i)
{
m_D3DDevice->SetStreamSource(0, m_GeometryBuffers->GetVertexBufferPointer(), 0, sizeof(Vertex));
m_D3DDevice->SetIndices(m_GeometryBuffers->GetIndexBufferPointer());
HRESULT hr = m_D3DDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,
0,
0,
m_GeometryBuffers->GetNumVertices(),
0,
m_GeometryBuffers->GetNumPrimitives() );
if (FAILED(hr))
{
assert(0);
}
}

// End the scene
m_D3DDevice->EndScene();
}

// Present the backbuffer contents to the display
m_D3DDevice->Present( NULL, NULL, NULL, NULL );
}

void ISO::Graphics::Renderer::InitProjection(float windowWidth, float windowHeight, float zNear, float zFar)
{
D3DXMatrixOrthoLH( &m_MatProj,
windowWidth,
windowHeight,
zNear,
zFar );
}

int ISO::Graphics::Renderer::AddTile(float bX, float bY, float bZ, float tX, float tY, float tZ)
{
Vertex verts[] =
{
{bX, bY, bZ, 0.f, 0.f, 0.f, D3DCOLOR_XRGB(0, 255, 0), 0.f, 0.f},
{bX, tY, bZ, 0.f, 0.f, 0.f, D3DCOLOR_XRGB(0, 0, 0), 0.f, 0.f},
{bX, tY, tZ, 0.f, 0.f, 0.f, D3DCOLOR_XRGB(0, 255, 0), 0.f, 0.f},
{bX, bY, tZ, 0.f, 0.f, 0.f, D3DCOLOR_XRGB(0, 255, 0), 0.f, 0.f},
{tX, bY, tZ, 0.f, 0.f, 0.f, D3DCOLOR_XRGB(0, 255, 0), 0.f, 0.f},
{tX, bY, bZ, 0.f, 0.f, 0.f, D3DCOLOR_XRGB(0, 255, 0), 0.f, 0.f},
{tX, tY, bZ, 0.f, 0.f, 0.f, D3DCOLOR_XRGB(0, 255, 0), 0.f, 0.f},
{tX, tY, tZ, 0.f, 0.f, 0.f, D3DCOLOR_XRGB(0, 255, 0), 0.f, 0.f}
};

short indices[] = { 0, 1, 2,
0, 2, 3,
3, 2, 7,
3, 7, 4,
4, 7, 6,
4, 6, 5,
5, 6, 1,
5, 1, 0,
6, 7, 2,
6, 2, 1,
4, 5, 0,
4, 0, 3 };

if (m_GeometryBuffers.empty() ||
m_GeometryBuffers.back()->GetNumVertices() > 792)
{
m_GeometryBuffers.push_back(new GeometryBuffer(m_D3DDevice, 800, 3200));
}

assert(!m_GeometryBuffers.empty());
assert(m_GeometryBuffers.back()->GetNumVertices() <= 792);

m_GeometryBuffers.back()->AddGeomtry(verts, 8, indices, 36);


return -1;
}



My tiles are all batched together into large vertex/index buffers, so all the tiles being drawn in the picture (9 of them) are taken care of in a single DrawIndexedPrimitive call. Right now the buffers I have set up can hold up to 100 tiles each, but that's easy enough to change. Here's the code that manages the vertex and index buffers:
GeometryBuffer.h

#ifndef GEOMETRYBUFFER_H
#define GEOMETRYBUFFER_H

#include "VertexBuffer.h"
#include "IndexBuffer.h"

namespace ISO
{
namespace Graphics
{
class GeometryBuffer
{
public:
GeometryBuffer(LPDIRECT3DDEVICE9 device, int numVerts, int numIndices);
~GeometryBuffer();

int AddGeomtry(Vertex *verts, int numVerts, short *indices, int numIndices);

LPDIRECT3DVERTEXBUFFER9 GetVertexBufferPointer();
LPDIRECT3DINDEXBUFFER9 GetIndexBufferPointer();

int GetNumPrimitives() const;
int GetNumVertices();
private:
VertexBuffer m_VertexBuffer;
IndexBuffer m_IndexBuffer;
int m_NumPrimitives;
};
}
}

#endif



GeometryBuffer.cpp

#include "../Header Files/GeometryBuffer.h"
#include "../Header Files/Renderer.h"

ISO::Graphics::GeometryBuffer::GeometryBuffer(LPDIRECT3DDEVICE9 device, int numVerts, int numIndices)
: m_VertexBuffer(device, numVerts),
m_IndexBuffer(device, numIndices),
m_NumPrimitives(0)
{
}

ISO::Graphics::GeometryBuffer::~GeometryBuffer()
{
}

int ISO::Graphics::GeometryBuffer::AddGeomtry(Vertex *verts, int numVerts, short *indices, int numIndices)
{
short i = static_cast<short>(m_VertexBuffer.AddVertices(verts, numVerts));
for (int index = 0; index < numIndices; ++index)
{
indices[index] = i + indices[index];
}
m_IndexBuffer.AddIndices(indices, numIndices);

m_NumPrimitives += numIndices / 3;

return 0;
}

LPDIRECT3DVERTEXBUFFER9 ISO::Graphics::GeometryBuffer::GetVertexBufferPointer()
{
return m_VertexBuffer.GetVertexBufferPointer();
}

LPDIRECT3DINDEXBUFFER9 ISO::Graphics::GeometryBuffer::GetIndexBufferPointer()
{
return m_IndexBuffer.GetIndexBufferPointer();
}

int ISO::Graphics::GeometryBuffer::GetNumPrimitives() const
{
return m_NumPrimitives;
}

int ISO::Graphics::GeometryBuffer::GetNumVertices()
{
return m_VertexBuffer.GetCurrentIndex();
}



VertexBuffer.h

#ifndef VERTEXBUFFER_H
#define VERTEXBUFFER_H

#include "Renderer.h"

namespace ISO
{
namespace Graphics
{
struct Vertex
{
float x, y, z; //position
float Nx, Ny, Nz; //normal
D3DCOLOR color; //diffuse color
float u, v; //tex coords
};
static const DWORD D3DFVF_CUSTOMVERTEX = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;

class VertexBuffer
{
public:
VertexBuffer(LPDIRECT3DDEVICE9 device, int size);
~VertexBuffer();

int AddVertices(Vertex *verts, int numVerts);

LPDIRECT3DVERTEXBUFFER9 GetVertexBufferPointer();
const int GetCurrentIndex();
private:
LPDIRECT3DVERTEXBUFFER9 m_VertexBuffer;
int m_Index;
};
}
}

#endif



VertexBuffer.cpp

#include
#include
#include "../Header Files/VertexBuffer.h"

ISO::Graphics::VertexBuffer::VertexBuffer(LPDIRECT3DDEVICE9 device, int size)
: m_VertexBuffer(NULL),
m_Index(0)
{
assert(size > 0);
HRESULT hr = device->CreateVertexBuffer( size * sizeof(Vertex),
D3DUSAGE_WRITEONLY,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&m_VertexBuffer,
NULL );
if (FAILED(hr))
{
return;
}
}

ISO::Graphics::VertexBuffer::~VertexBuffer()
{
if (m_VertexBuffer)
{
m_VertexBuffer->Release();
}
}

int ISO::Graphics::VertexBuffer::AddVertices(ISO::Graphics::Vertex *verts, int numVerts)
{
assert(m_VertexBuffer);

Vertex *buffer;
HRESULT hr = m_VertexBuffer->Lock(m_Index * sizeof(Vertex), numVerts * sizeof(Vertex), (void**)&buffer, 0);

if (FAILED(hr))
{
return -1;
}

std::copy(verts, verts + numVerts, buffer);

hr = m_VertexBuffer->Unlock();
if (FAILED(hr))
{
return -1;
}

int retVal = m_Index;
m_Index += numVerts;

return retVal;
}

LPDIRECT3DVERTEXBUFFER9 ISO::Graphics::VertexBuffer::GetVertexBufferPointer()
{
assert(m_VertexBuffer);
return m_VertexBuffer;
}

const int ISO::Graphics::VertexBuffer::GetCurrentIndex()
{
return m_Index;
}



IndexBuffer.h

#ifndef INDEXBUFFER_H
#define INDEXBUFFER_H

#include "Renderer.h"

namespace ISO
{
namespace Graphics
{
class IndexBuffer
{
public:
IndexBuffer(LPDIRECT3DDEVICE9 device, int size);
IndexBuffer(const IndexBuffer& iBuff);
~IndexBuffer();

int AddIndices(short *indices, int numIndices);

LPDIRECT3DINDEXBUFFER9 GetIndexBufferPointer() const;
private:
LPDIRECT3DINDEXBUFFER9 m_IndexBuffer;
int m_CurrentIndex;
};
}
}

#endif



IndexBuffer.cpp

#include
#include
#include "../Header Files/IndexBuffer.h"

ISO::Graphics::IndexBuffer::IndexBuffer(LPDIRECT3DDEVICE9 device, int size)
: m_IndexBuffer(NULL),
m_CurrentIndex(0)
{
assert(size > 0);

HRESULT hr = device->CreateIndexBuffer( size * sizeof(short),
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_DEFAULT,
&m_IndexBuffer,
NULL );

if (FAILED(hr))
{
return;
}
}

ISO::Graphics::IndexBuffer::IndexBuffer(const ISO::Graphics::IndexBuffer& iBuff)
{
iBuff;
}

ISO::Graphics::IndexBuffer::~IndexBuffer()
{
if (m_IndexBuffer)
{
m_IndexBuffer->Release();
}
}

int ISO::Graphics::IndexBuffer::AddIndices(short *indices, int numIndices)
{
assert(m_IndexBuffer);

short *Indices;
HRESULT hr = m_IndexBuffer->Lock(m_CurrentIndex * sizeof(short), numIndices * sizeof(short), (void**)&Indices, D3DLOCK_NOOVERWRITE);
if (FAILED(hr))
{
return -1;
}

std::copy(indices, indices + numIndices, Indices);

hr = m_IndexBuffer->Unlock();
if (FAILED(hr))
{
return -1;
}

m_CurrentIndex += numIndices;

return 0;
}

LPDIRECT3DINDEXBUFFER9 ISO::Graphics::IndexBuffer::GetIndexBufferPointer() const
{
assert(m_IndexBuffer);
return m_IndexBuffer;
}



Pretty simple stuff, really. Shouldn't have taken me more than a few hours to do, but I've been busy and yadda yadda yadda.

Also, Pix is super awesome.
Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now