⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ogremeshcollisionshape.cpp

📁 opcode是功能强大
💻 CPP
字号:
///////////////////////////////////////////////////////////////////////////////
///  @file OgreMeshCollisionShape.cpp
///  @brief <TODO: insert file description here>
///
///  @author The OgreOpcode Team @date 28-05-2005
///
///////////////////////////////////////////////////////////////////////////////
///
///  This file is part of OgreOpcode.
///
///  A lot of the code is based on the Nebula Opcode Collision module, see docs/Nebula_license.txt
///
///  OgreOpcode is free software; you can redistribute it and/or
///  modify it under the terms of the GNU Lesser General Public
///  License as published by the Free Software Foundation; either
///  version 2.1 of the License, or (at your option) any later version.
///
///  OgreOpcode is distributed in the hope that it will be useful,
///  but WITHOUT ANY WARRANTY; without even the implied warranty of
///  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
///  Lesser General Public License for more details.
///
///  You should have received a copy of the GNU Lesser General Public
///  License along with OgreOpcode; if not, write to the Free Software
///  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
///
///////////////////////////////////////////////////////////////////////////////
#include "OgreOpcodeExports.h"
#include "OgreMeshCollisionShape.h"
#include "OgreCollisionReporter.h"
#include "OgreCollisionManager.h"
#include "OgreOpcodeMath.h"
#include "OgreOpcodeUtils.h"

using namespace Ogre;
namespace OgreOpcode
{
	//------------------------------------------------------------------------
	MeshCollisionShape::MeshCollisionShape(const Ogre::String& name)
		: ICollisionShape(name),
		mDummyNode(0),
		mDummyCreated(false)
	{
	}

	//------------------------------------------------------------------------
	MeshCollisionShape::~MeshCollisionShape()
	{
		if (mEntity && mEntity->hasSkeleton())
		{
#ifdef BUILD_AGAINST_AZATHOTH
			mEntity->removeSoftwareSkinningRequest(false);
#else
			mEntity->removeSoftwareAnimationRequest(false);
#endif
		}
		delete[] mVertexBuf;
		delete[] mFaceBuf;
	}

