Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    132
  • comments
    99
  • views
    89009

And Now For Something Completely Different

Sign in to follow this  
Driv3MeFar

171 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
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!