Jelajahi Sumber

Added PhysXMesh

BearishSun 10 tahun lalu
induk
melakukan
e06de36247

+ 3 - 0
BansheeCore/BansheeCore.vcxproj

@@ -326,6 +326,7 @@
     <ClInclude Include="Include\BsPhysics.h" />
     <ClInclude Include="Include\BsPhysicsMaterial.h" />
     <ClInclude Include="Include\BsPhysicsMaterialRTTI.h" />
+    <ClInclude Include="Include\BsPhysicsMesh.h" />
     <ClInclude Include="Include\BsPlaneCollider.h" />
     <ClInclude Include="Include\BsPrefab.h" />
     <ClInclude Include="Include\BsPrefabDiff.h" />
@@ -482,6 +483,7 @@
     <ClInclude Include="Include\Win32\BsWin32DropTarget.h" />
     <ClInclude Include="Include\Win32\BsWin32FolderMonitor.h" />
     <ClInclude Include="Include\Win32\BSWin32PlatformData.h" />
+    <ClInclude Include="Source\BsPhysicsMeshRTTI.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsBoxCollider.cpp" />
@@ -505,6 +507,7 @@
     <ClCompile Include="Source\BsPhysics.cpp" />
     <ClCompile Include="Source\BsPhysicsManager.cpp" />
     <ClCompile Include="Source\BsPhysicsMaterial.cpp" />
+    <ClCompile Include="Source\BsPhysicsMesh.cpp" />
     <ClCompile Include="Source\BsPlaneCollider.cpp" />
     <ClCompile Include="Source\BsPrefab.cpp" />
     <ClCompile Include="Source\BsPrefabDiff.cpp" />

+ 9 - 0
BansheeCore/BansheeCore.vcxproj.filters

@@ -665,6 +665,12 @@
     <ClInclude Include="Include\BsCCapsuleColliderRTTI.h">
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsPhysicsMesh.h">
+      <Filter>Header Files\Physics</Filter>
+    </ClInclude>
+    <ClInclude Include="Source\BsPhysicsMeshRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsCoreApplication.cpp">
@@ -1045,5 +1051,8 @@
     <ClCompile Include="Source\BsCCapsuleCollider.cpp">
       <Filter>Source Files\Components</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsPhysicsMesh.cpp">
+      <Filter>Source Files\Physics</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 7 - 0
BansheeCore/Include/BsCommonTypes.h

@@ -343,6 +343,13 @@ namespace BansheeEngine
 		Transparent = 0x1 /**< Signifies that the shader is rendering a transparent object. */
 	};
 
+	/** Valid types of a mesh used for physics. */
+	enum class PhysicsMeshType
+	{
+		Triangle, /** A regular triangle mesh. */
+		Convex /** Mesh representing a convex shape. */
+	};
+
 	/**	Texture addressing mode, per component. */
 	struct UVWAddressingMode
 	{

+ 5 - 1
BansheeCore/Include/BsCorePrerequisites.h

@@ -267,6 +267,7 @@ namespace BansheeEngine
 	class OSDropTarget;
 	class StringTable;
 	class PhysicsMaterial;
+	class PhysicsMesh;
 	// Scene
 	class SceneObject;
 	class Component;
@@ -352,6 +353,7 @@ namespace BansheeEngine
 	typedef std::shared_ptr<RendererMeshData> RendererMeshDataPtr;
 	typedef std::shared_ptr<RenderAPIFactory> RenderAPIFactoryPtr;
 	typedef std::shared_ptr<PhysicsMaterial> PhysicsMaterialPtr;
+	typedef std::shared_ptr<PhysicsMesh> PhysicsMeshPtr;
 }
 
 /************************************************************************/
@@ -427,7 +429,8 @@ namespace BansheeEngine
 		TID_CSphereCollider = 1095,
 		TID_CCapsuleCollider = 1096,
 		TID_CPlaneCollider = 1097,
-		TID_CRigidbody = 1098
+		TID_CRigidbody = 1098,
+		TID_PhysicsMesh = 1099
 	};
 }
 
@@ -453,6 +456,7 @@ namespace BansheeEngine
 	typedef ResourceHandle<Prefab> HPrefab;
 	typedef ResourceHandle<StringTable> HStringTable;
 	typedef ResourceHandle<PhysicsMaterial> HPhysicsMaterial;
+	typedef ResourceHandle<PhysicsMesh> HPhysicsMesh;
 
 	/** @} */
 }

+ 1 - 0
BansheeCore/Include/BsPhysics.h

