ember/external/meshtree/MeshTree.cpp
Erik Ogenvik 271cf8024f More compiler warnings and use "external".
Put all external code under "external".
We can't use too many warnings though since there's a lot of code we
don't control.
2019-09-22 01:23:55 +02:00

236 lines
8.1 KiB
C++

#include "MeshTree.h"
//---------------------------------------------------------------------------
/*
Based "The Creation and Rendering of Realistic Trees" article by Jason Weber and Joseph Penn
Based on a port of Delphi code from TReal project by Ton van den Heuvel
For further information go see:
http://members.chello.nl/~l.vandenheuvel2/TReal/
Copyright (c) 2002-2003, Ton van den Heuvel
Copyright (c) 2004, Nicolas Chauvin
==================================
Tree generation classes for Ogre3D
==================================
*/
namespace Ogre {
//===========================================================================
// Class Tree
//===========================================================================
Tree::Tree(const String& name, TParameters *pParameters, uchar u8Season, int iSeed)
{
if (iSeed == -1)
{
srand(time(0));
}
else
{
srand(iSeed);
}
mpParameters = pParameters->Clone();
mpTrunk = new TStem(this);
mfMaxX = 0.0;
mfMaxY = 0.0;
mfMaxZ = 0.0;
miTotalStems = 0;
miTotalVertices = 0;
miTotalFaces = 0;
miTotalLeaves = 0;
miTotalLeavesFaces = 0;
miTotalCoordFrames = 0;
mu8Season = u8Season;
mfScale = mpParameters->mfScale + GetRandomValue(mpParameters->mfScaleV);
mfTrunkLength = (mpParameters->mafNLength[0] + GetRandomValue(mpParameters->mafNLengthV[0])) * mfScale;
mfTrunkRadius = mfTrunkLength * mpParameters->mfRatio * mpParameters->mfScale0;
mpTrunk->CreateStructure(NULL, mfTrunkLength, 0, 0);
}
//---------------------------------------------------------------------------
Tree::~Tree()
{
delete mpParameters;
delete mpTrunk;
}
//---------------------------------------------------------------------------
void Tree::Grow(void)
{
// Create trunk
TSectionFrame treeFrame(Quaternion::IDENTITY, Vector3(0,0,0), Vector3(0,0,0));
mpTrunk->Grow(treeFrame, mfTrunkRadius, 0);
}
//---------------------------------------------------------------------------
Real Tree::GetRandomValue(const Real fUpperBound)
{
int iSign = 1;
int iPrecision = 1000;
if (fUpperBound == 0)
{
return 0.0;
}
else
{
if (rand()%2 == 1)
iSign = -1;
return iSign*(rand()%iPrecision) * fUpperBound / iPrecision;
}
}
//---------------------------------------------------------------------------
Ogre::MeshPtr Tree::CreateMesh(const String &name)
{
//HACK: implement ManualResourceLoader
Ogre::MeshPtr pMesh = MeshManager::getSingleton().createManual(name,"trees");
SubMesh *pStemsSub, *pLeavesSub, *pCoordFrameSub;
// Set up vertex data
// Use a single shared buffer
pMesh->sharedVertexData = new VertexData();
VertexData* vertexData = pMesh->sharedVertexData;
// Set up Vertex Declaration
VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
size_t currOffset = 0;
// We always need positions
vertexDecl->addElement(POSITION_BINDING, currOffset, VET_FLOAT3, VES_POSITION);
currOffset += VertexElement::getTypeSize(VET_FLOAT3);
// normals
vertexDecl->addElement(POSITION_BINDING, currOffset, VET_FLOAT3, VES_NORMAL);
currOffset += VertexElement::getTypeSize(VET_FLOAT3);
// 2D texture coords
vertexDecl->addElement(POSITION_BINDING, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
currOffset += VertexElement::getTypeSize(VET_FLOAT2);
// vertex color
vertexDecl->addElement(COLOUR_BINDING, currOffset, VET_COLOUR, VES_DIFFUSE);
currOffset += VertexElement::getTypeSize(VET_COLOUR);
vertexData->vertexCount = miTotalVertices;
// Allocate vertex buffer
HardwareVertexBufferSharedPtr vbuf =
HardwareBufferManager::getSingleton().
createVertexBuffer(vertexDecl->getVertexSize(POSITION_BINDING), vertexData->vertexCount,
HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
// Set up the binding (one source only)
VertexBufferBinding* binding = vertexData->vertexBufferBinding;
binding->setBinding(POSITION_BINDING, vbuf);
// Generate vertex data recurcively
// Lock the whole buffer
Real* pVertexArray = static_cast<Real*>( vbuf->lock(HardwareBuffer::HBL_DISCARD) );
HardwareVertexBufferSharedPtr vcolbuf =
HardwareBufferManager::getSingleton().
createVertexBuffer(vertexDecl->getVertexSize(COLOUR_BINDING), vertexData->vertexCount,
HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
// bind position and diffuses
binding->setBinding(COLOUR_BINDING, vcolbuf);
RGBA* pVertexColorArray = static_cast<RGBA*>( vcolbuf->lock(HardwareBuffer::HBL_DISCARD) );
mpTrunk->AddMeshVertices(&pVertexArray, &pVertexColorArray);
if (miTotalLeaves > 0)
mpTrunk->AddLeavesVertices(&pVertexArray, &pVertexColorArray, 0);
if (this->mpParameters->mTreeType == TParameters::Simple)
mpTrunk->AddCoordFrameVertices(&pVertexArray, &pVertexColorArray);
// Unlock
vbuf->unlock();
vcolbuf->unlock();
// Generate face list for the trunk and the stems
pStemsSub = pMesh->createSubMesh();
pStemsSub->useSharedVertices = true;
pStemsSub->indexData->indexCount = 3 * miTotalFaces;
pStemsSub->indexData->indexBuffer = HardwareBufferManager::getSingleton().
createIndexBuffer( HardwareIndexBuffer::IT_32BIT /*HardwareIndexBuffer::IT_16BIT */ ,
pStemsSub->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
// int v1, v2, v3;
HardwareIndexBufferSharedPtr ibuf = pStemsSub->indexData->indexBuffer;
// Lock the whole buffer
// unsigned short* pFaceIndexes = static_cast<unsigned short*> ( ibuf->lock(HardwareBuffer::HBL_DISCARD) );
unsigned long* pFaceIndexes = static_cast<unsigned long*> ( ibuf->lock(HardwareBuffer::HBL_DISCARD) );
unsigned long u32VertexIndexOffset = 0;
mpTrunk->AddMeshFaces(&pFaceIndexes, &u32VertexIndexOffset);
// Unlock
ibuf->unlock();
// Generate face list for the leaves
if (miTotalLeaves > 0)
{
pLeavesSub = pMesh->createSubMesh();
pLeavesSub->useSharedVertices = true;
pLeavesSub->indexData->indexCount = 3 * miTotalLeavesFaces;
pLeavesSub->indexData->indexBuffer = HardwareBufferManager::getSingleton().
createIndexBuffer(HardwareIndexBuffer::IT_32BIT /*HardwareIndexBuffer::IT_16BIT*/,
pLeavesSub->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
// int v1, v2, v3;
ibuf = pLeavesSub->indexData->indexBuffer;
// Lock the whole buffer
// pFaceIndexes = static_cast<unsigned short*>( ibuf->lock(HardwareBuffer::HBL_DISCARD) );
pFaceIndexes = static_cast<unsigned long*>( ibuf->lock(HardwareBuffer::HBL_DISCARD) );
mpTrunk->AddLeavesMeshFaces(&pFaceIndexes, &u32VertexIndexOffset);
// Unlock
ibuf->unlock();
}
// Generate face list for the coordinate frame display
if (this->mpParameters->mTreeType == TParameters::Simple)
{
pCoordFrameSub = pMesh->createSubMesh();
pCoordFrameSub->useSharedVertices = true;
pCoordFrameSub->indexData->indexCount = 3 * 9 * miTotalCoordFrames; // 9 faces per coord frames
pCoordFrameSub->indexData->indexBuffer = HardwareBufferManager::getSingleton().
createIndexBuffer(HardwareIndexBuffer::IT_32BIT /*HardwareIndexBuffer::IT_16BIT*/,
pCoordFrameSub->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
ibuf = pCoordFrameSub->indexData->indexBuffer;
// Lock the whole buffer
pFaceIndexes = static_cast<unsigned long*>( ibuf->lock(HardwareBuffer::HBL_DISCARD) );
mpTrunk->AddCoordFrameMeshFaces(&pFaceIndexes, &u32VertexIndexOffset);
// Unlock
ibuf->unlock();
}
// TODO: Improve AAB + SphereRadius !!!!!!!!!!!
Vector3 vb1, vb2;
vb1 = Vector3(-mfMaxX, 0, -mfMaxZ) ;
vb2 = Vector3(mfMaxX, mfMaxY, mfMaxZ) ;
pMesh->_setBounds(AxisAlignedBox(vb1, vb2));
pMesh->_setBoundingSphereRadius(Math::Sqrt((vb2-vb1).Vector3::dotProduct(vb2-vb1))/2.0);
return pMesh;
}
//---------------------------------------------------------------------------
} // namespace