Browse Source

Added ConeShape & TriangleMeshShape.

Lasse Öörni 13 years ago
parent
commit
70d95e7ae6

+ 3 - 4
Bin/Data/Scripts/TestScene.as

@@ -180,10 +180,9 @@ void InitScene()
         object.material = cache.GetResource("Material", "Materials/Mushroom.xml");
         object.material = cache.GetResource("Material", "Materials/Mushroom.xml");
         object.castShadows = true;
         object.castShadows = true;
 
 
-        /*
-        CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
-        shape.SetTriangleMesh(cache.GetResource("Model", "Models/Mushroom.mdl"), 0);
-        */
+        RigidBody@ body = objectNode.CreateComponent("RigidBody");
+        TriangleMeshShape@ shape = objectNode.CreateComponent("TriangleMeshShape");
+        shape.model = cache.GetResource("Model", "Models/Mushroom.mdl");
     }
     }
 
 
     for (uint i = 0; i < 50; ++i)
     for (uint i = 0; i < 50; ++i)

+ 16 - 0
Engine/Engine/PhysicsAPI.cpp

@@ -25,12 +25,14 @@
 #include "APITemplates.h"
 #include "APITemplates.h"
 #include "BoxShape.h"
 #include "BoxShape.h"
 #include "CapsuleShape.h"
 #include "CapsuleShape.h"
+#include "ConeShape.h"
 #include "CylinderShape.h"
 #include "CylinderShape.h"
 #include "Joint.h"
 #include "Joint.h"
 #include "PhysicsWorld.h"
 #include "PhysicsWorld.h"
 #include "RigidBody.h"
 #include "RigidBody.h"
 #include "Scene.h"
 #include "Scene.h"
 #include "SphereShape.h"
 #include "SphereShape.h"