@@ -18,6 +18,7 @@ namespace BansheeEngine
 		virtual void update() = 0;
 
 		virtual SPtr<PhysicsMaterial> createMaterial(float staticFriction, float dynamicFriction, float restitution) = 0;
+		virtual SPtr<PhysicsMesh> createMesh(const MeshDataPtr& meshData, PhysicsMeshType type) = 0;
 		virtual SPtr<Rigidbody> createRigidbody(const HSceneObject& linkedSO) = 0;
 
 		virtual SPtr<BoxCollider> createBoxCollider(const Vector3& extents, const Vector3& position, 

+ 38 - 0
BansheeCore/Include/BsPhysicsMesh.h

@@ -0,0 +1,38 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsResource.h"
+
+namespace BansheeEngine
+{
+	class BS_CORE_EXPORT PhysicsMesh : public Resource
+	{
+	public:
+		PhysicsMesh(const MeshDataPtr& meshData, PhysicsMeshType type);
+		virtual ~PhysicsMesh() { }
+
+		PhysicsMeshType getType() const { return mType; }
+		virtual MeshDataPtr getMeshData() const = 0;
+
+		static HPhysicsMesh create(const MeshDataPtr& meshData, PhysicsMeshType type = PhysicsMeshType::Convex);
+		static PhysicsMeshPtr _createPtr(const MeshDataPtr& meshData, PhysicsMeshType type);
+
+	protected:
+		/** @copydoc PhysicsMesh::initialize() */
+		void initialize() override;
+
+		PhysicsMeshType mType;
+
+		MeshDataPtr mInitMeshData; // Transient, only used during initalization
+
+		/************************************************************************/
+		/* 								SERIALIZATION                      		*/
+		/************************************************************************/
+	public:
+		friend class PhysicsMeshRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		RTTITypeBase* getRTTI() const override;
+	};
+}

+ 10 - 10
BansheeCore/Source/BsPhysicsMaterial.cpp

@@ -5,16 +5,6 @@
 
 namespace BansheeEngine
 {
-	RTTITypeBase* PhysicsMaterial::getRTTIStatic()
-	{
-		return PhysicsMaterialRTTI::instance();
-	}
-
-	RTTITypeBase* PhysicsMaterial::getRTTI() const
-	{
-		return getRTTIStatic();
-	}
-
 	HPhysicsMaterial PhysicsMaterial::create(float staticFriction, float dynamicFriction, float restitution)
 	{
 		PhysicsMaterialPtr newMaterial = _createPtr(staticFriction, dynamicFriction, restitution);
@@ -30,4 +20,14 @@ namespace BansheeEngine
 
 		return newMaterial;
 	}
+
+	RTTITypeBase* PhysicsMaterial::getRTTIStatic()
+	{
+		return PhysicsMaterialRTTI::instance();
+	}
+
+	RTTITypeBase* PhysicsMaterial::getRTTI() const
+	{
+		return getRTTIStatic();
+	}
 }

+ 44 - 0
BansheeCore/Source/BsPhysicsMesh.cpp

@@ -0,0 +1,44 @@
+#include "BsPhysicsMesh.h"
+#include "BsPhysicsMeshRTTI.h"
+#include "BsResources.h"
+#include "BsPhysics.h"
+
+namespace BansheeEngine
+{
+	PhysicsMesh::PhysicsMesh(const MeshDataPtr& meshData, PhysicsMeshType type)
+		:mInitMeshData(meshData), mType(type)
+	{ }
+
+	HPhysicsMesh PhysicsMesh::create(const MeshDataPtr& meshData, PhysicsMeshType type)
+	{
+		PhysicsMeshPtr newMesh = _createPtr(meshData, type);
+
+		return static_resource_cast<PhysicsMesh>(gResources()._createResourceHandle(newMesh));
+	}
+
+	PhysicsMeshPtr PhysicsMesh::_createPtr(const MeshDataPtr& meshData, PhysicsMeshType type)
+	{
+		PhysicsMeshPtr newMesh = gPhysics().createMesh(meshData, type);
+		newMesh->_setThisPtr(newMesh);
+		newMesh->initialize();
+
+		return newMesh;
+	}
+
+	void PhysicsMesh::initialize()
+	{
+		mInitMeshData = nullptr;
+
+		Resource::initialize();
+	}
+
+	RTTITypeBase* PhysicsMesh::getRTTIStatic()
+	{
+		return PhysicsMeshRTTI::instance();
+	}
+
+	RTTITypeBase* PhysicsMesh::getRTTI() const
+	{
+		return getRTTIStatic();
+	}
+}

+ 46 - 0
BansheeCore/Source/BsPhysicsMeshRTTI.h

@@ -0,0 +1,46 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsPhysicsMesh.h"
+
+namespace BansheeEngine
+{
+	/** @cond RTTI */
+	/** @addtogroup RTTI-Impl-Core
+	*  @{
+	*/
+
+	class BS_CORE_EXPORT PhysicsMeshRTTI : public RTTIType<PhysicsMesh, Resource, PhysicsMeshRTTI>
+	{
+	private:
+		BS_PLAIN_MEMBER(mType)
+
+	public:
+		PhysicsMeshRTTI()
+		{
+			BS_ADD_PLAIN_FIELD(mType, 0)
+		}
+
+		const String& getRTTIName() override
+		{
+			static String name = "PhysicsMesh";
+			return name;
+		}
+
+		UINT32 getRTTIId() override
+		{
+			return TID_PhysicsMesh;
+		}
+
+		std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			BS_EXCEPT(InternalErrorException, "Cannot instantiate an abstract class.");
+		}
+	};
+
+	/** @} */
+	/** @endcond */
+}

