codesamples >> crossplatform octahedron class

Crossplatform: Octahedron class

Project:

Crossplatform application (Windows & PS3)

Engine:

Custom

Code language:

C++

Class description:

The octahedron class for Windows and PS3.

Octahedron.cpp

#include "Octahedron.h"
#include <math.h>

// Initialize Statics above the class
std::vector<Lod*> Octahedron::m_LODs;

Octahedron::Octahedron(): m_AmountOfVertices(0)
{
	m_Vertices = 6;
	m_Indices = 24;

	//m_LOD = lod;
	m_CurrentTessellation = 0;

	SetLOD(0);
}

Octahedron::~Octahedron()
{
	for(int index = 0; index < NUM_LODS; ++index)
	{
		delete m_LODs[index];
		m_LODs[index] = 0;
	}
}

//--------------------------------------------------------------------------------------
// Init Octahedron data
//--------------------------------------------------------------------------------------
bool Octahedron::InitializeData(DEVICE* device)
{
	if(m_LODs.size() > 0)
	{
		SetLOD(0);
		return false;
	}

	// Setup data for the construction 
	GeometryTriangles srcData;

	// Top point
	srcData.AddVertex(0.0f, 1.0f, 0.0f);

	// Center points
	srcData.AddVertex(1.0f, 0.0f, 0.0f);
	srcData.AddVertex(0.0f, 0.0f, -1.0f);
	srcData.AddVertex(-1.0f, 0.0f, 0.0f);
	srcData.AddVertex(0.0f, 0.0f, 1.0f);

	// Bottom point
	srcData.AddVertex(0.0f, -1.0f, 0.0f);

	// Top faces
	srcData.AddTriangle(0, 1, 2);
	srcData.AddTriangle(2, 3, 0);
	srcData.AddTriangle(0, 3, 4);
	srcData.AddTriangle(0, 4, 1);

	// Bottom faces
	srcData.AddTriangle(5, 1, 4);
	srcData.AddTriangle(5, 4, 3);
	srcData.AddTriangle(5, 3, 2);
	srcData.AddTriangle(5, 2, 1);

#if defined(PS3)
	// Get the amount of indices
	m_VertexCount = srcData.GetIndices().size();

	// Allocate vertex buffer
	uint32_t vsize = sizeof(Vertex_PS3);
	uint32_t vertexBufferOffset;       // this is vidmem

	m_VertexBuffer = (Vertex_PS3 *)cellGcmUtilAllocateLocalMemory(vsize*m_VertexCount, 128);
	assert(m_VertexBuffer != NULL);
	CELL_GCMUTIL_CHECK_ASSERT(cellGcmAddressToOffset(m_VertexBuffer, &vertexBufferOffset));

	printf("m_VertexBufferOffset:0x%08x\n", vertexBufferOffset);

	Vertex_PS3* curBuf = m_VertexBuffer;
	Vertex* vertex;
	// make sure the number of indices is a multiple of 3
	assert((srcData.GetIndices().size()/3)*3 == srcData.GetIndices().size()); 
	
	// Fill out the buffer for the shaders
	for(unsigned int numIndex=0; numIndex < srcData.GetIndices().size(); numIndex++ )
	{
		vertex = srcData.GetVertexAtIndex(srcData.GetIndices()[numIndex]);
		curBuf->Px = vertex->m_x; 
		curBuf->Py = vertex->m_y; 
		curBuf->Pz = vertex->m_z; 

		curBuf->RGBA = 0xFFFFFFFF; 
		curBuf->u = 0.0f; 
		curBuf->v = 0.0f; 

		curBuf++;
	}
#endif

	// Create the LODBuffer
	CreateLODBuffer(device, &srcData);
	
	// Increase the tesselation level
	m_CurrentTessellation++;

	// Tesselate
	Tessellate(device, &srcData);

	return true;
}