+#include "TriangleMeshShape.h"
 
 
 static PhysicsWorld* SceneGetPhysicsWorld(Scene* ptr)
 static PhysicsWorld* SceneGetPhysicsWorld(Scene* ptr)
 {
 {
@@ -77,6 +79,12 @@ static void RegisterCollisionShapes(asIScriptEngine* engine)
     engine->RegisterObjectMethod("CapsuleShape", "void set_height(float)", asMETHOD(CapsuleShape, SetHeight), asCALL_THISCALL);
     engine->RegisterObjectMethod("CapsuleShape", "void set_height(float)", asMETHOD(CapsuleShape, SetHeight), asCALL_THISCALL);
     engine->RegisterObjectMethod("CapsuleShape", "float get_height() const", asMETHOD(CapsuleShape, GetHeight), asCALL_THISCALL);
     engine->RegisterObjectMethod("CapsuleShape", "float get_height() const", asMETHOD(CapsuleShape, GetHeight), asCALL_THISCALL);
     
     
+    RegisterCollisionShape<ConeShape>(engine, "ConeShape");
+    engine->RegisterObjectMethod("ConeShape", "void set_radius(float)", asMETHOD(ConeShape, SetRadius), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ConeShape", "float get_radius() const", asMETHOD(ConeShape, GetRadius), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ConeShape", "void set_height(float)", asMETHOD(ConeShape, SetHeight), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ConeShape", "float get_height() const", asMETHOD(ConeShape, GetHeight), asCALL_THISCALL);
+    
     RegisterCollisionShape<CylinderShape>(engine, "CylinderShape");
     RegisterCollisionShape<CylinderShape>(engine, "CylinderShape");
     engine->RegisterObjectMethod("CylinderShape", "void set_radius(float)", asMETHOD(CylinderShape, SetRadius), asCALL_THISCALL);
     engine->RegisterObjectMethod("CylinderShape", "void set_radius(float)", asMETHOD(CylinderShape, SetRadius), asCALL_THISCALL);
     engine->RegisterObjectMethod("CylinderShape", "float get_radius() const", asMETHOD(CylinderShape, GetRadius), asCALL_THISCALL);
     engine->RegisterObjectMethod("CylinderShape", "float get_radius() const", asMETHOD(CylinderShape, GetRadius), asCALL_THISCALL);
@@ -87,6 +95,14 @@ static void RegisterCollisionShapes(asIScriptEngine* engine)
     engine->RegisterObjectMethod("SphereShape", "void set_radius(float)", asMETHOD(SphereShape, SetRadius), asCALL_THISCALL);
     engine->RegisterObjectMethod("SphereShape", "void set_radius(float)", asMETHOD(SphereShape, SetRadius), asCALL_THISCALL);
     engine->RegisterObjectMethod("SphereShape", "float get_radius() const", asMETHOD(SphereShape, GetRadius), asCALL_THISCALL);
     engine->RegisterObjectMethod("SphereShape", "float get_radius() const", asMETHOD(SphereShape, GetRadius), asCALL_THISCALL);
     
     
+    RegisterCollisionShape<TriangleMeshShape>(engine, "TriangleMeshShape");
+    engine->RegisterObjectMethod("TriangleMeshShape", "void set_model(Model@+)", asMETHOD(TriangleMeshShape, SetModel), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TriangleMeshShape", "Model@+ get_model() const", asMETHOD(TriangleMeshShape, GetModel), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TriangleMeshShape", "void set_lodLevel(uint)", asMETHOD(TriangleMeshShape, SetLodLevel), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TriangleMeshShape", "uint get_lodLevel() const", asMETHOD(TriangleMeshShape, GetLodLevel), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TriangleMeshShape", "void set_size(const Vector3&in)", asMETHOD(TriangleMeshShape, SetSize), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TriangleMeshShape", "const Vector3& get_size() const", asMETHOD(TriangleMeshShape, GetSize), asCALL_THISCALL);
+    
     // Register Variant GetPtr() for CollisionShape
     // Register Variant GetPtr() for CollisionShape
     engine->RegisterObjectMethod("Variant", "CollisionShape@+ GetCollisionShape() const", asFUNCTION(GetVariantPtr<CollisionShape>), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Variant", "CollisionShape@+ GetCollisionShape() const", asFUNCTION(GetVariantPtr<CollisionShape>), asCALL_CDECL_OBJLAST);
 }
 }

+ 1 - 0
Engine/Physics/BoxShape.h

@@ -38,6 +38,7 @@ public:
     
     
     /// %Set box size.
     /// %Set box size.
     void SetSize(const Vector3& size);
     void SetSize(const Vector3& size);
+    
     /// Return box size.
     /// Return box size.
     const Vector3& GetSize() { return size_; }
     const Vector3& GetSize() { return size_; }
     
     

+ 69 - 81
Engine/Physics/CollisionShape.cpp

@@ -33,47 +33,23 @@
 #include "RigidBody.h"
 #include "RigidBody.h"
 #include "Scene.h"
 #include "Scene.h"
 
 
-#include <BulletCollision/CollisionShapes/btCollisionShape.h>
+#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
+#include <BulletCollision/CollisionShapes/btTriangleMesh.h>
 #include <hull.h>
 #include <hull.h>
 
 
-#include "DebugNew.h"
-
-void GetVertexAndIndexData(const Model* model, unsigned lodLevel, SharedArrayPtr<Vector3>& destVertexData, unsigned& destVertexCount,
-    SharedArrayPtr<unsigned>& destIndexData, unsigned& destIndexCount, const Vector3& scale)
+TriangleMeshData::TriangleMeshData(Model* model, unsigned lodLevel, const Vector3& scale) :
+    meshData_(0),
+    shape_(0)
 {
 {
+    modelName_ = model->GetName();
+    meshData_ = new btTriangleMesh();
     const Vector<Vector<SharedPtr<Geometry> > >& geometries = model->GetGeometries();
     const Vector<Vector<SharedPtr<Geometry> > >& geometries = model->GetGeometries();
     
     
-    destVertexCount = 0;
-    destIndexCount = 0;
-    
-    for (unsigned i = 0; i < geometries.Size(); ++i)
-    {
-        unsigned subGeometryLodLevel = lodLevel;
-        if (subGeometryLodLevel >= geometries[i].Size())
-            subGeometryLodLevel = geometries[i].Size() / 2;
-        
-        Geometry* geom = geometries[i][subGeometryLodLevel];
-        if (!geom)
-            continue;
-        
-        destVertexCount += geom->GetVertexCount();
-        destIndexCount += geom->GetIndexCount();
-    }
-    
-    if (!destVertexCount || !destIndexCount)
-        return;
-    
-    destVertexData = new Vector3[destVertexCount];
-    destIndexData = new unsigned[destIndexCount];
-    
-    unsigned firstVertex = 0;
-    unsigned firstIndex = 0;
-    
     for (unsigned i = 0; i < geometries.Size(); ++i)
     for (unsigned i = 0; i < geometries.Size(); ++i)
     {
     {
         unsigned subGeometryLodLevel = lodLevel;
         unsigned subGeometryLodLevel = lodLevel;
         if (subGeometryLodLevel >= geometries[i].Size())
         if (subGeometryLodLevel >= geometries[i].Size())
-            subGeometryLodLevel = geometries[i].Size() / 2;
+            subGeometryLodLevel = geometries[i].Size() - 1;
         
         
         Geometry* geom = geometries[i][subGeometryLodLevel];
         Geometry* geom = geometries[i][subGeometryLodLevel];
         if (!geom)
         if (!geom)
@@ -88,16 +64,6 @@ void GetVertexAndIndexData(const Model* model, unsigned lodLevel, SharedArrayPtr
         if (!vertexData || !indexData)
         if (!vertexData || !indexData)
             continue;
             continue;
         
         
-        unsigned vertexStart = geom->GetVertexStart();
-        unsigned vertexCount = geom->GetVertexCount();
-        
-        // Copy vertex data
-        for (unsigned j = 0; j < vertexCount; ++j)
-        {
-            const Vector3& v = *((const Vector3*)(&vertexData[(vertexStart + j) * vertexSize]));
-            destVertexData[firstVertex + j] = scale * v;
-        }
-        
         unsigned indexStart = geom->GetIndexStart();
         unsigned indexStart = geom->GetIndexStart();
         unsigned indexCount = geom->GetIndexCount();
         unsigned indexCount = geom->GetIndexCount();
         
         
@@ -106,12 +72,12 @@ void GetVertexAndIndexData(const Model* model, unsigned lodLevel, SharedArrayPtr
         {
         {
             const unsigned short* indices = (const unsigned short*)indexData;
             const unsigned short* indices = (const unsigned short*)indexData;
             
             
-            for (unsigned j = 0; j < indexCount; j += 3)
+            for (unsigned j = indexStart; j < indexStart + indexCount; j += 3)
             {
             {
-                // Rebase the indices according to our vertex numbering
-                destIndexData[firstIndex + j] = indices[indexStart + j] - vertexStart + firstVertex;
-                destIndexData[firstIndex + j + 1] = indices[indexStart + j + 1] - vertexStart + firstVertex;
-                destIndexData[firstIndex + j + 2] = indices[indexStart + j + 2] - vertexStart + firstVertex;
+                const Vector3& v0 = *((const Vector3*)(&vertexData[indices[j] * vertexSize]));
+                const Vector3& v1 = *((const Vector3*)(&vertexData[indices[j + 1] * vertexSize]));
+                const Vector3& v2 = *((const Vector3*)(&vertexData[indices[j + 2] * vertexSize]));
+                meshData_->addTriangle(ToBtVector3(scale * v0), ToBtVector3(scale * v1), ToBtVector3(scale * v2), true);
             }
             }
         }
         }
         // 32-bit indices
         // 32-bit indices
@@ -119,69 +85,91 @@ void GetVertexAndIndexData(const Model* model, unsigned lodLevel, SharedArrayPtr
         {
         {
             const unsigned* indices = (const unsigned*)indexData;
             const unsigned* indices = (const unsigned*)indexData;
             
             
-            for (unsigned j = 0; j < indexCount; j += 3)
+            for (unsigned j = indexStart; j < indexStart + indexCount; j += 3)
             {
             {
-                // Rebase the indices according to our vertex numbering
-                destIndexData[firstIndex + j] = indices[indexStart + j] - vertexStart + firstVertex;
-                destIndexData[firstIndex + j + 1] = indices[indexStart + j + 1] - vertexStart + firstVertex;
-                destIndexData[firstIndex + j + 2] = indices[indexStart + j + 2] - vertexStart + firstVertex;
+                const Vector3& v0 = *((const Vector3*)(&vertexData[indices[j] * vertexSize]));
+                const Vector3& v1 = *((const Vector3*)(&vertexData[indices[j + 1] * vertexSize]));
+                const Vector3& v2 = *((const Vector3*)(&vertexData[indices[j + 2] * vertexSize]));
+                meshData_->addTriangle(ToBtVector3(scale * v0), ToBtVector3(scale * v1), ToBtVector3(scale * v2), true);
             }
             }
         }
         }
-        
-        firstVertex += vertexCount;
-        firstIndex += indexCount;
     }
     }
+    
+    shape_ = new btBvhTriangleMeshShape(meshData_, true, true);
 }
 }
 
 
-TriangleMeshData::TriangleMeshData(Model* model, bool makeConvexHull, float thickness, unsigned lodLevel, const Vector3& scale) :
-    indexCount_(0)
+TriangleMeshData::~TriangleMeshData()
+{
+    delete shape_;
+    shape_ = 0;
+    
+    delete meshData_;
+    meshData_ = 0;
+}
+
+ConvexHullData::ConvexHullData(Model* model, unsigned lodLevel, float thickness, const Vector3& scale)
 {
 {
     modelName_ = model->GetName();
     modelName_ = model->GetName();
+    const Vector<Vector<SharedPtr<Geometry> > >& geometries = model->GetGeometries();
     
     
-    unsigned vertexCount;
-    unsigned indexCount;
+    PODVector<Vector3> originalVertices;
     
     
-    if (!makeConvexHull)
-        GetVertexAndIndexData(model, lodLevel, vertexData_, vertexCount, indexData_, indexCount, scale);
-    else
+    for (unsigned i = 0; i < geometries.Size(); ++i)
     {
     {
-        SharedArrayPtr<Vector3> originalVertices;
-        SharedArrayPtr<unsigned> originalIndices;
-        unsigned originalVertexCount;
-        unsigned originalIndexCount;
+        unsigned subGeometryLodLevel = lodLevel;
+        if (subGeometryLodLevel >= geometries[i].Size())
+            subGeometryLodLevel = geometries[i].Size() - 1;
+        
+        Geometry* geom = geometries[i][subGeometryLodLevel];
+        if (!geom)
+            continue;
+        
+        const unsigned char* vertexData;
+        const unsigned char* indexData;
+        unsigned vertexSize;
+        unsigned indexSize;
+        
+        geom->GetRawData(vertexData, vertexSize, indexData, indexSize);
+        if (!vertexData || !indexData)
+            continue;
         
         
-        GetVertexAndIndexData(model, lodLevel, originalVertices, originalVertexCount, originalIndices, originalIndexCount, scale);
+        unsigned vertexStart = geom->GetVertexStart();
+        unsigned vertexCount = geom->GetVertexCount();
         
         
+        // Copy vertex data
+        for (unsigned j = 0; j < vertexCount; ++j)
+        {
+            const Vector3& v = *((const Vector3*)(&vertexData[(vertexStart + j) * vertexSize]));
+            originalVertices.Push(scale * v);
+        }
+    }
+    
+    if (originalVertices.Size())
+    {
         // Build the convex hull from the raw geometry
         // Build the convex hull from the raw geometry
         StanHull::HullDesc desc;
         StanHull::HullDesc desc;
         desc.SetHullFlag(StanHull::QF_TRIANGLES);
         desc.SetHullFlag(StanHull::QF_TRIANGLES);
-        desc.mVcount = originalVertexCount;
-        desc.mVertices = (float*)originalVertices.Get();
+        desc.mVcount = originalVertices.Size();
+        desc.mVertices = originalVertices[0].Data();
         desc.mVertexStride = 3 * sizeof(float);
         desc.mVertexStride = 3 * sizeof(float);
         desc.mSkinWidth = thickness;
         desc.mSkinWidth = thickness;
         
         
         StanHull::HullLibrary lib;
         StanHull::HullLibrary lib;
         StanHull::HullResult result;
         StanHull::HullResult result;
         lib.CreateConvexHull(desc, result);
         lib.CreateConvexHull(desc, result);
-    
-        vertexCount = result.mNumOutputVertices;
-        indexCount = result.mNumIndices;
         
         
+        vertexCount_ = result.mNumOutputVertices;
+        vertexData_ = new Vector3[vertexCount_];
         // Copy vertex data
         // Copy vertex data
-        vertexData_ = new Vector3[vertexCount];
-        memcpy(vertexData_.Get(), result.mOutputVertices, vertexCount * sizeof(Vector3));
-        
-        // Copy index data
-        indexData_ = new unsigned[indexCount];
-        memcpy(indexData_.Get(), result.mIndices, indexCount * sizeof(unsigned));
+        memcpy(vertexData_.Get(), result.mOutputVertices, vertexCount_ * sizeof(Vector3));
         
         
         lib.ReleaseResult(result);
         lib.ReleaseResult(result);
     }
     }
-    
-    indexCount_ = indexCount;
+    else
+        vertexCount_ = 0;
 }
 }
 
 
-TriangleMeshData::~TriangleMeshData()
+ConvexHullData::~ConvexHullData()
 {
 {
 }
 }
 
 

+ 19 - 5
Engine/Physics/CollisionShape.h

@@ -34,7 +34,9 @@ class Model;
 class PhysicsWorld;
 class PhysicsWorld;
 class RigidBody;
 class RigidBody;
 
 
+class btBvhTriangleMeshShape;
 class btCollisionShape;
 class btCollisionShape;
+class btTriangleMesh;
 
 
 /// Base class for collision shape geometry data.
 /// Base class for collision shape geometry data.
 struct CollisionGeometryData : public RefCounted
 struct CollisionGeometryData : public RefCounted
@@ -47,16 +49,28 @@ struct CollisionGeometryData : public RefCounted
 struct TriangleMeshData : public CollisionGeometryData
 struct TriangleMeshData : public CollisionGeometryData
 {
 {
     /// Construct from a model.
     /// Construct from a model.
-    TriangleMeshData(Model* model, bool makeConvexHull, float thickness, unsigned lodLevel, const Vector3& scale);
+    TriangleMeshData(Model* model, unsigned lodLevel, const Vector3& scale);
     /// Destruct. Free geometry data.
     /// Destruct. Free geometry data.
     ~TriangleMeshData();
     ~TriangleMeshData();
     
     
+    /// Bullet triangle mesh data.
+    btTriangleMesh* meshData_;
+    /// Bullet triangle mesh collision shape.
+    btBvhTriangleMeshShape* shape_;
+};
+
+/// Convex hull geometry data.
+struct ConvexHullData : public CollisionGeometryData
+{
+    /// Construct from a model.
+    ConvexHullData(Model* model, unsigned lodLevel, float thickness, const Vector3& scale);
+    /// Destruct. Free geometry data.
+    ~ConvexHullData();
+    
     /// Vertex data.
     /// Vertex data.
     SharedArrayPtr<Vector3> vertexData_;
     SharedArrayPtr<Vector3> vertexData_;
-    /// Index data.
-    SharedArrayPtr<unsigned> indexData_;
-    /// Number of indices.
-    unsigned indexCount_;
+    /// Number of vertices.
+    unsigned vertexCount_;
 };
 };
 
 
 /// Heightfield geometry data.
 /// Heightfield geometry data.

+ 84 - 0
Engine/Physics/ConeShape.cpp

@@ -0,0 +1,84 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2012 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "ConeShape.h"
+#include "Context.h"
+#include "Node.h"
+#include "PhysicsUtils.h"
+
+#include <BulletCollision/CollisionShapes/btConeShape.h>
+
+OBJECTTYPESTATIC(ConeShape);
+
+static const float DEFAULT_RADIUS = 0.5f;
+static const float DEFAULT_HEIGHT = 1.0f;
+
+ConeShape::ConeShape(Context* context) :
+    CollisionShape(context),
+    radius_(DEFAULT_RADIUS),
+    height_(DEFAULT_HEIGHT)
+{
+}
+
+void ConeShape::RegisterObject(Context* context)
+{
+    context->RegisterFactory<ConeShape>();
+    
+    ATTRIBUTE(ConeShape, VAR_VECTOR3, "Offset Position", position_, Vector3::ZERO, AM_DEFAULT);
+    ATTRIBUTE(ConeShape, VAR_QUATERNION, "Offset Rotation", rotation_, Quaternion::IDENTITY, AM_DEFAULT);
+    ATTRIBUTE(ConeShape, VAR_FLOAT, "Radius", radius_, DEFAULT_RADIUS, AM_DEFAULT);
+    ATTRIBUTE(ConeShape, VAR_FLOAT, "Height", height_, DEFAULT_HEIGHT, AM_DEFAULT);
+}
+
+void ConeShape::SetRadius(float radius)
+{
+    if (radius != radius_)
+    {
+        radius_ = radius;
+        UpdateCollisionShape();
+        NotifyRigidBody();
+    }
+}
+
+void ConeShape::SetHeight(float height)
+{
+    if (height != height_)
+    {
+        height_ = height;
+        UpdateCollisionShape();
+        NotifyRigidBody();
+    }
+}
+
+void ConeShape::UpdateCollisionShape()
+{
+    if (node_)
+    {
+        delete shape_;
+        shape_ = 0;
+        
+        shape_ = new btConeShape(radius_, height_);
+        shape_->setLocalScaling(ToBtVector3(node_->GetWorldScale()));
+    }
+}

+ 58 - 0
Engine/Physics/ConeShape.h

@@ -0,0 +1,58 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2012 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "CollisionShape.h"
+
+/// Cylinder collision shape component.
+class ConeShape : public CollisionShape
+{
+    OBJECT(ConeShape);
+    
+public:
+    /// Construct.
+    ConeShape(Context* context);
+    /// Register object factory.
+    static void RegisterObject(Context* context);
+    
+    /// %Set cylinder radius.
+    void SetRadius(float radius);
+    /// %Set cylinder height.
+    void SetHeight(float height);
+    
+    /// Return cylinder radius.
+    float GetRadius() const { return radius_; }
+    /// Return cylinder height.
+    float GetHeight() const { return height_; }
+    
+protected:
+    /// Update the collision shape.
+    virtual void UpdateCollisionShape();
+    
+private:
+    /// Cylinder radius.
+    float radius_;
+    /// Cylinder height.
+    float height_;
+};

+ 1 - 1
Engine/Physics/CylinderShape.cpp

@@ -22,8 +22,8 @@
 //
 //
 
 
 #include "Precompiled.h"
 #include "Precompiled.h"
-#include "CylinderShape.h"
 #include "Context.h"
 #include "Context.h"
+#include "CylinderShape.h"
 #include "Node.h"
 #include "Node.h"
 #include "PhysicsUtils.h"
 #include "PhysicsUtils.h"
 
 

+ 12 - 1
Engine/Physics/PhysicsWorld.cpp

@@ -24,6 +24,7 @@
 #include "Precompiled.h"
 #include "Precompiled.h"
 #include "BoxShape.h"
 #include "BoxShape.h"
 #include "CapsuleShape.h"
 #include "CapsuleShape.h"
+#include "ConeShape.h"
 #include "Context.h"
 #include "Context.h"
 #include "CylinderShape.h"
 #include "CylinderShape.h"
 #include "DebugRenderer.h"
 #include "DebugRenderer.h"
@@ -40,6 +41,7 @@
 #include "SceneEvents.h"
 #include "SceneEvents.h"
 #include "Sort.h"
 #include "Sort.h"
 #include "SphereShape.h"
 #include "SphereShape.h"
+#include "TriangleMeshShape.h"
 
 
 #include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h>
 #include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h>
 #include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h>
 #include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h>
@@ -80,7 +82,7 @@ PhysicsWorld::PhysicsWorld(Context* context) :
     maxNetworkAngularVelocity_(DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY),
     maxNetworkAngularVelocity_(DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY),
     interpolation_(true),
     interpolation_(true),
     debugRenderer_(0),
     debugRenderer_(0),
-    debugMode_(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawConstraints)
+    debugMode_(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawNormals | btIDebugDraw::DBG_DrawConstraints)
 {
 {
     collisionConfiguration_ = new btDefaultCollisionConfiguration();
     collisionConfiguration_ = new btDefaultCollisionConfiguration();
     collisionDispatcher_ = new btCollisionDispatcher(collisionConfiguration_);
     collisionDispatcher_ = new btCollisionDispatcher(collisionConfiguration_);
@@ -260,6 +262,13 @@ void PhysicsWorld::CleanupGeometryCache()
             triangleMeshCache_.Erase(current);
             triangleMeshCache_.Erase(current);
     }
     }
     
     
+    for (Map<String, SharedPtr<ConvexHullData> >::Iterator i = convexHullCache_.Begin();
+        i != convexHullCache_.End();)
+    {
+        Map<String, SharedPtr<ConvexHullData> >::Iterator current = i++;
+        if (current->second_.Refs() == 1)
+            convexHullCache_.Erase(current);
+    }
     for (Map<String, SharedPtr<HeightfieldData> >::Iterator i = heightfieldCache_.Begin();
     for (Map<String, SharedPtr<HeightfieldData> >::Iterator i = heightfieldCache_.Begin();
         i != heightfieldCache_.End();)
         i != heightfieldCache_.End();)
     {
     {
@@ -321,7 +330,9 @@ void RegisterPhysicsLibrary(Context* context)
     RigidBody::RegisterObject(context);
     RigidBody::RegisterObject(context);
     BoxShape::RegisterObject(context);
     BoxShape::RegisterObject(context);
     CapsuleShape::RegisterObject(context);
     CapsuleShape::RegisterObject(context);
+    ConeShape::RegisterObject(context);
     CylinderShape::RegisterObject(context);
     CylinderShape::RegisterObject(context);
     SphereShape::RegisterObject(context);
     SphereShape::RegisterObject(context);
+    TriangleMeshShape::RegisterObject(context);
     PhysicsWorld::RegisterObject(context);
     PhysicsWorld::RegisterObject(context);
 }
 }

+ 5 - 0
Engine/Physics/PhysicsWorld.h

@@ -47,6 +47,7 @@ class btDiscreteDynamicsWorld;
 class btDispatcher;
 class btDispatcher;
 class btDynamicsWorld;
 class btDynamicsWorld;
 
 
+struct ConvexHullData;
 struct HeightfieldData;
 struct HeightfieldData;
 struct TriangleMeshData;
 struct TriangleMeshData;
 
 
@@ -169,6 +170,8 @@ public:
     void CleanupGeometryCache();
     void CleanupGeometryCache();
     /// Return the triangle mesh cache.
     /// Return the triangle mesh cache.
     Map<String, SharedPtr<TriangleMeshData> >& GetTriangleMeshCache() { return triangleMeshCache_; }
     Map<String, SharedPtr<TriangleMeshData> >& GetTriangleMeshCache() { return triangleMeshCache_; }
+    /// Return the convex hull cache.
+    Map<String, SharedPtr<ConvexHullData> >& GetConvexHullCache() { return convexHullCache_; }
     /// Return the heightfield cache.
     /// Return the heightfield cache.
     Map<String, SharedPtr<HeightfieldData> >& GetHeightfieldCache() { return heightfieldCache_; }
     Map<String, SharedPtr<HeightfieldData> >& GetHeightfieldCache() { return heightfieldCache_; }
     
     
@@ -214,6 +217,8 @@ private:
     Vector<PhysicsCollisionInfo> collisionInfos_;
     Vector<PhysicsCollisionInfo> collisionInfos_;
     /// Cache for triangle mesh geometries.
     /// Cache for triangle mesh geometries.
     Map<String, SharedPtr<TriangleMeshData> > triangleMeshCache_;
     Map<String, SharedPtr<TriangleMeshData> > triangleMeshCache_;
+    /// Cache for convex hull geometries.
+    Map<String, SharedPtr<ConvexHullData> > convexHullCache_;
     /// Cache for heightfield geometries.
     /// Cache for heightfield geometries.
     Map<String, SharedPtr<HeightfieldData> > heightfieldCache_;
     Map<String, SharedPtr<HeightfieldData> > heightfieldCache_;
     /// Simulation steps per second.
     /// Simulation steps per second.

+ 2 - 3
Engine/Physics/RigidBody.cpp

@@ -591,6 +591,8 @@ void RigidBody::OnNodeSet(Node* node)
             physicsWorld_ = scene->GetComponent<PhysicsWorld>();
             physicsWorld_ = scene->GetComponent<PhysicsWorld>();
             if (physicsWorld_)
             if (physicsWorld_)
                 physicsWorld_->AddRigidBody(this);
                 physicsWorld_->AddRigidBody(this);
+            else
+                LOGERROR("Null physics world, can not create rigid body");
             
             
             CreateBody();
             CreateBody();
         }
         }
@@ -601,10 +603,7 @@ void RigidBody::OnNodeSet(Node* node)
 void RigidBody::CreateBody()
 void RigidBody::CreateBody()
 {
 {
     if (!physicsWorld_)
     if (!physicsWorld_)
-    {
-        LOGERROR("Null physics world, can not create body");
         return;
         return;
-    }
     
     
     btVector3 localInertia(0.0f, 0.0f, 0.0f);
     btVector3 localInertia(0.0f, 0.0f, 0.0f);
     if (mass_ > 0.0f)
     if (mass_ > 0.0f)

+ 146 - 0
Engine/Physics/TriangleMeshShape.cpp

@@ -0,0 +1,146 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2012 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "Context.h"
+#include "Model.h"
+#include "Node.h"
+#include "PhysicsUtils.h"
+#include "PhysicsWorld.h"
+#include "ResourceCache.h"
+#include "TriangleMeshShape.h"
+
+#include <BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h>
+#include <stdio.h>
+
+OBJECTTYPESTATIC(TriangleMeshShape);
+
+TriangleMeshShape::TriangleMeshShape(Context* context) :
+    CollisionShape(context),
+    size_(Vector3::ONE),
+    lodLevel_(0)
+{
+}
+
+TriangleMeshShape::~TriangleMeshShape()
+{
+    delete shape_;
+    shape_ = 0;
+    
+    geometry_.Reset();
+    if (physicsWorld_)
+        physicsWorld_->CleanupGeometryCache();
+}
+
+void TriangleMeshShape::RegisterObject(Context* context)
+{
+    context->RegisterFactory<TriangleMeshShape>();
+    
+    ACCESSOR_ATTRIBUTE(TriangleMeshShape, VAR_RESOURCEREF, "Model", GetModelAttr, SetModelAttr, ResourceRef, ResourceRef(Model::GetTypeStatic()), AM_DEFAULT);
+    ATTRIBUTE(TriangleMeshShape, VAR_INT, "LOD Level", lodLevel_, 0, AM_DEFAULT);
+    ATTRIBUTE(TriangleMeshShape, VAR_VECTOR3, "Offset Position", position_, Vector3::ZERO, AM_DEFAULT);
+    ATTRIBUTE(TriangleMeshShape, VAR_QUATERNION, "Offset Rotation", rotation_, Quaternion::IDENTITY, AM_DEFAULT);
+    ATTRIBUTE(TriangleMeshShape, VAR_VECTOR3, "Size", size_, Vector3::ONE, AM_DEFAULT);
+}
+
+void TriangleMeshShape::SetModel(Model* model)
+{
+    if (model != model_)
+    {
+        model_ = model;
+        UpdateCollisionShape();
+        NotifyRigidBody();
+    }
+}
+
+void TriangleMeshShape::SetLodLevel(unsigned lodLevel)
+{
+    if (lodLevel != lodLevel_)
+    {
+        lodLevel_ = lodLevel;
+        UpdateCollisionShape();
+        NotifyRigidBody();
+    }
+}
+
+void TriangleMeshShape::SetSize(const Vector3& size)
+{
+    if (size != size_)
+    {
+        size_ = size;
+        UpdateCollisionShape();
+        NotifyRigidBody();
+    }
+}
+
+Model* TriangleMeshShape::GetModel() const
+{
+    return model_;
+}
+
+void TriangleMeshShape::SetModelAttr(ResourceRef value)
+{
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    model_ = cache->GetResource<Model>(value.id_);
+    dirty_ = true;
+}
+
+ResourceRef TriangleMeshShape::GetModelAttr() const
+{
+    return GetResourceRef(model_, Model::GetTypeStatic());
+}
+
+void TriangleMeshShape::UpdateCollisionShape()
+{
+    if (node_)
+    {
+        delete shape_;
+        shape_ = 0;
+        
+        if (model_ && physicsWorld_)
+        {
+            char sizeText[CONVERSION_BUFFER_LENGTH];
+            sprintf(sizeText, "%.3f%.3f%.3f", size_.x_, size_.y_, size_.z_);
+            
+            // Check the geometry cache
+            String id = model_->GetName() + "_" + String(lodLevel_) + "_" + String(sizeText);
+            
+            Map<String, SharedPtr<TriangleMeshData> >& cache = physicsWorld_->GetTriangleMeshCache();
+            Map<String, SharedPtr<TriangleMeshData> >::Iterator j = cache.Find(id);
+            if (j != cache.End())
+                geometry_ = j->second_;
+            else
+            {
+                geometry_ = new TriangleMeshData(model_, lodLevel_, size_);
+                cache[id] = geometry_;
+            }
+            
+            shape_ = new btScaledBvhTriangleMeshShape(geometry_->shape_, ToBtVector3(node_->GetWorldScale()));
+        }
+        else
+            geometry_.Reset();
+        
+        if (physicsWorld_)
+            physicsWorld_->CleanupGeometryCache();
+    }
+}

+ 73 - 0
Engine/Physics/TriangleMeshShape.h

@@ -0,0 +1,73 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2012 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "CollisionShape.h"
+
+/// Box collision shape component.
+class TriangleMeshShape : public CollisionShape
+{
+    OBJECT(TriangleMeshShape);
+    
+public:
+    /// Construct.
+    TriangleMeshShape(Context* context);
+    /// Destruct.
+    ~TriangleMeshShape();
+    /// Register object factory.
+    static void RegisterObject(Context* context);
+    
+    /// %Set model.
+    void SetModel(Model* model);
+    /// %Set LOD level.
+    void SetLodLevel(unsigned lodLevel);
+    /// %Set model scaling.
+    void SetSize(const Vector3& size);
+    
+    /// Return model.
+    Model* GetModel() const;
+    /// Return LOD level.
+    unsigned GetLodLevel() const { return lodLevel_; }
+    /// Return model scaling.
+    const Vector3& GetSize() { return size_; }
+    
+    /// %Set model attribute.
+    void SetModelAttr(ResourceRef value);
+    /// Return model attribute.
+    ResourceRef GetModelAttr() const;
+    
+protected:
+    /// Update the collision shape.
+    virtual void UpdateCollisionShape();
+    
+private:
+    /// Model.
+    SharedPtr<Model> model_;
+    /// Current geometry data.
+    SharedPtr<TriangleMeshData> geometry_;
+    /// Model scaling.
+    Vector3 size_;
+    /// LOD level.
+    unsigned lodLevel_;
+};