+ 3 - 0
BansheePhysX/BansheePhysX.vcxproj

@@ -250,6 +250,7 @@
     <ClCompile Include="Source\BsPhysXBoxCollider.cpp" />
     <ClCompile Include="Source\BsPhysXCapsuleCollider.cpp" />
     <ClCompile Include="Source\BsPhysXMaterial.cpp" />
+    <ClCompile Include="Source\BsPhysXMesh.cpp" />
     <ClCompile Include="Source\BsPhysXPlaneCollider.cpp" />
     <ClCompile Include="Source\BsPhysXPlugin.cpp" />
     <ClCompile Include="Source\BsPhysXRigidbody.cpp" />
@@ -261,6 +262,8 @@
     <ClInclude Include="Include\BsFPhysXCollider.h" />
     <ClInclude Include="Include\BsPhysXCapsuleCollider.h" />
     <ClInclude Include="Include\BsPhysXMaterial.h" />
+    <ClInclude Include="Include\BsPhysXMesh.h" />
+    <ClInclude Include="Include\BsPhysXMeshRTTI.h" />
     <ClInclude Include="Include\BsPhysXPlaneCollider.h" />
     <ClInclude Include="Include\BsPhysXPrerequisites.h" />
     <ClInclude Include="Include\BsPhysXRigidbody.h" />

+ 12 - 0
BansheePhysX/BansheePhysX.vcxproj.filters

@@ -9,6 +9,9 @@
       <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
       <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
     </Filter>
+    <Filter Include="Header Files\RTTI">
+      <UniqueIdentifier>{9f0be24d-5f52-4550-8ccf-beba570457fb}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsPhysXPlugin.cpp">
@@ -38,6 +41,9 @@
     <ClCompile Include="Source\BsPhysXCapsuleCollider.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsPhysXMesh.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\BsPhysXPrerequisites.h">
@@ -67,5 +73,11 @@
     <ClInclude Include="Include\BsPhysXCapsuleCollider.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsPhysXMesh.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsPhysXMeshRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>

+ 2 - 0
BansheePhysX/Include/BsPhysX.h

@@ -42,6 +42,7 @@ namespace BansheeEngine
 		void update() override;
 
 		SPtr<PhysicsMaterial> createMaterial(float staticFriction, float dynamicFriction, float restitution) override;