bool Octahedron::Tessellate(DEVICE* device, GeometryTriangles* geometryTriangles)
{
	// Get the previous indices and vertices  
	std::vector<INDEX> previousIndices = geometryTriangles->GetIndices();
	std::vector<Vertex> previousVertices = geometryTriangles->GetVertices();

	// Keep track of the new indices and vertices
	std::vector<INDEX> newIndices;
	std::vector<Vertex> newVertices;

	for(int index=0; index < geometryTriangles->GetIndices().size(); index+=3)
	{
		// The 3 previous vertices
		Vertex previousVertex1 = previousVertices[previousIndices[index]];
		Vertex previousVertex2 = previousVertices[previousIndices[index+1]];
		Vertex previousVertex3 = previousVertices[previousIndices[index+2]];

		// Create 3 new vertices based on the previous vertices
		Vertex newVertex1;
		newVertex1.m_x = (previousVertex1.m_x + previousVertex2.m_x)*0.5f;
		newVertex1.m_y = (previousVertex1.m_y + previousVertex2.m_y)*0.5f;
		newVertex1.m_z = (previousVertex1.m_z + previousVertex2.m_z)*0.5f;

		Vertex newVertex2;
		newVertex2.m_x = (previousVertex2.m_x + previousVertex3.m_x)*0.5f;
		newVertex2.m_y = (previousVertex2.m_y + previousVertex3.m_y)*0.5f;
		newVertex2.m_z = (previousVertex2.m_z + previousVertex3.m_z)*0.5f;

		Vertex newVertex3;
		newVertex3.m_x = (previousVertex3.m_x + previousVertex1.m_x)*0.5f;
		newVertex3.m_y = (previousVertex3.m_y + previousVertex1.m_y)*0.5f;
		newVertex3.m_z = (previousVertex3.m_z + previousVertex1.m_z)*0.5f;

		// Normalize
		float length1 = sqrt(newVertex1.m_x*newVertex1.m_x + newVertex1.m_y*newVertex1.m_y + 
		newVertex1.m_z*newVertex1.m_z);
		float length2 = sqrt(newVertex2.m_x*newVertex2.m_x + newVertex2.m_y*newVertex2.m_y + 
		newVertex2.m_z*newVertex2.m_z);
		float length3 = sqrt(newVertex3.m_x*newVertex3.m_x + newVertex3.m_y*newVertex3.m_y + 
		newVertex3.m_z*newVertex3.m_z);

		newVertex1.m_x /= length1;
		newVertex1.m_y /= length1;
		newVertex1.m_z /= length1;

		newVertex2.m_x /= length2;
		newVertex2.m_y /= length2;
		newVertex2.m_z /= length2;

		newVertex3.m_x /= length3;
		newVertex3.m_y /= length3;
		newVertex3.m_z /= length3;

		// Based on new vertices create 4 new triangles
		newVertices.push_back(previousVertex1);
		newVertices.push_back(newVertex1);
		newVertices.push_back(newVertex3);

		newVertices.push_back(newVertex3);
		newVertices.push_back(newVertex2);
		newVertices.push_back(previousVertex3);

		newVertices.push_back(newVertex1);
		newVertices.push_back(previousVertex2);
		newVertices.push_back(newVertex2);

		newVertices.push_back(newVertex1);
		newVertices.push_back(newVertex2);
		newVertices.push_back(newVertex3);
	}

	// Set the indices
	for(int index=0; index < newVertices.size(); ++index)
	{
		newIndices.push_back(index);
	}

	// Save new vertices to previous vertices (use swap to also switch the capacity of the vector)
	geometryTriangles->GetVertices().swap(newVertices);
	geometryTriangles->GetIndices().swap(newIndices);

	// Create LOD buffers
	CreateLODBuffer(device, geometryTriangles);

	// Increase tesselation
	m_CurrentTessellation++;

	// Keep tesselating until maximum is reached
	if(m_CurrentTessellation < NUM_LODS)
	{
		Tessellate(device, geometryTriangles);
	}

	return true;
}

void Octahedron::SetLOD(int lod)
{
	if(m_LOD == lod || lod >= NUM_LODS)
		return;

	m_LOD = lod;
}

bool Octahedron::CreateLODBuffer(DEVICE* device, GeometryTriangles* srcData)
{
	int numVertices = srcData->GetVertices().size();
	int numIndices = srcData->GetIndices().size();

	Lod* activeLod = new Lod();

#if defined(WIN32)
	D3D11_BUFFER_DESC bd;
	ZeroMemory(&bd, sizeof(bd));
   
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(Vertex) * numVertices;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;

	D3D11_SUBRESOURCE_DATA InitData;
	ZeroMemory(&InitData, sizeof(InitData));

	InitData.pSysMem = &srcData->GetVertices()[0];
	// Create Vertex buffer
	device->GetDevice()->CreateBuffer(&bd, &InitData, &activeLod->m_pVertexBuffer);

	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(INDEX) * numIndices;
	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bd.CPUAccessFlags = 0;
	InitData.pSysMem = &srcData->GetIndices()[0];
	// Create Index buffer
	device->GetDevice()->CreateBuffer(&bd, &InitData, &activeLod->m_pIndexBuffer);

#elif(PS3)
	m_VertexCount = srcData->GetIndices().size();

	// Allocate vertex buffer
	uint32_t vsize = sizeof(Vertex_PS3);
	uint32_t vertexBufferOffset;       // this is vidmem

	//m_VertexBuffer = (Vertex_PS3 *)cellGcmUtilAllocateLocalMemory(vsize*m_VertexCount, 128);
	activeLod->m_pVertexBuffer = (Vertex_PS3 *)cellGcmUtilAllocateLocalMemory(vsize*m_VertexCount, 128);
	assert(activeLod->m_pVertexBuffer != NULL);
	CELL_GCMUTIL_CHECK_ASSERT(cellGcmAddressToOffset(activeLod->m_pVertexBuffer, &vertexBufferOffset));

	printf("m_VertexBufferOffset:0x%08x\n", vertexBufferOffset);

	Vertex_PS3* curBuf = activeLod->m_pVertexBuffer;
	Vertex* vertex;
	// make sure the number of indices is a multiple of 3
	assert((srcData->GetIndices().size()/3)*3 == srcData->GetIndices().size()); 
	
	// Fill out the buffer for the shaders
	for(unsigned int numIndex = 0; numIndex < srcData->GetIndices().size(); numIndex++ )
	{
		vertex = srcData->GetVertexAtIndex(srcData->GetIndices()[numIndex]);
		curBuf->Px = vertex->m_x; 
		curBuf->Py = vertex->m_y; 
		curBuf->Pz = vertex->m_z; 

		curBuf->RGBA = 0xFFFFFFFF; 
		curBuf->u = 0.0f; 
		curBuf->v = 0.0f; 

		curBuf++;
	}
#endif

	// Set the CurrentLOD
	activeLod->m_NumVertices = numVertices;
	activeLod->m_NumIndices = numIndices;
	
	// Add the current LOD to the Vector of LODs
	m_LODs.push_back(activeLod);

	return true;
}

#if defined(PS3)
void Octahedron::Render(Camera* camera, CGprogram cGVertexProgram, CGprogram cGFragmentProgram, 
void* vertexProgramUCode, void* fragmentProgramUCode)
{
	float MLocal[16];
	float MVP[16];

	camera->EulerRotate(MLocal, m_AngleX, m_AngleY, m_AngleZ); 
	MLocal[0*4+3] = m_PosX;
	MLocal[1*4+3] = m_PosY;
	MLocal[2*4+3] = m_PosZ; 

	camera->MatrixMul(MVP, &camera->GetView().m[0][0], MLocal);  
	camera->MatrixMul(MVP, camera->m_MVP, MVP);

	// set uniform variables 
	// NOTE: this modifies the ucode but currently the ucode is inlined into the push buffer
	CGparameter modelViewProj = cellGcmCgGetNamedParameter(cGVertexProgram, "modelViewProj");
	CGparameter objCoord = cellGcmCgGetNamedParameter(cGVertexProgram, "a2v.objCoord");

	CELL_GCMUTIL_CG_PARAMETER_CHECK_ASSERT( modelViewProj );
	CELL_GCMUTIL_CG_PARAMETER_CHECK_ASSERT( objCoord );

	cellGcmSetVertexProgramParameter(modelViewProj, MVP);

	// get Vertex Attribute index
	uint32_t ObjCoordIndex = cellGcmCgGetParameterResource(cGVertexProgram, objCoord) - CG_ATTR0; 

	// bind the shaders
	// NOTE: vertex program constants are copied here
	cellGcmSetVertexProgram(cGVertexProgram, vertexProgramUCode);

	uint32_t fragment_offset;
	CELL_GCMUTIL_CHECK_ASSERT(cellGcmAddressToOffset(fragmentProgramUCode, &fragment_offset));
	cellGcmSetFragmentProgram(cGFragmentProgram, fragment_offset);

	uint32_t vertex_offset[3];
	CELL_GCMUTIL_CHECK_ASSERT(cellGcmAddressToOffset(&m_LODs[m_LOD]->GetVertexBuffer()->Px, 
	&vertex_offset[0]));
	CELL_GCMUTIL_CHECK_ASSERT(cellGcmAddressToOffset(&m_LODs[m_LOD]->GetVertexBuffer()->RGBA, 
	&vertex_offset[1]));
	CELL_GCMUTIL_CHECK_ASSERT(cellGcmAddressToOffset(&m_LODs[m_LOD]->GetVertexBuffer()->u, 
	&vertex_offset[2]));

	// set vertex pointer
	cellGcmSetVertexDataArray(ObjCoordIndex, 0, sizeof(Vertex_PS3), 3,
	CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, vertex_offset[0]);

	// Render call
	cellGcmSetDrawArrays(CELL_GCM_PRIMITIVE_TRIANGLES, 0, m_LODs[m_LOD]->GetNumIndices());
}
#endif

#if defined(WIN32)
void Octahedron::Render(Camera* camera, ID3D11DeviceContext* deviceContext, ID3D11VertexShader* vertexShader, 
ID3D11PixelShader* pixelShader, float time)
{
	//
	// Render the cube
	//
	// Rotate cube around the origin
	XMMATRIX mObj;

	//
	// Update variables that change once per frame
	//

	// Set vertex buffer
	UINT stride = sizeof(Vertex);
	UINT offset = 0;

	deviceContext->IASetVertexBuffers(0, 1, &m_LODs[m_LOD]->GetVertexBuffer(), &stride, &offset);
	
	// Set index buffer
	deviceContext->IASetIndexBuffer(m_LODs[m_LOD]->GetIndexBuffer(), DXGI_FORMAT_R16_UINT, 0);

	// Set primitive topology
	deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	m_AngleY += time;

	mObj = XMMatrixRotationRollPitchYaw(m_AngleX, m_AngleY, m_AngleZ);

	mObj.m[3][0] = m_PosX;
	mObj.m[3][1] = m_PosY;
	mObj.m[3][2] = m_PosZ;
	mObj.m[3][3] = 1.0f;

	// Update World Matrix
	CBChangesEveryFrame cb;
	cb.mWorld = XMMatrixTranspose(mObj);
	deviceContext->UpdateSubresource(camera->GetpCBChangesEveryFrame(), 0, NULL, &cb, 0, 0);

	// Update View Matrix
	CBNeverChanges cbNeverChanges;
	cbNeverChanges.mView  = XMMatrixTranspose(camera->GetView());
	deviceContext->UpdateSubresource(camera->GetpCBNeverChanges(), 0, NULL, &cbNeverChanges, 0, 0);

	// Update Projections Matrix
	CBChangeOnResize cbChangesOnResize;
	cbChangesOnResize.mProjection = XMMatrixTranspose(camera->GetProjection());
	deviceContext->UpdateSubresource(camera->GetpCBChangeOnResize(), 0, NULL, &cbChangesOnResize, 0, 0);

	deviceContext->VSSetShader(vertexShader, NULL, 0); 
	deviceContext->VSSetConstantBuffers(0, 1, &camera->GetpCBNeverChanges());
	deviceContext->VSSetConstantBuffers(1, 1, &camera->GetpCBChangeOnResize());

	deviceContext->VSSetConstantBuffers(2, 1, &camera->GetpCBChangesEveryFrame());

	deviceContext->PSSetShader(pixelShader, NULL, 0 );
	deviceContext->PSSetConstantBuffers(2, 1, &camera->GetpCBChangesEveryFrame());

	deviceContext->DrawIndexed(m_LODs[m_LOD]->GetNumIndices(), 0, 0);
}
#endif

Octahedron.h

#ifndef _OCTAHEDRON_H
#define _OCTAHEDRON_H

// Crossplatform: Includes
#include <vector>
#include <assert.h>
#include "Structs.h"
#include "GeometryTriangles.h"
#include "Camera.h"

#include "Primitive.h"
#include "Lod.h"

// Windows Specific: Includes
#if defined(WIN32)
#include <windows.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dcompiler.h>
#include <xnamath.h>
#endif

// DEVICE definition
#if defined(WIN32)
#include "Device_Win32.h"
#elif(PS3)
#include "Device_PS3.h"
#endif

class Octahedron: public Primitive
{
public:

	// Crossplatform: Functions
	Octahedron();
	~Octahedron();

	bool InitializeData(DEVICE* device);
	bool Tessellate(DEVICE* device, GeometryTriangles* geometryTriangles);
	bool CreateLODBuffer(DEVICE* device, GeometryTriangles* srcData);
	virtual void SetLOD(int lod);

#if defined(WIN32)
	virtual void Render(Camera* camera, ID3D11DeviceContext* deviceContext, ID3D11VertexShader* vertexShader, 
	ID3D11PixelShader* pixelShader, float time);
#elif(PS3)
	virtual void Render(Camera* camera, CGprogram cGVertexProgram, CGprogram cGFragmentProgram, 
	void* vertexProgramUCode, void* fragmentProgramUCode);
#endif

private:
	
	// Crossplatform: Datamembers
	unsigned int m_AmountOfVertices;
	static const int NUM_LODS = 5;
	static std::vector<Lod*> m_LODs;
	int m_LOD;
	int m_CurrentTessellation;

	#if defined(PS3)
	// PS3 Specific: Datamembers				
	Vertex_PS3* m_VertexBuffer;
	uint32_t m_VertexCount;
	#endif
};
#endif