	//------------------------------------------------------------------------
	///////////////////////////////////////////////////////////////////////////////
	/// Counts how many indices (faces) and vertices an entity contains.
	/// @param[in]  entity Entity to count its data.
	/// @param[out] index_count  Number of indices.
	/// @param[out] vertex_count Number of vertices.
	/// @author Yavin from the Ogre4J team
	///////////////////////////////////////////////////////////////////////////////
	void MeshCollisionShape::countIndicesAndVertices(Entity * entity, size_t & index_count, size_t & vertex_count)
	{
		Mesh * mesh = entity->getMesh().getPointer();

#ifdef BUILD_AGAINST_AZATHOTH
		bool hwSkinning = entity->isHardwareSkinningEnabled();
#else
		bool hwSkinning = entity->isHardwareAnimationEnabled();
#endif

		bool added_shared = false;
		index_count  = 0;
		vertex_count = 0;

		// Calculate how many vertices and indices we're going to need
		for ( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
		{
			SubMesh* submesh = mesh->getSubMesh( i );

			// We only need to add the shared vertices once
			if(submesh->useSharedVertices)
			{
				if( !added_shared )
				{
					vertex_count += mesh->sharedVertexData->vertexCount;
					added_shared = true;
				}
			}
			else
			{
				vertex_count += submesh->vertexData->vertexCount;
			}

			// Add the indices
			index_count += submesh->indexData->indexCount;
		}
	}


	//------------------------------------------------------------------------
	//////////////////////////////////////////////////////////////////////////
	/// Converts mesh vertex and face data into simple float arrays.
	/// If the buffer parameters are null then that data is not converted.
	/// @param[in]  entity              Entity to extract data from.
	/// @param[out] vertexBuf          Target vertex data array (can be null).
	/// @param[in]  size_t vertex_count Number of vertices.
	/// @param[out] faceData            Target face data array (can be null).
	/// @param[int] index_count         Number of indices.
	/// @author Yavin from the Ogre4J team
	//////////////////////////////////////////////////////////////////////////
	void MeshCollisionShape::convertMeshData(Entity * entity,
		float * vertexBuf, size_t vertex_count,
		size_t * faceBuf, size_t index_count)
	{
		//---------------------------------------------------------------------
		// CONVERT MESH DATA
		//---------------------------------------------------------------------
		MeshPtr mesh = entity->getMesh();
		bool added_shared = false;
		size_t current_offset = 0;
		size_t shared_offset = 0;
		size_t next_offset = 0;
		size_t index_offset = 0;
		int numOfSubs = 0;

		bool useSoftwareBlendingVertices = entity->hasSkeleton();

		if (useSoftwareBlendingVertices)
		{
			entity->_updateAnimation();
		}

		// Run through the submeshes again, adding the data into the arrays
		for ( size_t i = 0; i < mesh->getNumSubMeshes(); ++i)
		{
			SubMesh* submesh = mesh->getSubMesh(i);
			bool useSharedVertices = submesh->useSharedVertices;

			if (vertexBuf)
			{
				//----------------------------------------------------------------
				// GET VERTEXDATA
				//----------------------------------------------------------------
				const VertexData * vertex_data;
				if(useSoftwareBlendingVertices)
#ifdef BUILD_AGAINST_AZATHOTH
					vertex_data = useSharedVertices ? entity->_getSharedBlendedVertexData() : entity->getSubEntity(i)->_getBlendedVertexData();
#else
					vertex_data = useSharedVertices ? entity->_getSkelAnimVertexData() : entity->getSubEntity(i)->_getSkelAnimVertexData();
#endif
				else
					vertex_data = useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;

				if((!useSharedVertices)||(useSharedVertices && !added_shared))
				{
					if(useSharedVertices)
					{
						added_shared = true;
						shared_offset = current_offset;
					}

					const VertexElement* posElem =
						vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);

					HardwareVertexBufferSharedPtr vbuf =
						vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());

					unsigned char* vertex =
						static_cast<unsigned char*>(vbuf->lock(HardwareBuffer::HBL_READ_ONLY));

					// There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double
					//  as second argument. So make it float, to avoid trouble when Ogre::Real is
					//  comiled/typedefed as double:
					float* pReal;

#ifdef BUILD_AGAINST_AZATHOTH
					if (useSoftwareBlendingVertices)
					{
						// Blended bone data is computed in world space.
						// Opcode expects data in local coordinates.
						Matrix4 xform = entity->_getParentNodeFullTransform().inverse();

						for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
						{
							posElem->baseVertexPointerToElement(vertex, &pReal);
							Vector3 v = Vector3(pReal[0],pReal[1],pReal[2]);
							v = xform * v;
							size_t n = current_offset*3 + j*3;
							vertexBuf[n + 0] = v[0];
							vertexBuf[n + 1] = v[1];
							vertexBuf[n + 2] = v[2];
						}
					}
					else
					{
						for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
						{
							posElem->baseVertexPointerToElement(vertex, &pReal);
							size_t n = current_offset*3 + j*3;
							vertexBuf[n + 0] = pReal[0];
							vertexBuf[n + 1] = pReal[1];
							vertexBuf[n + 2] = pReal[2];
						}
					}
#else

					for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
					{
						posElem->baseVertexPointerToElement(vertex, &pReal);

						size_t n = current_offset*3 + j*3;

						vertexBuf[n + 0] = pReal[0];
						vertexBuf[n + 1] = pReal[1];
						vertexBuf[n + 2] = pReal[2];
					}
#endif 	

					vbuf->unlock();
					next_offset += vertex_data->vertexCount;
				}
			}

			if (faceBuf)
			{
				//----------------------------------------------------------------
				// GET INDEXDATA
				//----------------------------------------------------------------
				IndexData* index_data = submesh->indexData;
				size_t numTris = index_data->indexCount / 3;
				HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;

				bool use32bitindexes = (ibuf->getType() == HardwareIndexBuffer::IT_32BIT);

				uint32 *pLong = static_cast<uint32*>(ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
				uint16* pShort = reinterpret_cast<uint16*>(pLong);


				size_t offset = (submesh->useSharedVertices)? shared_offset : current_offset;

				if ( use32bitindexes )
				{
					for ( size_t k = 0; k < numTris*3; ++k)
					{
						faceBuf[index_offset++] = pLong[k] + static_cast<int>(offset);
					}
				}
				else
				{
					for ( size_t k = 0; k < numTris*3; ++k)
					{
						faceBuf[index_offset++] = static_cast<int>(pShort[k]) + static_cast<int>(offset);
					}
				}

				ibuf->unlock();
			}

			current_offset = next_offset;
		}
	}

	//------------------------------------------------------------------------
	/// load collide geometry from mesh, and build a collision tree
	/// @param meshName [in]  name of mesh to load
	/// @param orientation [in]  optional orientation
	/// @param position [in]  optional position
	/// @return bool boolean value indicating success or failure
	bool MeshCollisionShape::load(const Ogre::String& meshName, const Quaternion& orientation, const Vector3& position)
	{
		//MeshPtr mesh = MeshManager::getSingleton().load(meshName);
		//assert(mesh);
		assert(!mVertexBuf && !mFaceBuf);
		mEntity = CollisionManager::getSingletonPtr()->getSceneManager()->createEntity(mName, meshName);
		assert(mEntity);
		createDummyNode();
		mDummyNode->setOrientation(orientation);
		mDummyNode->setPosition(position);

		if (mEntity->hasSkeleton()) {
#ifdef BUILD_AGAINST_AZATHOTH
			mEntity->addSoftwareSkinningRequest(false);
#else
			mEntity->addSoftwareAnimationRequest(false);
#endif
		}

		mParentNode = mDummyNode;
		//mFullTransform = mEntity->getParentSceneNode()->_getFullTransform();
		mParentNode->getWorldTransforms(&mFullTransform);
		return rebuild();
	}

	//------------------------------------------------------------------------
	/// Reload the collision geometry from mesh, rebuild collision tree from scratch. 
	/// Potentially very slow. Only necessary if the mesh has drastically changed,
	/// like topology changing deformations, or a change in the number of tris.
	/// In most cases RefitToMesh() is sufficient, and much faster.
	/// Under usual circumstances there is no need to call this method.
	/// @return bool Whether the rebuild operation was successful or not
	bool MeshCollisionShape::rebuild()
	{
		assert(mEntity);

		// NOTE: Assuming presence or absence of skeleton hasn't changed!

		size_t vertex_count = 0;
		size_t index_count  = 0;
		countIndicesAndVertices(mEntity, index_count, vertex_count);

		// Re-Allocate space for the vertices and indices
		if (mVertexBuf && numVertices != vertex_count) {
			delete [] mVertexBuf;
			mVertexBuf = 0;
		}
		if (mFaceBuf && numFaces != index_count/3) {
			delete [] mFaceBuf;
			mFaceBuf = 0;
		}

		if (!mVertexBuf)
			mVertexBuf = new float[vertex_count * 3];
		if (!mFaceBuf)
			mFaceBuf = new size_t[index_count];

		convertMeshData(mEntity, mVertexBuf, vertex_count, mFaceBuf, index_count );

		numFaces = index_count / 3;
		numVertices = vertex_count;

		opcMeshAccess.SetNbTriangles(numFaces);
		opcMeshAccess.SetNbVertices(numVertices);
		opcMeshAccess.SetPointers((IceMaths::IndexedTriangle*)mFaceBuf, (IceMaths::Point*)mVertexBuf);
		//opcMeshAccess.SetStrides(sizeof(int) * 3, sizeof(float) * 3);

		return _rebuildFromCachedData();

	}

	//------------------------------------------------------------------------
	/// Retrieve current vertex data from mesh and refit collision tree.
	/// This is an O(n) operation in the number of vertices in the mesh.
	/// @return bool Whether the operation was successful or not.
	bool MeshCollisionShape::refit()
	{
		// bail if we don't need to refit
		if ( mShapeIsStatic )
			return true;

		assert(mEntity && mVertexBuf);

#ifdef _DEBUG
		size_t vertex_count = 0;
		size_t index_count  = 0;
		countIndicesAndVertices(mEntity, index_count, vertex_count);
		assert(numVertices == vertex_count);
#endif

		convertMeshData(mEntity, mVertexBuf, numVertices);

		return _refitToCachedData();
	}


	//------------------------------------------------------------------------
	/// Refits the collision tree to the currently cached vertex data.
	/// This is an O(n) operation in the number of vertices in the mesh.
	/// This is an advanced method.  It assumes that the user is manually 
	/// updating both the MeshCollisionShape's cached data and the actual mesh
	/// hardware buffers.  Mostly useful for implementing something like 
	/// deformable body physics.
	/// @return bool
	bool MeshCollisionShape::_refitToCachedData()
	{
		assert(mEntity && mVertexBuf);

		// rebuild tree
		if (!opcModel.Refit())
		{
			LogManager::getSingleton().logMessage(
				"OgreOpcode::MeshCollisionShape::_refitToCachedData(): OPCODE Quick refit not possible with the given tree type.");
			// Backup plan -- rebuild full tree
			opcMeshAccess.SetPointers((IceMaths::IndexedTriangle*)mFaceBuf, (IceMaths::Point*)mVertexBuf);
			Opcode::OPCODECREATE opcc;
			_prepareOpcodeCreateParams(opcc);
			opcModel.Build(opcc);
		}

		calculateSize();

		//computeIceABB();

		//createDummyNode();

		return true;
	}

	//------------------------------------------------------------------------
	/// <TODO: insert function description here>
	/// @return bool <TODO: insert return value description here>
	bool MeshCollisionShape::_rebuildFromCachedData()
	{
		assert(mEntity && mVertexBuf && mFaceBuf);

		Opcode::OPCODECREATE opcc;
		_prepareOpcodeCreateParams(opcc);
		opcModel.Build(opcc);

		calculateSize();

		//computeIceABB();

		//createDummyNode();

		return true;
	}
	//------------------------------------------------------------------------
	void MeshCollisionShape::createDummyNode()
	{
		if(!mDummyCreated)
		{
			mDummyNode = CollisionManager::getSingletonPtr()->getSceneManager()->getRootSceneNode()->createChildSceneNode(getName());
			mDummyNode->attachObject(mEntity);
			mDummyCreated = true;
		}
		
	}
}

//------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -