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