+		SPtr<PhysicsMesh> createMesh(const MeshDataPtr& meshData, PhysicsMeshType type) override;
 		SPtr<Rigidbody> createRigidbody(const HSceneObject& linkedSO) override;
 
 		SPtr<BoxCollider> createBoxCollider(const Vector3& extents, const Vector3& position,
@@ -57,6 +58,7 @@ namespace BansheeEngine
 		physx::PxMaterial* getDefaultMaterial() const { return mDefaultMaterial; }
 		physx::PxPhysics* getPhysX() const { return mPhysics; }
 		physx::PxScene* getScene() const { return mScene; }
+		physx::PxCooking* getCooking() const { return mCooking; }
 
 	private:
 		friend class PhysXEventCallback;

+ 42 - 0
BansheePhysX/Include/BsPhysXMesh.h

@@ -0,0 +1,42 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPhysXPrerequisites.h"
+#include "BsPhysicsMesh.h"
+#include "PxMaterial.h"
+
+namespace BansheeEngine
+{
+	class PhysXMesh : public PhysicsMesh
+	{
+	public:
+		PhysXMesh(const MeshDataPtr& meshData, PhysicsMeshType type);
+
+		MeshDataPtr getMeshData() const override;
+
+		physx::PxTriangleMesh* _getTriangle() const { assert(mType == PhysicsMeshType::Triangle); return mTriangleMesh; }
+		physx::PxConvexMesh* _getConvex() const { assert(mType == PhysicsMeshType::Convex); return mConvexMesh; }
+
+	private:
+		/** @copydoc PhysicsMesh::initialize() */
+		void initialize() override;
+
+		/** @copydoc PhysicsMesh::initialize() */
+		void destroy() override;
+
+		physx::PxTriangleMesh* mTriangleMesh = nullptr;
+		physx::PxConvexMesh* mConvexMesh = nullptr;
+
+		UINT8* mCookedData = nullptr;
+		UINT32 mCookedDataSize = 0;
+
+		/************************************************************************/
+		/* 								SERIALIZATION                      		*/
+		/************************************************************************/
+	public:
+		friend class PhysXMeshRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		RTTITypeBase* getRTTI() const override;
+	};
+}

+ 62 - 0
BansheePhysX/Include/BsPhysXMeshRTTI.h

@@ -0,0 +1,62 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPhysXPrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsPhysXMesh.h"
+
+namespace BansheeEngine
+{
+	class BS_PHYSX_EXPORT PhysXMeshRTTI : public RTTIType<PhysXMesh, PhysicsMesh, PhysXMeshRTTI>
+	{
+	private:
+		ManagedDataBlock getCookedData(PhysXMesh* obj)
+		{
+			ManagedDataBlock dataBlock((UINT8*)obj->mCookedData, obj->mCookedDataSize);
+			return dataBlock;
+		}
+
+		void setCookedData(PhysXMesh* obj, ManagedDataBlock val)
+		{
+			// Nothing to do here, the pointer we provided in allocateCookedData() already belongs to PhysXMesh
+			// so the data is already written
+		}
+
+		static UINT8* allocateCookedData(PhysXMesh* obj, UINT32 numBytes)
+		{
+			obj->mCookedData = (UINT8*)bs_alloc(numBytes);
+			obj->mCookedDataSize = numBytes;
+
+			return obj->mCookedData;
+		}
+	public:
+		PhysXMeshRTTI()
+		{
+			addDataBlockField("mCookedData", 0, 
+				&PhysXMeshRTTI::getCookedData, &PhysXMeshRTTI::setCookedData, 0, &PhysXMeshRTTI::allocateCookedData);
+		}
+
+		void onDeserializationEnded(IReflectable* obj) override
+		{
+			PhysXMesh* mesh = static_cast<PhysXMesh*>(obj);
+			mesh->initialize();
+		}
+
+		const String& getRTTIName() override
+		{
+			static String name = "PhysXMesh";
+			return name;
+		}
+
+		UINT32 getRTTIId() override
+		{
+			return TID_PhysXMesh;
+		}
+
+		SPtr<IReflectable> newRTTIObject() override
+		{
+			return PhysicsMesh::_createPtr(nullptr, PhysicsMeshType::Convex);
+		}
+	};
+}

+ 6 - 0
BansheePhysX/Include/BsPhysXPrerequisites.h

@@ -28,6 +28,12 @@ namespace BansheeEngine
 	class PhsyXMaterial;
 	class FPhysXCollider;
 
+	/**	Type IDs used by the RTTI system for the PhysX library. */
+	enum TypeID_BansheeEditor
+	{
+		TID_PhysXMesh = 100000,
+	};
+
 	inline const physx::PxVec3& toPxVector(const Vector3& input)
 	{
 		return *(physx::PxVec3*)&input;

+ 11 - 2
BansheePhysX/Source/BsPhysX.cpp

@@ -1,6 +1,7 @@
 #include "BsPhysX.h"
 #include "PxPhysicsAPI.h"
 #include "BsPhysXMaterial.h"
+#include "BsPhysXMesh.h"
 #include "BsPhysXRigidbody.h"
 #include "BsPhysXBoxCollider.h"
 #include "BsPhysXSphereCollider.h"
@@ -19,7 +20,7 @@ namespace BansheeEngine
 		float typicalLength = 1.0f;
 		float typicalSpeed = 9.81f;
 		Vector3 gravity = Vector3(0.0f, -9.81f, 0.0f);
-		bool initCooking = false;
+		bool initCooking = true; // TODO: Disable this for Game build
 		float timeStep = 1.0f / 60.0f;
 	};
 
@@ -292,7 +293,10 @@ namespace BansheeEngine
 
 		if (input.initCooking)
 		{
-			PxCookingParams cookingParams(scale); // TODO - Potentially allow more customization to set up cooking params
+			// Note: PhysX supports cooking for specific platforms to make the generated results better. Consider
+			// allowing the meshes to be re-cooked when target platform is changed. Right now we just use the default value.
+
+			PxCookingParams cookingParams(scale);
 			mCooking = PxCreateCooking(PX_PHYSICS_VERSION, *mFoundation, cookingParams);
 		}
 
@@ -459,6 +463,11 @@ namespace BansheeEngine
 		return bs_shared_ptr_new<PhysXMaterial>(mPhysics, staticFriction, dynamicFriction, restitution);
 	}
 
+	SPtr<PhysicsMesh> PhysX::createMesh(const MeshDataPtr& meshData, PhysicsMeshType type)
+	{
+		return bs_shared_ptr_new<PhysXMesh>(meshData, type);
+	}
+
 	SPtr<Rigidbody> PhysX::createRigidbody(const HSceneObject& linkedSO)
 	{
 		return bs_shared_ptr_new<PhysXRigidbody>(mPhysics, mScene, linkedSO);

+ 375 - 0
BansheePhysX/Source/BsPhysXMesh.cpp

@@ -0,0 +1,375 @@
+#include "BsPhysXMesh.h"
+#include "BsPhysXMeshRTTI.h"
+#include "BsMeshData.h"
+#include "BsVertexDataDesc.h"
+#include "BsPhysX.h"
+#include "BsAABox.h"
+#include "foundation\PxAllocatorCallback.h"
+#include "geometry\PxTriangleMesh.h"
+#include "geometry\PxConvexMesh.h"
+#include "cooking\PxConvexMeshDesc.h"
+#include "extensions\PxDefaultStreams.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	/**
+	 * Attempts to cook a convex mesh from the provided mesh data. Assumes the mesh data is not null and contains vertex
+	 * positions as well as face indices. If the method returns true the resulting convex mesh will be output in the @p
+	 * data buffer, and its size in @p size. The data buffer will be allocated used the generic allocator and is up to the
+	 * caller to free it.
+	 */
+	bool cookConvex(PxCooking* cooking, const MeshDataPtr& meshData, UINT8** data, UINT32& size)
+	{
+		VertexDataDescPtr vertexDesc = meshData->getVertexDesc();
+
+		// Generate hull polygons
+		PxSimpleTriangleMesh meshDesc;
+		meshDesc.points.count = meshData->getNumVertices();
+		meshDesc.points.stride = vertexDesc->getVertexStride();
+		meshDesc.points.data = meshData->getElementData(VES_POSITION);
+
+		meshDesc.triangles.count = meshData->getNumIndices() / 3;
+		meshDesc.triangles.stride = 3 * sizeof(PxU32);
+
+		IndexType indexType = meshData->getIndexType();
+		if (indexType == IT_32BIT)
+		{
+			meshDesc.triangles.stride = 4;
+			meshDesc.triangles.data = meshData->getIndices32();
+		}
+		else
+		{
+			meshDesc.triangles.stride = 2;
+			meshDesc.triangles.data = meshData->getIndices16();
+			meshDesc.flags |= PxMeshFlag::e16_BIT_INDICES;
+		}
+
+		PxAllocatorCallback& allocator = PxGetFoundation().getAllocatorCallback();
+
+		PxU32 numVertices = 0;
+		PxU32 numIndices = 0;
+		PxU32 numPolygons = 0;
+		PxVec3* vertices = nullptr;
+		PxU32* indices = nullptr;
+		PxHullPolygon* polygons = nullptr;
+
+		bool gotPolygons = cooking->computeHullPolygons(meshDesc, allocator,
+			numVertices, vertices, numIndices, indices, numPolygons, polygons);
+
+		// If we have polygons try to create hull directly from them
+		if(gotPolygons)
+		{
+			PxConvexMeshDesc convexPolyDesc;
+			convexPolyDesc.points.count = numVertices;
+			convexPolyDesc.points.stride = sizeof(PxVec3);
+			convexPolyDesc.points.data = vertices;
+
+			convexPolyDesc.indices.count = numIndices;
+			convexPolyDesc.indices.stride = sizeof(PxU32);
+			convexPolyDesc.indices.data = indices;
+
+			convexPolyDesc.polygons.count = numPolygons;
+			convexPolyDesc.polygons.stride = sizeof(PxHullPolygon);
+			convexPolyDesc.polygons.data = polygons;
+
+			PxDefaultMemoryOutputStream output;
+			if (cooking->cookConvexMesh(convexPolyDesc, output))
+			{
+				size = output.getSize();
+				*data = (UINT8*)bs_alloc(size);
+
+				memcpy(*data, output.getData(), size);
+
+				allocator.deallocate(vertices);
+				allocator.deallocate(indices);
+				allocator.deallocate(polygons);
+
+				return true;
+			}
+
+			allocator.deallocate(vertices);
+			allocator.deallocate(indices);
+			allocator.deallocate(polygons);
+		}
+
+		// Try to create hull from points
+		PxConvexMeshDesc convexDesc;
+		convexDesc.points.count = meshData->getNumVertices();
+		convexDesc.points.stride = vertexDesc->getVertexStride();
+		convexDesc.points.data = meshData->getElementData(VES_POSITION);
+		convexDesc.flags |= PxConvexFlag::eCOMPUTE_CONVEX;
+
+		PxDefaultMemoryOutputStream output;
+		if (cooking->cookConvexMesh(convexDesc, output))
+		{
+			size = output.getSize();
+			*data = (UINT8*)bs_alloc(size);
+
+			memcpy(*data, output.getData(), size);
+			return true;
+		}
+
+		// Try inflating the convex mesh
+		convexDesc.flags |= PxConvexFlag::eINFLATE_CONVEX;
+		if (cooking->cookConvexMesh(convexDesc, output))
+		{
+			size = output.getSize();
+			*data = (UINT8*)bs_alloc(size);
+
+			memcpy(*data, output.getData(), size);
+			return true;
+		}
+
+		// Nothing works, just compute an AABB
+		AABox box;
+
+		auto vertIter = meshData->getVec3DataIter(VES_POSITION);
+		do
+		{
+			box.merge(vertIter.getValue());
+		}
+		while (vertIter.moveNext());
+
+		Vector3 aabbVerts[8];
+		aabbVerts[0] = box.getCorner(AABox::FAR_LEFT_BOTTOM);
+		aabbVerts[1] = box.getCorner(AABox::FAR_RIGHT_BOTTOM);
+		aabbVerts[2] = box.getCorner(AABox::FAR_RIGHT_TOP);
+		aabbVerts[3] = box.getCorner(AABox::FAR_LEFT_TOP);
+
+		aabbVerts[4] = box.getCorner(AABox::NEAR_LEFT_BOTTOM);
+		aabbVerts[5] = box.getCorner(AABox::NEAR_RIGHT_BOTTOM);
+		aabbVerts[6] = box.getCorner(AABox::NEAR_RIGHT_TOP);
+		aabbVerts[7] = box.getCorner(AABox::NEAR_LEFT_TOP);
+
+		convexDesc.points.count = 8;
+		convexDesc.points.stride = sizeof(Vector3);
+		convexDesc.points.data = &aabbVerts[0];
+		convexDesc.flags &= ~PxConvexFlag::eINFLATE_CONVEX;
+
+		if (cooking->cookConvexMesh(convexDesc, output))
+		{
+			size = output.getSize();
+			*data = (UINT8*)bs_alloc(size);
+
+			memcpy(*data, output.getData(), size);
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Attempts to cook a triangle or convex mesh from the provided mesh data. Will log a warning and return false if it is
+	 * unable to cook the mesh. If the method returns true the resulting convex mesh will be output in the @p data buffer,
+	 * and its size in @p size. The data buffer will be allocated used the generic allocator and is up to the caller to 
+	 * free it.
+	 */
+	bool cookMesh(const MeshDataPtr& meshData, PhysicsMeshType type, UINT8** data, UINT32& size)
+	{
+		if (meshData == nullptr)
+			return false;
+
+		PxCooking* cooking = gPhysX().getCooking();
+		if (cooking == nullptr)
+		{
+			LOGWRN("Attempting to cook a physics mesh but cooking is not enabled globally.");
+			return false;
+		}
+
+		VertexDataDescPtr vertexDesc = meshData->getVertexDesc();
+		if (!vertexDesc->hasElement(VES_POSITION))
+		{
+			LOGWRN("Provided PhysicsMesh mesh data has no vertex positions.");
+			return false;
+		}
+
+		if (type == PhysicsMeshType::Convex)
+		{
+			if(!cookConvex(cooking, meshData, data, size))
+			{
+				LOGWRN("Failed cooking a convex mesh. Perpahs it is too complex? Maximum number of convex vertices is 256.");
+				return false;
+			}
+		}
+		else
+		{
+			PxTriangleMeshDesc meshDesc;
+			meshDesc.points.count = meshData->getNumVertices();
+			meshDesc.points.stride = vertexDesc->getVertexStride();
+			meshDesc.points.data = meshData->getElementData(VES_POSITION);
+
+			meshDesc.triangles.count = meshData->getNumIndices() / 3;
+			meshDesc.triangles.stride = 3 * sizeof(PxU32);
+
+			IndexType indexType = meshData->getIndexType();
+			if (indexType == IT_32BIT)
+			{
+				meshDesc.triangles.stride = 4;
+				meshDesc.triangles.data = meshData->getIndices32();
+			}
+			else
+			{
+				meshDesc.triangles.stride = 2;
+				meshDesc.triangles.data = meshData->getIndices16();
+				meshDesc.flags |= PxMeshFlag::e16_BIT_INDICES;
+			}
+
+			PxDefaultMemoryOutputStream output;
+			if (!cooking->cookTriangleMesh(meshDesc, output))
+				return false;
+
+			size = output.getSize();
+			*data = (UINT8*)bs_alloc(size);
+
+			memcpy(*data, output.getData(), size);
+		}
+
+		return true;
+	}
+
+	PhysXMesh::PhysXMesh(const MeshDataPtr& meshData, PhysicsMeshType type)
+		:PhysicsMesh(meshData, type)
+	{ }
+
+	void PhysXMesh::initialize()
+	{
+		// Perform cooking if needed
+		if (mInitMeshData != nullptr)
+			cookMesh(mInitMeshData, mType, &mCookedData, mCookedDataSize);
+
+		if (mCookedData != nullptr && mCookedDataSize > 0)
+		{
+			PxPhysics* physx = gPhysX().getPhysX();
+
+			PxDefaultMemoryInputData input(mCookedData, mCookedDataSize);
+			if (mType == PhysicsMeshType::Convex)
+				mConvexMesh = physx->createConvexMesh(input);
+			else
+				mTriangleMesh = physx->createTriangleMesh(input);
+		}
+
+		PhysicsMesh::initialize();
+	}
+
+	void PhysXMesh::destroy()
+	{
+		if(mCookedData != nullptr)
+		{
+			bs_free(mCookedData);
+
+			mCookedData = nullptr;
+			mCookedDataSize = 0;
+		}
+
+		if(mTriangleMesh != nullptr)
+		{
+			mTriangleMesh->release();
+			mTriangleMesh = nullptr;
+		}
+
+		if (mConvexMesh != nullptr)
+		{
+			mConvexMesh->release();
+			mConvexMesh = nullptr;
+		}
+
+		PhysicsMesh::destroy();
+	}
+
+	MeshDataPtr PhysXMesh::getMeshData() const
+	{
+		VertexDataDescPtr vertexDesc = VertexDataDesc::create();
+		vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
+
+		if (mConvexMesh == nullptr && mTriangleMesh == nullptr)
+			return MeshData::create(0, 0, vertexDesc);
+
+		UINT32 numVertices = 0;
+		UINT32 numIndices = 0;
+
+		if(mConvexMesh != nullptr)
+		{
+			numVertices = mConvexMesh->getNbVertices();
+
+			UINT32 numPolygons = mConvexMesh->getNbPolygons();
+			for (UINT32 i = 0; i < numPolygons; i++)
+			{
+				PxHullPolygon face;
+				bool status = mConvexMesh->getPolygonData(i, face);
+				assert(status);
+
+				numIndices += (face.mNbVerts - 2) * 3;
+			}
+		}
+		else // Triangle
+		{
+			numVertices = mTriangleMesh->getNbVertices();
+			numIndices = mTriangleMesh->getNbTriangles() * 3;
+		}
+
+		MeshDataPtr meshData = MeshData::create(numVertices, numIndices, vertexDesc);
+
+		auto posIter = meshData->getVec3DataIter(VES_POSITION);
+		UINT32* outIndices = meshData->getIndices32();
+
+		if (mConvexMesh != nullptr)
+		{
+			const PxVec3* convexVertices = mConvexMesh->getVertices();
+			const UINT8* convexIndices = mConvexMesh->getIndexBuffer();
+
+			UINT32 numPolygons = mConvexMesh->getNbPolygons();
+			UINT32 offset = 0;
+			for (UINT32 i = 0; i < numPolygons; i++)
+			{
+				PxHullPolygon face;
+				bool status = mConvexMesh->getPolygonData(i, face);
+				assert(status);
+
+				const PxU8* faceIndices = convexIndices + face.mIndexBase;
+				for (UINT32 j = 0; j < face.mNbVerts; j++)
+					posIter.addValue(fromPxVector(convexVertices[faceIndices[j]]));
+
+				for (UINT32 j = 2; j < face.mNbVerts; j++)
+				{
+					*outIndices++ = offset;
+					*outIndices++ = offset + j;
+					*outIndices++ = offset + j - 1;
+				}
+
+				offset += face.mNbVerts;
+			}
+		}
+		else
+		{
+			const PxVec3* vertices = mTriangleMesh->getVertices();
+			for (UINT32 i = 0; i < numVertices; i++)
+				posIter.addValue(fromPxVector(vertices[i]));
+
+			if(mTriangleMesh->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES)
+			{
+				const UINT16* indices = (const UINT16*)mTriangleMesh->getTriangles();
+				for (UINT32 i = 0; i < numIndices; i++)
+					outIndices[i] = (UINT32)indices[i];
+			}
+			else
+			{
+				const UINT32* indices = (const UINT32*)mTriangleMesh->getTriangles();
+				memcpy(outIndices, indices, numIndices * sizeof(UINT32));
+			}
+		}
+
+		return meshData;
+	}
+
+	RTTITypeBase* PhysXMesh::getRTTIStatic()
+	{
+		return PhysXMeshRTTI::instance();
+	}
+
+	RTTITypeBase* PhysXMesh::getRTTI() const
+	{
+		return getRTTIStatic();
+	}
+}

+ 9 - 9
Doxyfile

@@ -32,7 +32,7 @@ DOXYFILE_ENCODING      = UTF-8
 # title of most generated pages and in a few other places.
 # The default value is: My Project.
 
-PROJECT_NAME           = "Banshee Engine"
+PROJECT_NAME           = "Banshee 3D"
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number. This
 # could be handy for archiving the generated documentation or if some version
@@ -68,7 +68,7 @@ OUTPUT_DIRECTORY       = C:\Projects\BansheeEngineDev\BansheeEngine\Documentatio
 # performance problems for the file system.
 # The default value is: NO.
 
-CREATE_SUBDIRS         = NO
+CREATE_SUBDIRS         = YES
 
 # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
 # characters to appear in the names of generated files. If set to NO, non-ASCII
@@ -492,7 +492,7 @@ HIDE_UNDOC_CLASSES     = NO
 # included in the documentation.
 # The default value is: NO.
 
-HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_FRIEND_COMPOUNDS  = YES
 
 # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
 # documentation blocks found inside the body of a function. If set to NO, these
@@ -522,7 +522,7 @@ CASE_SENSE_NAMES       = NO
 # scope will be hidden.
 # The default value is: NO.
 
-HIDE_SCOPE_NAMES       = NO
+HIDE_SCOPE_NAMES       = YES
 
 # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
 # append additional text to a page's title, such as Class Reference. If set to
@@ -554,7 +554,7 @@ FORCE_LOCAL_INCLUDES   = NO
 # documentation for inline members.
 # The default value is: YES.
 
-INLINE_INFO            = YES
+INLINE_INFO            = NO
 
 # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
 # (detailed) documentation of file and class members alphabetically by member
@@ -588,7 +588,7 @@ SORT_MEMBERS_CTORS_1ST = YES
 # appear in their defined order.
 # The default value is: NO.
 
-SORT_GROUP_NAMES       = NO
+SORT_GROUP_NAMES       = YES
 
 # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
 # fully-qualified names, including namespaces. If set to NO, the class list will
@@ -694,7 +694,7 @@ FILE_VERSION_FILTER    =
 # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
 # tag is left empty.
 
-LAYOUT_FILE            = 
+LAYOUT_FILE            = layout.xml
 
 # The CITE_BIB_FILES tag can be used to specify one or more bib files containing
 # the reference definitions. This must be a list of .bib files. The .bib
@@ -1442,7 +1442,7 @@ ECLIPSE_DOC_ID         = org.doxygen.Project
 # The default value is: NO.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-DISABLE_INDEX          = NO
+DISABLE_INDEX          = YES
 
 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
 # structure should be generated to display hierarchical information. If the tag
@@ -2156,7 +2156,7 @@ PERL_PATH              = /usr/bin/perl
 # powerful graphs.
 # The default value is: YES.
 
-CLASS_DIAGRAMS         = YES
+CLASS_DIAGRAMS         = NO
 
 # You can define message sequence charts within doxygen comments using the \msc
 # command. Doxygen will then run the mscgen tool (see: