You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1091 lines
38 KiB
C++
1091 lines
38 KiB
C++
/*
|
|
* =============================================================================================
|
|
*
|
|
* Filename: BtOgre.cpp
|
|
*
|
|
* Description: BtOgre implementation.
|
|
*
|
|
* Version: 1.0
|
|
* Created: 27/12/2008 01:47:56 PM
|
|
*
|
|
* Author: Nikhilesh (nikki)
|
|
*
|
|
* =============================================================================================
|
|
*/
|
|
|
|
#include "BtOgrePG.h"
|
|
#include "BtOgreGP.h"
|
|
#include "BtOgreExtras.h"
|
|
|
|
using namespace Ogre;
|
|
|
|
namespace BtOgre {
|
|
|
|
/*
|
|
* =============================================================================================
|
|
* BtOgre::VertexIndexToShape
|
|
* =============================================================================================
|
|
*/
|
|
|
|
void VertexIndexToShape::addStaticVertexData(const VertexData *vertex_data)
|
|
{
|
|
if (!vertex_data)
|
|
return;
|
|
|
|
const VertexData *data = vertex_data;
|
|
|
|
const unsigned int prev_size = mVertexCount;
|
|
mVertexCount += (unsigned int)data->vertexCount;
|
|
|
|
Ogre::Vector3* tmp_vert = new Ogre::Vector3[mVertexCount];
|
|
if (mVertexBuffer)
|
|
{
|
|
memcpy(tmp_vert, mVertexBuffer, sizeof(Vector3) * prev_size);
|
|
delete[] mVertexBuffer;
|
|
}
|
|
mVertexBuffer = tmp_vert;
|
|
|
|
// Get the positional buffer element
|
|
{
|
|
const Ogre::VertexElement* posElem = data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
|
|
Ogre::HardwareVertexBufferSharedPtr vbuf = data->vertexBufferBinding->getBuffer(posElem->getSource());
|
|
const unsigned int vSize = (unsigned int)vbuf->getVertexSize();
|
|
|
|
unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
|
|
float* pReal;
|
|
Ogre::Vector3 * curVertices = &mVertexBuffer[prev_size];
|
|
const unsigned int vertexCount = (unsigned int)data->vertexCount;
|
|
for(unsigned int j = 0; j < vertexCount; ++j)
|
|
{
|
|
posElem->baseVertexPointerToElement(vertex, &pReal);
|
|
vertex += vSize;
|
|
|
|
curVertices->x = (*pReal++);
|
|
curVertices->y = (*pReal++);
|
|
curVertices->z = (*pReal++);
|
|
|
|
*curVertices = mTransform * (*curVertices);
|
|
|
|
curVertices++;
|
|
}
|
|
vbuf->unlock();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void VertexIndexToShape::addAnimatedVertexData(const Ogre::VertexData *vertex_data,
|
|
const Ogre::VertexData *blend_data,
|
|
const Ogre::Mesh::IndexMap *indexMap)
|
|
{
|
|
// Get the bone index element
|
|
assert(vertex_data);
|
|
|
|
const VertexData *data = blend_data;
|
|
const unsigned int prev_size = mVertexCount;
|
|
mVertexCount += (unsigned int)data->vertexCount;
|
|
Ogre::Vector3* tmp_vert = new Ogre::Vector3[mVertexCount];
|
|
if (mVertexBuffer)
|
|
{
|
|
memcpy(tmp_vert, mVertexBuffer, sizeof(Vector3) * prev_size);
|
|
delete[] mVertexBuffer;
|
|
}
|
|
mVertexBuffer = tmp_vert;
|
|
|
|
// Get the positional buffer element
|
|
{
|
|
const Ogre::VertexElement* posElem = data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
|
|
assert (posElem);
|
|
Ogre::HardwareVertexBufferSharedPtr vbuf = data->vertexBufferBinding->getBuffer(posElem->getSource());
|
|
const unsigned int vSize = (unsigned int)vbuf->getVertexSize();
|
|
|
|
unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
|
|
float* pReal;
|
|
Ogre::Vector3 * curVertices = &mVertexBuffer[prev_size];
|
|
const unsigned int vertexCount = (unsigned int)data->vertexCount;
|
|
for(unsigned int j = 0; j < vertexCount; ++j)
|
|
{
|
|
posElem->baseVertexPointerToElement(vertex, &pReal);
|
|
vertex += vSize;
|
|
|
|
curVertices->x = (*pReal++);
|
|
curVertices->y = (*pReal++);
|
|
curVertices->z = (*pReal++);
|
|
|
|
*curVertices = mTransform * (*curVertices);
|
|
|
|
curVertices++;
|
|
}
|
|
vbuf->unlock();
|
|
}
|
|
|
|
{
|
|
const Ogre::VertexElement* bneElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_BLEND_INDICES);
|
|
assert (bneElem);
|
|
|
|
Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(bneElem->getSource());
|
|
const unsigned int vSize = (unsigned int)vbuf->getVertexSize();
|
|
unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
|
|
|
|
unsigned char* pBone;
|
|
|
|
if (!mBoneIndex)
|
|
mBoneIndex = new BoneIndex();
|
|
BoneIndex::iterator i;
|
|
|
|
Ogre::Vector3 * curVertices = &mVertexBuffer[prev_size];
|
|
|
|
const unsigned int vertexCount = (unsigned int)vertex_data->vertexCount;
|
|
for(unsigned int j = 0; j < vertexCount; ++j)
|
|
{
|
|
bneElem->baseVertexPointerToElement(vertex, &pBone);
|
|
vertex += vSize;
|
|
|
|
const unsigned char currBone = (indexMap) ? (*indexMap)[*pBone] : *pBone;
|
|
i = mBoneIndex->find (currBone);
|
|
Vector3Array* l = 0;
|
|
if (i == mBoneIndex->end())
|
|
{
|
|
l = new Vector3Array;
|
|
mBoneIndex->insert(BoneKeyIndex(currBone, l));
|
|
}
|
|
else
|
|
{
|
|
l = i->second;
|
|
}
|
|
|
|
l->push_back(*curVertices);
|
|
|
|
curVertices++;
|
|
}
|
|
vbuf->unlock();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void VertexIndexToShape::addIndexData(IndexData *data, const unsigned int offset)
|
|
{
|
|
const unsigned int prev_size = mIndexCount;
|
|
mIndexCount += (unsigned int)data->indexCount;
|
|
|
|
unsigned int* tmp_ind = new unsigned int[mIndexCount];
|
|
if (mIndexBuffer)
|
|
{
|
|
memcpy (tmp_ind, mIndexBuffer, sizeof(unsigned int) * prev_size);
|
|
delete[] mIndexBuffer;
|
|
}
|
|
mIndexBuffer = tmp_ind;
|
|
|
|
const unsigned int numTris = (unsigned int) data->indexCount / 3;
|
|
HardwareIndexBufferSharedPtr ibuf = data->indexBuffer;
|
|
const bool use32bitindexes = (ibuf->getType() == HardwareIndexBuffer::IT_32BIT);
|
|
unsigned int index_offset = prev_size;
|
|
|
|
if (use32bitindexes)
|
|
{
|
|
const unsigned int* pInt = static_cast<unsigned int*>(ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
|
|
for(unsigned int k = 0; k < numTris; ++k)
|
|
{
|
|
mIndexBuffer[index_offset ++] = offset + *pInt++;
|
|
mIndexBuffer[index_offset ++] = offset + *pInt++;
|
|
mIndexBuffer[index_offset ++] = offset + *pInt++;
|
|
}
|
|
ibuf->unlock();
|
|
}
|
|
else
|
|
{
|
|
const unsigned short* pShort = static_cast<unsigned short*>(ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
|
|
for(unsigned int k = 0; k < numTris; ++k)
|
|
{
|
|
mIndexBuffer[index_offset ++] = offset + static_cast<unsigned int> (*pShort++);
|
|
mIndexBuffer[index_offset ++] = offset + static_cast<unsigned int> (*pShort++);
|
|
mIndexBuffer[index_offset ++] = offset + static_cast<unsigned int> (*pShort++);
|
|
}
|
|
ibuf->unlock();
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
Real VertexIndexToShape::getRadius()
|
|
{
|
|
if (mBoundRadius == (-1))
|
|
{
|
|
getSize();
|
|
mBoundRadius = (std::max(mBounds.x,std::max(mBounds.y,mBounds.z)) * 0.5);
|
|
}
|
|
return mBoundRadius;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
Vector3 VertexIndexToShape::getSize()
|
|
{
|
|
const unsigned int vCount = getVertexCount();
|
|
if (mBounds == Ogre::Vector3(-1,-1,-1) && vCount > 0)
|
|
{
|
|
|
|
const Ogre::Vector3 * const v = getVertices();
|
|
|
|
Ogre::Vector3 vmin(v[0]);
|
|
Ogre::Vector3 vmax(v[0]);
|
|
|
|
for(unsigned int j = 1; j < vCount; j++)
|
|
{
|
|
vmin.x = std::min(vmin.x, v[j].x);
|
|
vmin.y = std::min(vmin.y, v[j].y);
|
|
vmin.z = std::min(vmin.z, v[j].z);
|
|
|
|
vmax.x = std::max(vmax.x, v[j].x);
|
|
vmax.y = std::max(vmax.y, v[j].y);
|
|
vmax.z = std::max(vmax.z, v[j].z);
|
|
}
|
|
|
|
mBounds.x = vmax.x - vmin.x;
|
|
mBounds.y = vmax.y - vmin.y;
|
|
mBounds.z = vmax.z - vmin.z;
|
|
}
|
|
|
|
return mBounds;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
const Ogre::Vector3* VertexIndexToShape::getVertices()
|
|
{
|
|
return mVertexBuffer;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
unsigned int VertexIndexToShape::getVertexCount()
|
|
{
|
|
return mVertexCount;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
const unsigned int* VertexIndexToShape::getIndices()
|
|
{
|
|
return mIndexBuffer;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
unsigned int VertexIndexToShape::getIndexCount()
|
|
{
|
|
return mIndexCount;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
btSphereShape* VertexIndexToShape::createSphere()
|
|
{
|
|
const Ogre::Real rad = getRadius();
|
|
assert((rad > 0.0) &&
|
|
("Sphere radius must be greater than zero"));
|
|
btSphereShape* shape = new btSphereShape(rad);
|
|
|
|
shape->setLocalScaling(Convert::toBullet(mScale));
|
|
|
|
return shape;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
btBoxShape* VertexIndexToShape::createBox()
|
|
{
|
|
const Ogre::Vector3 sz = getSize();
|
|
|
|
assert((sz.x > 0.0) && (sz.y > 0.0) && (sz.y > 0.0) &&
|
|
("Size of box must be greater than zero on all axes"));
|
|
|
|
btBoxShape* shape = new btBoxShape(Convert::toBullet(sz * 0.5));
|
|
|
|
shape->setLocalScaling(Convert::toBullet(mScale));
|
|
|
|
return shape;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
btCylinderShape* VertexIndexToShape::createCylinder()
|
|
{
|
|
const Ogre::Vector3 sz = getSize();
|
|
|
|
assert((sz.x > 0.0) && (sz.y > 0.0) && (sz.y > 0.0) &&
|
|
("Size of Cylinder must be greater than zero on all axes"));
|
|
|
|
btCylinderShape* shape = new btCylinderShapeX(Convert::toBullet(sz * 0.5));
|
|
|
|
shape->setLocalScaling(Convert::toBullet(mScale));
|
|
|
|
return shape;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
btConvexHullShape* VertexIndexToShape::createConvex()
|
|
{
|
|
assert(mVertexCount && (mIndexCount >= 6) &&
|
|
("Mesh must have some vertices and at least 6 indices (2 triangles)"));
|
|
|
|
return new btConvexHullShape((btScalar*) &mVertexBuffer[0].x, mVertexCount, sizeof(Vector3));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
btBvhTriangleMeshShape* VertexIndexToShape::createTrimesh()
|
|
{
|
|
assert(mVertexCount && (mIndexCount >= 6) &&
|
|
("Mesh must have some vertices and at least 6 indices (2 triangles)"));
|
|
|
|
unsigned int numFaces = mIndexCount / 3;
|
|
|
|
btTriangleMesh *trimesh = new btTriangleMesh();
|
|
unsigned int *indices = mIndexBuffer;
|
|
Vector3 *vertices = mVertexBuffer;
|
|
|
|
btVector3 vertexPos[3];
|
|
for (unsigned int n = 0; n < numFaces; ++n)
|
|
{
|
|
{
|
|
const Vector3 &vec = vertices[*indices];
|
|
vertexPos[0][0] = vec.x;
|
|
vertexPos[0][1] = vec.y;
|
|
vertexPos[0][2] = vec.z;
|
|
}
|
|
{
|
|
const Vector3 &vec = vertices[*(indices + 1)];
|
|
vertexPos[1][0] = vec.x;
|
|
vertexPos[1][1] = vec.y;
|
|
vertexPos[1][2] = vec.z;
|
|
}
|
|
{
|
|
const Vector3 &vec = vertices[*(indices + 2)];
|
|
vertexPos[2][0] = vec.x;
|
|
vertexPos[2][1] = vec.y;
|
|
vertexPos[2][2] = vec.z;
|
|
}
|
|
|
|
indices += 3;
|
|
|
|
trimesh->addTriangle(vertexPos[0], vertexPos[1], vertexPos[2]);
|
|
}
|
|
|
|
const bool useQuantizedAABB = true;
|
|
btBvhTriangleMeshShape *shape = new btBvhTriangleMeshShape(trimesh, useQuantizedAABB);
|
|
|
|
shape->setLocalScaling(Convert::toBullet(mScale));
|
|
|
|
return shape;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
VertexIndexToShape::~VertexIndexToShape()
|
|
{
|
|
delete[] mVertexBuffer;
|
|
delete[] mIndexBuffer;
|
|
|
|
if (mBoneIndex)
|
|
{
|
|
for(BoneIndex::iterator i = mBoneIndex->begin();
|
|
i != mBoneIndex->end();
|
|
++i)
|
|
{
|
|
delete i->second;
|
|
}
|
|
delete mBoneIndex;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
VertexIndexToShape::VertexIndexToShape(const Matrix4 &transform) :
|
|
mVertexBuffer (0),
|
|
mIndexBuffer (0),
|
|
mVertexCount (0),
|
|
mIndexCount (0),
|
|
mTransform (transform),
|
|
mBoundRadius (-1),
|
|
mBounds (Vector3(-1,-1,-1)),
|
|
mBoneIndex (0),
|
|
mScale(1)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* =============================================================================================
|
|
* BtOgre::StaticMeshToShapeConverter
|
|
* =============================================================================================
|
|
*/
|
|
|
|
StaticMeshToShapeConverter::StaticMeshToShapeConverter() :
|
|
VertexIndexToShape(),
|
|
mEntity (0),
|
|
mNode (0)
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
StaticMeshToShapeConverter::~StaticMeshToShapeConverter()
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
StaticMeshToShapeConverter::StaticMeshToShapeConverter(Entity *entity, const Matrix4 &transform) :
|
|
VertexIndexToShape(transform),
|
|
mEntity (0),
|
|
mNode (0)
|
|
{
|
|
addEntity(entity, transform);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
StaticMeshToShapeConverter::StaticMeshToShapeConverter(Renderable *rend, const Matrix4 &transform) :
|
|
VertexIndexToShape(transform),
|
|
mEntity (0),
|
|
mNode (0)
|
|
{
|
|
RenderOperation op;
|
|
rend->getRenderOperation(op);
|
|
VertexIndexToShape::addStaticVertexData(op.vertexData);
|
|
if(op.useIndexes)
|
|
VertexIndexToShape::addIndexData(op.indexData);
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void StaticMeshToShapeConverter::addEntity(Entity *entity,const Matrix4 &transform)
|
|
{
|
|
// Each entity added need to reset size and radius
|
|
// next time getRadius and getSize are asked, they're computed.
|
|
mBounds = Ogre::Vector3(-1,-1,-1);
|
|
mBoundRadius = -1;
|
|
|
|
mEntity = entity;
|
|
mNode = (SceneNode*)(mEntity->getParentNode());
|
|
mTransform = transform;
|
|
mScale = mNode->getScale();
|
|
|
|
if (mEntity->getMesh()->sharedVertexData)
|
|
{
|
|
VertexIndexToShape::addStaticVertexData (mEntity->getMesh()->sharedVertexData);
|
|
}
|
|
|
|
for (unsigned int i = 0;i < mEntity->getNumSubEntities();++i)
|
|
{
|
|
SubMesh *sub_mesh = mEntity->getSubEntity(i)->getSubMesh();
|
|
|
|
if (!sub_mesh->useSharedVertices)
|
|
{
|
|
VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount);
|
|
VertexIndexToShape::addStaticVertexData (sub_mesh->vertexData);
|
|
}
|
|
else
|
|
{
|
|
VertexIndexToShape::addIndexData (sub_mesh->indexData);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void StaticMeshToShapeConverter::addMesh(const MeshPtr &mesh, const Matrix4 &transform)
|
|
{
|
|
// Each entity added need to reset size and radius
|
|
// next time getRadius and getSize are asked, they're computed.
|
|
mBounds = Ogre::Vector3(-1,-1,-1);
|
|
mBoundRadius = -1;
|
|
|
|
//_entity = entity;
|
|
//_node = (SceneNode*)(_entity->getParentNode());
|
|
mTransform = transform;
|
|
|
|
if (mesh->hasSkeleton ())
|
|
Ogre::LogManager::getSingleton().logMessage("MeshToShapeConverter::addMesh : Mesh " + mesh->getName () + " as skeleton but added to trimesh non animated");
|
|
|
|
if (mesh->sharedVertexData)
|
|
{
|
|
VertexIndexToShape::addStaticVertexData (mesh->sharedVertexData);
|
|
}
|
|
|
|
for(unsigned int i = 0;i < mesh->getNumSubMeshes();++i)
|
|
{
|
|
SubMesh *sub_mesh = mesh->getSubMesh(i);
|
|
|
|
if (!sub_mesh->useSharedVertices)
|
|
{
|
|
VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount);
|
|
VertexIndexToShape::addStaticVertexData (sub_mesh->vertexData);
|
|
}
|
|
else
|
|
{
|
|
VertexIndexToShape::addIndexData (sub_mesh->indexData);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
* =============================================================================================
|
|
* BtOgre::AnimatedMeshToShapeConverter
|
|
* =============================================================================================
|
|
*/
|
|
|
|
AnimatedMeshToShapeConverter::AnimatedMeshToShapeConverter(Entity *entity,const Matrix4 &transform) :
|
|
VertexIndexToShape(transform),
|
|
mEntity (0),
|
|
mNode (0),
|
|
mTransformedVerticesTemp(0),
|
|
mTransformedVerticesTempSize(0)
|
|
{
|
|
addEntity(entity, transform);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
AnimatedMeshToShapeConverter::AnimatedMeshToShapeConverter() :
|
|
VertexIndexToShape(),
|
|
mEntity (0),
|
|
mNode (0),
|
|
mTransformedVerticesTemp(0),
|
|
mTransformedVerticesTempSize(0)
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
AnimatedMeshToShapeConverter::~AnimatedMeshToShapeConverter()
|
|
{
|
|
delete[] mTransformedVerticesTemp;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void AnimatedMeshToShapeConverter::addEntity(Entity *entity,const Matrix4 &transform)
|
|
{
|
|
// Each entity added need to reset size and radius
|
|
// next time getRadius and getSize are asked, they're computed.
|
|
mBounds = Ogre::Vector3(-1,-1,-1);
|
|
mBoundRadius = -1;
|
|
|
|
mEntity = entity;
|
|
mNode = (SceneNode*)(mEntity->getParentNode());
|
|
mTransform = transform;
|
|
|
|
assert (entity->getMesh()->hasSkeleton ());
|
|
|
|
mEntity->addSoftwareAnimationRequest(false);
|
|
mEntity->_updateAnimation();
|
|
|
|
if (mEntity->getMesh()->sharedVertexData)
|
|
{
|
|
VertexIndexToShape::addAnimatedVertexData (mEntity->getMesh()->sharedVertexData,
|
|
mEntity->_getSkelAnimVertexData(),
|
|
&mEntity->getMesh()->sharedBlendIndexToBoneIndexMap);
|
|
}
|
|
|
|
for (unsigned int i = 0;i < mEntity->getNumSubEntities();++i)
|
|
{
|
|
SubMesh *sub_mesh = mEntity->getSubEntity(i)->getSubMesh();
|
|
|
|
if (!sub_mesh->useSharedVertices)
|
|
{
|
|
VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount);
|
|
|
|
VertexIndexToShape::addAnimatedVertexData (sub_mesh->vertexData,
|
|
mEntity->getSubEntity(i)->_getSkelAnimVertexData(),
|
|
&sub_mesh->blendIndexToBoneIndexMap);
|
|
}
|
|
else
|
|
{
|
|
VertexIndexToShape::addIndexData (sub_mesh->indexData);
|
|
}
|
|
|
|
}
|
|
|
|
mEntity->removeSoftwareAnimationRequest(false);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void AnimatedMeshToShapeConverter::addMesh(const MeshPtr &mesh, const Matrix4 &transform)
|
|
{
|
|
// Each entity added need to reset size and radius
|
|
// next time getRadius and getSize are asked, they're computed.
|
|
mBounds = Ogre::Vector3(-1,-1,-1);
|
|
mBoundRadius = -1;
|
|
|
|
//_entity = entity;
|
|
//_node = (SceneNode*)(_entity->getParentNode());
|
|
mTransform = transform;
|
|
|
|
assert (mesh->hasSkeleton ());
|
|
|
|
if (mesh->sharedVertexData)
|
|
{
|
|
VertexIndexToShape::addAnimatedVertexData (mesh->sharedVertexData,
|
|
0,
|
|
&mesh->sharedBlendIndexToBoneIndexMap);
|
|
}
|
|
|
|
for(unsigned int i = 0;i < mesh->getNumSubMeshes();++i)
|
|
{
|
|
SubMesh *sub_mesh = mesh->getSubMesh(i);
|
|
|
|
if (!sub_mesh->useSharedVertices)
|
|
{
|
|
VertexIndexToShape::addIndexData(sub_mesh->indexData, mVertexCount);
|
|
|
|
VertexIndexToShape::addAnimatedVertexData (sub_mesh->vertexData,
|
|
0,
|
|
&sub_mesh->blendIndexToBoneIndexMap);
|
|
}
|
|
else
|
|
{
|
|
VertexIndexToShape::addIndexData (sub_mesh->indexData);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
bool AnimatedMeshToShapeConverter::getBoneVertices(unsigned char bone,
|
|
unsigned int &vertex_count,
|
|
Ogre::Vector3* &vertices,
|
|
const Vector3 &bonePosition)
|
|
{
|
|
BoneIndex::iterator i = mBoneIndex->find(bone);
|
|
|
|
if (i == mBoneIndex->end())
|
|
return false;
|
|
|
|
if (i->second->empty())
|
|
return false;
|
|
|
|
vertex_count = (unsigned int) i->second->size() + 1;
|
|
if (vertex_count > mTransformedVerticesTempSize)
|
|
{
|
|
if (mTransformedVerticesTemp)
|
|
delete[] mTransformedVerticesTemp;
|
|
|
|
mTransformedVerticesTemp = new Ogre::Vector3[vertex_count];
|
|
|
|
}
|
|
|
|
vertices = mTransformedVerticesTemp;
|
|
vertices[0] = bonePosition;
|
|
//mEntity->_getParentNodeFullTransform() *
|
|
//mEntity->getSkeleton()->getBone(bone)->_getDerivedPosition();
|
|
|
|
//mEntity->getSkeleton()->getBone(bone)->_getDerivedOrientation()
|
|
unsigned int currBoneVertex = 1;
|
|
Vector3Array::iterator j = i->second->begin();
|
|
while(j != i->second->end())
|
|
{
|
|
vertices[currBoneVertex] = (*j);
|
|
++j;
|
|
++currBoneVertex;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
btBoxShape* AnimatedMeshToShapeConverter::createAlignedBox(unsigned char bone,
|
|
const Vector3 &bonePosition,
|
|
const Quaternion &boneOrientation)
|
|
{
|
|
unsigned int vertex_count;
|
|
Vector3* vertices;
|
|
|
|
if (!getBoneVertices(bone, vertex_count, vertices, bonePosition))
|
|
return 0;
|
|
|
|
Vector3 min_vec(vertices[0]);
|
|
Vector3 max_vec(vertices[0]);
|
|
|
|
for(unsigned int j = 1; j < vertex_count ;j++)
|
|
{
|
|
min_vec.x = std::min(min_vec.x,vertices[j].x);
|
|
min_vec.y = std::min(min_vec.y,vertices[j].y);
|
|
min_vec.z = std::min(min_vec.z,vertices[j].z);
|
|
|
|
max_vec.x = std::max(max_vec.x,vertices[j].x);
|
|
max_vec.y = std::max(max_vec.y,vertices[j].y);
|
|
max_vec.z = std::max(max_vec.z,vertices[j].z);
|
|
}
|
|
const Ogre::Vector3 maxMinusMin(max_vec - min_vec);
|
|
btBoxShape* box = new btBoxShape(Convert::toBullet(maxMinusMin));
|
|
|
|
/*const Ogre::Vector3 pos
|
|
(min_vec.x + (maxMinusMin.x * 0.5),
|
|
min_vec.y + (maxMinusMin.y * 0.5),
|
|
min_vec.z + (maxMinusMin.z * 0.5));*/
|
|
|
|
//box->setPosition(pos);
|
|
|
|
return box;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
bool AnimatedMeshToShapeConverter::getOrientedBox(unsigned char bone,
|
|
const Vector3 &bonePosition,
|
|
const Quaternion &boneOrientation,
|
|
Vector3 &box_afExtent,
|
|
Vector3 *box_akAxis,
|
|
Vector3 &box_kCenter)
|
|
{
|
|
unsigned int vertex_count;
|
|
Vector3* vertices;
|
|
|
|
if (!getBoneVertices(bone, vertex_count, vertices, bonePosition))
|
|
return false;
|
|
|
|
box_kCenter = Vector3::ZERO;
|
|
|
|
{
|
|
for(unsigned int c = 0 ;c < vertex_count;c++)
|
|
{
|
|
box_kCenter += vertices[c];
|
|
}
|
|
const Ogre::Real invVertexCount = 1.0 / vertex_count;
|
|
box_kCenter *= invVertexCount;
|
|
}
|
|
Quaternion orient = boneOrientation;
|
|
orient.ToAxes(box_akAxis);
|
|
|
|
// Let C be the box center and let U0, U1, and U2 be the box axes. Each
|
|
// input point is of the form X = C + y0*U0 + y1*U1 + y2*U2. The
|
|
// following code computes min(y0), max(y0), min(y1), max(y1), min(y2),
|
|
// and max(y2). The box center is then adjusted to be
|
|
// C' = C + 0.5*(min(y0)+max(y0))*U0 + 0.5*(min(y1)+max(y1))*U1 +
|
|
// 0.5*(min(y2)+max(y2))*U2
|
|
|
|
Ogre::Vector3 kDiff (vertices[1] - box_kCenter);
|
|
Ogre::Real fY0Min = kDiff.dotProduct(box_akAxis[0]), fY0Max = fY0Min;
|
|
Ogre::Real fY1Min = kDiff.dotProduct(box_akAxis[1]), fY1Max = fY1Min;
|
|
Ogre::Real fY2Min = kDiff.dotProduct(box_akAxis[2]), fY2Max = fY2Min;
|
|
|
|
for (unsigned int i = 2; i < vertex_count; i++)
|
|
{
|
|
kDiff = vertices[i] - box_kCenter;
|
|
|
|
const Ogre::Real fY0 = kDiff.dotProduct(box_akAxis[0]);
|
|
if ( fY0 < fY0Min )
|
|
fY0Min = fY0;
|
|
else if ( fY0 > fY0Max )
|
|
fY0Max = fY0;
|
|
|
|
const Ogre::Real fY1 = kDiff.dotProduct(box_akAxis[1]);
|
|
if ( fY1 < fY1Min )
|
|
fY1Min = fY1;
|
|
else if ( fY1 > fY1Max )
|
|
fY1Max = fY1;
|
|
|
|
const Ogre::Real fY2 = kDiff.dotProduct(box_akAxis[2]);
|
|
if ( fY2 < fY2Min )
|
|
fY2Min = fY2;
|
|
else if ( fY2 > fY2Max )
|
|
fY2Max = fY2;
|
|
}
|
|
|
|
box_afExtent.x = ((Real)0.5)*(fY0Max - fY0Min);
|
|
box_afExtent.y = ((Real)0.5)*(fY1Max - fY1Min);
|
|
box_afExtent.z = ((Real)0.5)*(fY2Max - fY2Min);
|
|
|
|
box_kCenter += (0.5*(fY0Max+fY0Min))*box_akAxis[0] +
|
|
(0.5*(fY1Max+fY1Min))*box_akAxis[1] +
|
|
(0.5*(fY2Max+fY2Min))*box_akAxis[2];
|
|
|
|
box_afExtent *= 2.0;
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
btBoxShape *AnimatedMeshToShapeConverter::createOrientedBox(unsigned char bone,
|
|
const Vector3 &bonePosition,
|
|
const Quaternion &boneOrientation)
|
|
{
|
|
Ogre::Vector3 box_akAxis[3];
|
|
Ogre::Vector3 box_afExtent;
|
|
Ogre::Vector3 box_afCenter;
|
|
|
|
if (!getOrientedBox(bone, bonePosition, boneOrientation,
|
|
box_afExtent,
|
|
box_akAxis,
|
|
box_afCenter))
|
|
return 0;
|
|
|
|
btBoxShape *geom = new btBoxShape(Convert::toBullet(box_afExtent));
|
|
//geom->setOrientation(Quaternion(box_akAxis[0],box_akAxis[1],box_akAxis[2]));
|
|
//geom->setPosition(box_afCenter);
|
|
return geom;
|
|
}
|
|
|
|
/*
|
|
* =============================================================================================
|
|
* BtOgre::DynamicRenderable
|
|
* =============================================================================================
|
|
*/
|
|
|
|
DynamicRenderable::DynamicRenderable()
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
DynamicRenderable::~DynamicRenderable()
|
|
{
|
|
delete mRenderOp.vertexData;
|
|
delete mRenderOp.indexData;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void DynamicRenderable::initialize(RenderOperation::OperationType operationType,
|
|
bool useIndices)
|
|
{
|
|
// Initialize render operation
|
|
mRenderOp.operationType = operationType;
|
|
mRenderOp.useIndexes = useIndices;
|
|
mRenderOp.vertexData = new VertexData;
|
|
if (mRenderOp.useIndexes)
|
|
mRenderOp.indexData = new IndexData;
|
|
|
|
// Reset buffer capacities
|
|
mVertexBufferCapacity = 0;
|
|
mIndexBufferCapacity = 0;
|
|
|
|
// Create vertex declaration
|
|
createVertexDeclaration();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void DynamicRenderable::prepareHardwareBuffers(size_t vertexCount,
|
|
size_t indexCount)
|
|
{
|
|
// Prepare vertex buffer
|
|
size_t newVertCapacity = mVertexBufferCapacity;
|
|
if ((vertexCount > mVertexBufferCapacity) ||
|
|
(!mVertexBufferCapacity))
|
|
{
|
|
// vertexCount exceeds current capacity!
|
|
// It is necessary to reallocate the buffer.
|
|
|
|
// Check if this is the first call
|
|
if (!newVertCapacity)
|
|
newVertCapacity = 1;
|
|
|
|
// Make capacity the next power of two
|
|
while (newVertCapacity < vertexCount)
|
|
newVertCapacity <<= 1;
|
|
}
|
|
else if (vertexCount < mVertexBufferCapacity>>1) {
|
|
// Make capacity the previous power of two
|
|
while (vertexCount < newVertCapacity>>1)
|
|
newVertCapacity >>= 1;
|
|
}
|
|
if (newVertCapacity != mVertexBufferCapacity)
|
|
{
|
|
mVertexBufferCapacity = newVertCapacity;
|
|
// Create new vertex buffer
|
|
HardwareVertexBufferSharedPtr vbuf =
|
|
HardwareBufferManager::getSingleton().createVertexBuffer(
|
|
mRenderOp.vertexData->vertexDeclaration->getVertexSize(0),
|
|
mVertexBufferCapacity,
|
|
HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); // TODO: Custom HBU_?
|
|
|
|
// Bind buffer
|
|
mRenderOp.vertexData->vertexBufferBinding->setBinding(0, vbuf);
|
|
}
|
|
// Update vertex count in the render operation
|
|
mRenderOp.vertexData->vertexCount = vertexCount;
|
|
|
|
if (mRenderOp.useIndexes)
|
|
{
|
|
OgreAssert(indexCount <= std::numeric_limits<unsigned short>::max(), "indexCount exceeds 16 bit");
|
|
|
|
size_t newIndexCapacity = mIndexBufferCapacity;
|
|
// Prepare index buffer
|
|
if ((indexCount > newIndexCapacity) ||
|
|
(!newIndexCapacity))
|
|
{
|
|
// indexCount exceeds current capacity!
|
|
// It is necessary to reallocate the buffer.
|
|
|
|
// Check if this is the first call
|
|
if (!newIndexCapacity)
|
|
newIndexCapacity = 1;
|
|
|
|
// Make capacity the next power of two
|
|
while (newIndexCapacity < indexCount)
|
|
newIndexCapacity <<= 1;
|
|
|
|
}
|
|
else if (indexCount < newIndexCapacity>>1)
|
|
{
|
|
// Make capacity the previous power of two
|
|
while (indexCount < newIndexCapacity>>1)
|
|
newIndexCapacity >>= 1;
|
|
}
|
|
|
|
if (newIndexCapacity != mIndexBufferCapacity)
|
|
{
|
|
mIndexBufferCapacity = newIndexCapacity;
|
|
// Create new index buffer
|
|
mRenderOp.indexData->indexBuffer =
|
|
HardwareBufferManager::getSingleton().createIndexBuffer(
|
|
HardwareIndexBuffer::IT_16BIT,
|
|
mIndexBufferCapacity,
|
|
HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); // TODO: Custom HBU_?
|
|
}
|
|
|
|
// Update index count in the render operation
|
|
mRenderOp.indexData->indexCount = indexCount;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
Real DynamicRenderable::getBoundingRadius(void) const
|
|
{
|
|
return Math::Sqrt(std::max(mBox.getMaximum().squaredLength(), mBox.getMinimum().squaredLength()));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
Real DynamicRenderable::getSquaredViewDepth(const Camera* cam) const
|
|
{
|
|
Vector3 vMin, vMax, vMid, vDist;
|
|
vMin = mBox.getMinimum();
|
|
vMax = mBox.getMaximum();
|
|
vMid = ((vMax - vMin) * 0.5) + vMin;
|
|
vDist = cam->getDerivedPosition() - vMid;
|
|
|
|
return vDist.squaredLength();
|
|
}
|
|
|
|
/*
|
|
* =============================================================================================
|
|
* BtOgre::DynamicLines
|
|
* =============================================================================================
|
|
*/
|
|
|
|
enum {
|
|
POSITION_BINDING,
|
|
TEXCOORD_BINDING
|
|
};
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
DynamicLines::DynamicLines(OperationType opType)
|
|
{
|
|
initialize(opType,false);
|
|
setMaterial("BaseWhiteNoLighting");
|
|
mDirty = true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
DynamicLines::~DynamicLines()
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void DynamicLines::setOperationType(OperationType opType)
|
|
{
|
|
mRenderOp.operationType = opType;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
RenderOperation::OperationType DynamicLines::getOperationType() const
|
|
{
|
|
return mRenderOp.operationType;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void DynamicLines::addPoint(const Vector3 &p)
|
|
{
|
|
mPoints.push_back(p);
|
|
mDirty = true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void DynamicLines::addPoint(Real x, Real y, Real z)
|
|
{
|
|
mPoints.push_back(Vector3(x,y,z));
|
|
mDirty = true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
const Vector3& DynamicLines::getPoint(unsigned short index) const
|
|
{
|
|
assert(index < mPoints.size() && "Point index is out of bounds!!");
|
|
return mPoints[index];
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
unsigned short DynamicLines::getNumPoints(void) const
|
|
{
|
|
return (unsigned short)mPoints.size();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void DynamicLines::setPoint(unsigned short index, const Vector3 &value)
|
|
{
|
|
assert(index < mPoints.size() && "Point index is out of bounds!!");
|
|
|
|
mPoints[index] = value;
|
|
mDirty = true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void DynamicLines::clear()
|
|
{
|
|
mPoints.clear();
|
|
mDirty = true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void DynamicLines::update()
|
|
{
|
|
if (mDirty) fillHardwareBuffers();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void DynamicLines::createVertexDeclaration()
|
|
{
|
|
VertexDeclaration *decl = mRenderOp.vertexData->vertexDeclaration;
|
|
decl->addElement(POSITION_BINDING, 0, VET_FLOAT3, VES_POSITION);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
void DynamicLines::fillHardwareBuffers()
|
|
{
|
|
int size = mPoints.size();
|
|
|
|
prepareHardwareBuffers(size,0);
|
|
|
|
if (!size) {
|
|
mBox.setExtents(Vector3::ZERO,Vector3::ZERO);
|
|
mDirty=false;
|
|
return;
|
|
}
|
|
|
|
Vector3 vaabMin = mPoints[0];
|
|
Vector3 vaabMax = mPoints[0];
|
|
|
|
HardwareVertexBufferSharedPtr vbuf =
|
|
mRenderOp.vertexData->vertexBufferBinding->getBuffer(0);
|
|
|
|
Real *prPos = static_cast<Real*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
|
|
{
|
|
for(int i = 0; i < size; i++)
|
|
{
|
|
*prPos++ = mPoints[i].x;
|
|
*prPos++ = mPoints[i].y;
|
|
*prPos++ = mPoints[i].z;
|
|
|
|
if(mPoints[i].x < vaabMin.x)
|
|
vaabMin.x = mPoints[i].x;
|
|
if(mPoints[i].y < vaabMin.y)
|
|
vaabMin.y = mPoints[i].y;
|
|
if(mPoints[i].z < vaabMin.z)
|
|
vaabMin.z = mPoints[i].z;
|
|
|
|
if(mPoints[i].x > vaabMax.x)
|
|
vaabMax.x = mPoints[i].x;
|
|
if(mPoints[i].y > vaabMax.y)
|
|
vaabMax.y = mPoints[i].y;
|
|
if(mPoints[i].z > vaabMax.z)
|
|
vaabMax.z = mPoints[i].z;
|
|
}
|
|
}
|
|
vbuf->unlock();
|
|
|
|
mBox.setExtents(vaabMin, vaabMax);
|
|
|
|
mDirty = false;
|
|
}
|
|
}
|