diff --git a/examples/collisionshapes/CMakeLists.txt b/examples/collisionshapes/CMakeLists.txt index 2d58d41d..6bdd5d3e 100644 --- a/examples/collisionshapes/CMakeLists.txt +++ b/examples/collisionshapes/CMakeLists.txt @@ -30,6 +30,7 @@ SET(COLLISION_SHAPES_SOURCES "../common/Sphere.cpp" "../common/Cylinder.cpp" "../common/Cone.cpp" + "../common/Dumbbell.cpp" "../common/Box.cpp" "../common/Viewer.cpp" ) diff --git a/examples/collisionshapes/Scene.cpp b/examples/collisionshapes/Scene.cpp index 582c4040..440ec5a6 100644 --- a/examples/collisionshapes/Scene.cpp +++ b/examples/collisionshapes/Scene.cpp @@ -62,6 +62,25 @@ Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath, const std::str float radius = 3.0f; + for (int i=0; igetRigidBody()->getMaterial(); + material.setBounciness(rp3d::decimal(0.2)); + + // Add the mesh the list of dumbbells in the scene + mDumbbells.push_back(dumbbell); + } + // Create all the boxes of the scene for (int i=0; i::iterator it = mDumbbells.begin(); + it != mDumbbells.end(); ++it) { + + // Destroy the corresponding rigid body from the dynamics world + mDynamicsWorld->destroyRigidBody((*it)->getRigidBody()); + + // Destroy the convex mesh + delete (*it); + } + // Destroy all the visual contact points for (std::vector::iterator it = mContactPoints.begin(); it != mContactPoints.end(); ++it) { @@ -342,6 +372,14 @@ void Scene::simulate() { (*it)->updateTransform(); } + // Update the position and orientation of the dumbbells + for (std::vector::iterator it = mDumbbells.begin(); + it != mDumbbells.end(); ++it) { + + // Update the transform used for the rendering + (*it)->updateTransform(); + } + // Destroy all the visual contact points for (std::vector::iterator it = mContactPoints.begin(); it != mContactPoints.end(); ++it) { @@ -422,6 +460,12 @@ void Scene::render() { (*it)->render(mPhongShader, worldToCameraMatrix); } + // Render all the dumbbells of the scene + for (std::vector::iterator it = mDumbbells.begin(); + it != mDumbbells.end(); ++it) { + (*it)->render(mPhongShader, worldToCameraMatrix); + } + // Render all the visual contact points for (std::vector::iterator it = mContactPoints.begin(); it != mContactPoints.end(); ++it) { diff --git a/examples/collisionshapes/Scene.h b/examples/collisionshapes/Scene.h index 9d2959e8..347a4eda 100644 --- a/examples/collisionshapes/Scene.h +++ b/examples/collisionshapes/Scene.h @@ -35,16 +35,18 @@ #include "Cylinder.h" #include "Capsule.h" #include "ConvexMesh.h" +#include "Dumbbell.h" #include "VisualContactPoint.h" #include "../common/Viewer.h" // Constants const int NB_BOXES = 3; -const int NB_SPHERES = 3; -const int NB_CONES = 3; -const int NB_CYLINDERS = 3; -const int NB_CAPSULES = 3; -const int NB_MESHES = 3; +const int NB_SPHERES = 2; +const int NB_CONES = 0; +const int NB_CYLINDERS = 0; +const int NB_CAPSULES = 0; +const int NB_MESHES = 0; +const int NB_COMPOUND_SHAPES = 2; const openglframework::Vector3 BOX_SIZE(2, 2, 2); const float SPHERE_RADIUS = 1.5f; const float CONE_RADIUS = 2.0f; @@ -53,6 +55,7 @@ const float CYLINDER_RADIUS = 1.0f; const float CYLINDER_HEIGHT = 5.0f; const float CAPSULE_RADIUS = 1.0f; const float CAPSULE_HEIGHT = 1.0f; +const float DUMBBELL_HEIGHT = 1.0f; const openglframework::Vector3 FLOOR_SIZE(20, 0.5f, 20); // Floor dimensions in meters const float BOX_MASS = 1.0f; const float CONE_MASS = 1.0f; @@ -91,6 +94,9 @@ class Scene { /// All the convex meshes of the scene std::vector mConvexMeshes; + /// All the dumbbell of the scene + std::vector mDumbbells; + /// All the visual contact points std::vector mContactPoints; diff --git a/examples/common/Box.cpp b/examples/common/Box.cpp index 817080b2..1a738714 100644 --- a/examples/common/Box.cpp +++ b/examples/common/Box.cpp @@ -77,7 +77,7 @@ Box::Box(const openglframework::Vector3& size, const openglframework::Vector3 &p // Create the collision shape for the rigid body (box shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() const rp3d::BoxShape collisionShape(rp3d::Vector3(mSize[0], mSize[1], mSize[2])); // Initial position and orientation of the rigid body diff --git a/examples/common/Capsule.cpp b/examples/common/Capsule.cpp index d593281f..85c1f341 100644 --- a/examples/common/Capsule.cpp +++ b/examples/common/Capsule.cpp @@ -50,7 +50,7 @@ Capsule::Capsule(float radius, float height, const openglframework::Vector3& pos // Create the collision shape for the rigid body (sphere shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() const rp3d::CapsuleShape collisionShape(mRadius, mHeight); // Initial position and orientation of the rigid body diff --git a/examples/common/Cone.cpp b/examples/common/Cone.cpp index df6714c7..58b0b2d7 100644 --- a/examples/common/Cone.cpp +++ b/examples/common/Cone.cpp @@ -50,7 +50,7 @@ Cone::Cone(float radius, float height, const openglframework::Vector3 &position, // Create the collision shape for the rigid body (cone shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() const rp3d::ConeShape collisionShape(mRadius, mHeight); // Initial position and orientation of the rigid body diff --git a/examples/common/ConvexMesh.cpp b/examples/common/ConvexMesh.cpp index 725c68e5..152417fd 100644 --- a/examples/common/ConvexMesh.cpp +++ b/examples/common/ConvexMesh.cpp @@ -44,7 +44,7 @@ ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, float mass, // Create the collision shape for the rigid body (convex mesh shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() rp3d::decimal* verticesArray = (rp3d::decimal*) getVerticesPointer(); rp3d::ConvexMeshShape collisionShape(verticesArray, mVertices.size(), sizeof(openglframework::Vector3)); diff --git a/examples/common/Cylinder.cpp b/examples/common/Cylinder.cpp index 15f4756c..106f7258 100644 --- a/examples/common/Cylinder.cpp +++ b/examples/common/Cylinder.cpp @@ -28,7 +28,7 @@ // Constructor -Cylinder::Cylinder(float radius, float height, const openglframework::Vector3 &position, +Cylinder::Cylinder(float radius, float height, const openglframework::Vector3& position, float mass, reactphysics3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath) : openglframework::Mesh(), mRadius(radius), mHeight(height) { @@ -50,7 +50,7 @@ Cylinder::Cylinder(float radius, float height, const openglframework::Vector3 &p // Create the collision shape for the rigid body (cylinder shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() const rp3d::CylinderShape collisionShape(mRadius, mHeight); // Initial position and orientation of the rigid body diff --git a/examples/common/Dumbbell.cpp b/examples/common/Dumbbell.cpp new file mode 100644 index 00000000..d1fc708e --- /dev/null +++ b/examples/common/Dumbbell.cpp @@ -0,0 +1,154 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2014 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +// Libraries +#include "Dumbbell.h" + + +// Constructor +Dumbbell::Dumbbell(const openglframework::Vector3 &position, + reactphysics3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath) + : openglframework::Mesh() { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "dumbbell.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Identity scaling matrix + mScalingMatrix.setToIdentity(); + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Create a sphere collision shape for the two ends of the dumbbell + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::decimal radiusSphere = rp3d::decimal(1.5); + const rp3d::decimal massSphere = rp3d::decimal(2.0); + const rp3d::SphereShape sphereCollisionShape(radiusSphere); + + // Create a cylinder collision shape for the middle of the dumbbell + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::decimal radiusCylinder = rp3d::decimal(0.5); + const rp3d::decimal heightCylinder = rp3d::decimal(8.0); + const rp3d::decimal massCylinder = rp3d::decimal(1.0); + const rp3d::CylinderShape cylinderCollisionShape(radiusCylinder, heightCylinder); + + // Initial position and orientation of the rigid body + rp3d::Vector3 initPosition(position.x, position.y, position.z); + rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); + rp3d::Transform transformBody(initPosition, initOrientation); + + // Initial transform of the first sphere collision shape of the dumbbell (in local-space) + rp3d::Transform transformSphereShape1(rp3d::Vector3(0, 4.0, 0), rp3d::Quaternion::identity()); + + // Initial transform of the second sphere collision shape of the dumbell (in local-space) + rp3d::Transform transformSphereShape2(rp3d::Vector3(0, -4.0, 0), rp3d::Quaternion::identity()); + + // Initial transform of the cylinder collision shape of the dumbell (in local-space) + rp3d::Transform transformCylinderShape(rp3d::Vector3(0, 0, 0), rp3d::Quaternion::identity()); + + // Create a rigid body corresponding to the dumbbell in the dynamics world + mRigidBody = dynamicsWorld->createRigidBody(transformBody); + + // Add the three collision shapes to the body and specify the mass and transform of the shapes + mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape1); + mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape2); + //mRigidBody->addCollisionShape(cylinderCollisionShape, massCylinder, transformCylinderShape); +} + +// Destructor +Dumbbell::~Dumbbell() { + + // Destroy the mesh + destroy(); +} + +// Render the sphere at the correct position and with the correct orientation +void Dumbbell::render(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix) { + + // Bind the shader + shader.bind(); + + // Set the model to camera matrix + const openglframework::Matrix4 localToCameraMatrix = worldToCameraMatrix * mTransformMatrix; + shader.setMatrix4x4Uniform("localToCameraMatrix", localToCameraMatrix); + + // Set the normal matrix (inverse transpose of the 3x3 upper-left sub matrix of the + // model-view matrix) + const openglframework::Matrix3 normalMatrix = + localToCameraMatrix.getUpperLeft3x3Matrix().getInverse().getTranspose(); + shader.setMatrix3x3Uniform("normalMatrix", normalMatrix); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + if (hasTexture()) { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + + glVertexPointer(3, GL_FLOAT, 0, getVerticesPointer()); + glNormalPointer(GL_FLOAT, 0, getNormalsPointer()); + if(hasTexture()) { + glTexCoordPointer(2, GL_FLOAT, 0, getUVTextureCoordinatesPointer()); + } + + // For each part of the mesh + for (unsigned int i=0; igetInterpolatedTransform(); + + // Compute the transform used for rendering the sphere + float matrix[16]; + transform.getOpenGLMatrix(matrix); + openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], + matrix[1], matrix[5], matrix[9], matrix[13], + matrix[2], matrix[6], matrix[10], matrix[14], + matrix[3], matrix[7], matrix[11], matrix[15]); + + // Apply the scaling matrix to have the correct sphere dimensions + mTransformMatrix = newMatrix * mScalingMatrix; +} + diff --git a/examples/common/Dumbbell.h b/examples/common/Dumbbell.h new file mode 100644 index 00000000..abcb6c60 --- /dev/null +++ b/examples/common/Dumbbell.h @@ -0,0 +1,78 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2014 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef DUMBBELL_H +#define DUMBBELL_H + +// Libraries +#include "openglframework.h" +#include "reactphysics3d.h" + +// Class Sphere +class Dumbbell : public openglframework::Mesh { + + private : + + // -------------------- Attributes -------------------- // + + /// Radius of the spheres + float mRadius; + + /// Rigid body used to simulate the dynamics of the sphere + rp3d::RigidBody* mRigidBody; + + /// Scaling matrix (applied to a sphere to obtain the correct sphere dimensions) + openglframework::Matrix4 mScalingMatrix; + + // -------------------- Methods -------------------- // + + public : + + // -------------------- Methods -------------------- // + + /// Constructor + Dumbbell(const openglframework::Vector3& position, rp3d::DynamicsWorld* dynamicsWorld, + const std::string& meshFolderPath); + + /// Destructor + ~Dumbbell(); + + /// Return a pointer to the rigid body of the sphere + rp3d::RigidBody* getRigidBody(); + + /// Update the transform matrix of the sphere + void updateTransform(); + + /// Render the sphere at the correct position and with the correct orientation + void render(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix); +}; + +// Return a pointer to the rigid body of the sphere +inline rp3d::RigidBody* Dumbbell::getRigidBody() { + return mRigidBody; +} + +#endif diff --git a/examples/common/Sphere.cpp b/examples/common/Sphere.cpp index d8af5af7..075c0c22 100644 --- a/examples/common/Sphere.cpp +++ b/examples/common/Sphere.cpp @@ -50,7 +50,7 @@ Sphere::Sphere(float radius, const openglframework::Vector3 &position, // Create the collision shape for the rigid body (sphere shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() const rp3d::SphereShape collisionShape(mRadius); // Initial position and orientation of the rigid body diff --git a/examples/common/meshes/dumbbell.obj b/examples/common/meshes/dumbbell.obj new file mode 100644 index 00000000..43099a93 --- /dev/null +++ b/examples/common/meshes/dumbbell.obj @@ -0,0 +1,1396 @@ +#### +# +# OBJ File Generated by Meshlab +# +#### +# Object dumbbell.obj +# +# Vertices: 464 +# Faces: 916 +# +#### +v -0.429342 4.000000 1.439240 +v -0.823902 4.000000 1.261880 +v -1.151714 4.000000 0.982291 +v -1.386221 4.000000 0.623122 +v -1.508424 4.000000 0.213472 +v -1.508424 4.000000 -0.213472 +v -1.386221 4.000000 -0.623123 +v -1.151714 4.000000 -0.982291 +v -0.823902 4.000000 -1.261880 +v -0.429342 4.000000 -1.439240 +v -0.410268 4.126197 1.439240 +v -0.787298 4.242170 1.261880 +v -1.100546 4.338524 0.982291 +v -1.324635 4.407454 0.623122 +v -1.441409 4.443373 0.213472 +v -1.441409 4.443373 -0.213472 +v -1.324635 4.407454 -0.623123 +v -1.100546 4.338524 -0.982291 +v -0.787298 4.242170 -1.261880 +v -0.410268 4.126197 -1.439240 +v -0.354739 4.241181 1.439240 +v -0.680740 4.462823 1.261880 +v -0.951591 4.646970 0.982291 +v -1.145349 4.778703 0.623122 +v -1.246319 4.847349 0.213472 +v -1.246319 4.847349 -0.213472 +v -1.145349 4.778703 -0.623123 +v -0.951590 4.646970 -0.982291 +v -0.680740 4.462823 -1.261880 +v -0.354739 4.241181 -1.439240 +v -0.267691 4.334735 1.439240 +v -0.513694 4.642351 1.261880 +v -0.718082 4.897928 0.982291 +v -0.864294 5.080761 0.623122 +v -0.940487 5.176036 0.213472 +v -0.940487 5.176036 -0.213472 +v -0.864295 5.080761 -0.623123 +v -0.718082 4.897928 -0.982291 +v -0.513694 4.642351 -1.261880 +v -0.267691 4.334735 -1.439240 +v -0.156856 4.398545 1.439240 +v -0.301005 4.764804 1.261880 +v -0.420768 5.069102 0.982291 +v -0.506443 5.286788 0.623122 +v -0.551089 5.400227 0.213472 +v -0.551089 5.400227 -0.213472 +v -0.506443 5.286788 -0.623123 +v -0.420768 5.069102 -0.982291 +v -0.301005 4.764804 -1.261880 +v -0.156856 4.398545 -1.439240 +v -0.032085 4.426945 1.439240 +v -0.061570 4.819301 1.261880 +v -0.086068 5.145282 0.982291 +v -0.103592 5.378479 0.623122 +v -0.112725 5.500000 0.213472 +v -0.112725 5.500000 -0.213472 +v -0.103593 5.378479 -0.623123 +v -0.086068 5.145282 -0.982291 +v -0.061570 4.819301 -1.261880 +v -0.032085 4.426945 -1.439240 +v 0.095537 4.417407 1.439240 +v 0.183335 4.800999 1.261880 +v 0.256280 5.119698 0.982291 +v 0.308463 5.347686 0.623122 +v 0.335656 5.466493 0.213472 +v 0.335656 5.466493 -0.213472 +v 0.308463 5.347686 -0.623123 +v 0.256280 5.119698 -0.982291 +v 0.183335 4.800999 -1.261880 +v 0.095537 4.417407 -1.439240 +v 0.214671 4.370781 1.439240 +v 0.411951 4.711524 1.261880 +v 0.575857 4.994623 0.982291 +v 0.693110 5.197145 0.623122 +v 0.754212 5.302681 0.213472 +v 0.754212 5.302681 -0.213472 +v 0.693110 5.197145 -0.623123 +v 0.575857 4.994623 -0.982291 +v 0.411951 4.711524 -1.261880 +v 0.214671 4.370781 -1.439240 +v 0.000000 4.000000 1.500000 +v 0.314730 4.291210 1.439240 +v 0.603963 4.558828 1.261880 +v 0.844266 4.781174 0.982291 +v 1.016171 4.940232 0.623122 +v 1.105753 5.023119 0.213472 +v 1.105753 5.023119 -0.213472 +v 1.016171 4.940232 -0.623123 +v 0.844265 4.781174 -0.982291 +v 0.603963 4.558828 -1.261880 +v 0.314730 4.291210 -1.439240 +v 0.000000 4.000000 -1.500000 +v 0.386824 4.185763 1.439240 +v 0.742310 4.356478 1.261880 +v 1.037658 4.498313 0.982291 +v 1.248941 4.599776 0.623122 +v 1.359043 4.652650 0.213472 +v 1.359043 4.652650 -0.213472 +v 1.248941 4.599776 -0.623123 +v 1.037657 4.498311 -0.982291 +v 0.742310 4.356478 -1.261880 +v 0.386824 4.185763 -1.439240 +v 0.424547 4.063811 1.439240 +v 0.814699 4.122453 1.261880 +v 1.138849 4.171173 0.982291 +v 1.370737 4.206027 0.623122 +v 1.491576 4.224190 0.213472 +v 1.491576 4.224190 -0.213472 +v 1.370737 4.206027 -0.623123 +v 1.138849 4.171173 -0.982291 +v 0.814699 4.122453 -1.261880 +v 0.424547 4.063811 -1.439240 +v 0.424546 3.936189 1.439240 +v 0.814699 3.877547 1.261880 +v 1.138849 3.828825 0.982291 +v 1.370737 3.793972 0.623122 +v 1.491575 3.775809 0.213472 +v 1.491575 3.775809 -0.213472 +v 1.370737 3.793972 -0.623123 +v 1.138849 3.828825 -0.982291 +v 0.814699 3.877547 -1.261880 +v 0.424547 3.936189 -1.439240 +v 0.386824 3.814236 1.439240 +v 0.742309 3.643522 1.261880 +v 1.037657 3.501688 0.982291 +v 1.248941 3.400223 0.623122 +v 1.359042 3.347349 0.213472 +v 1.359042 3.347349 -0.213472 +v 1.248941 3.400223 -0.623123 +v 1.037657 3.501688 -0.982291 +v 0.742309 3.643522 -1.261880 +v 0.386824 3.814236 -1.439240 +v 0.314730 3.708790 1.439240 +v 0.603962 3.441171 1.261880 +v 0.844265 3.218826 0.982291 +v 1.016171 3.059767 0.623122 +v 1.105752 2.976880 0.213472 +v 1.105752 2.976880 -0.213472 +v 1.016171 3.059767 -0.623123 +v 0.844265 3.218826 -0.982291 +v 0.603962 3.441171 -1.261880 +v 0.314730 3.708790 -1.439240 +v 0.214671 3.629218 1.439240 +v 0.411950 3.288475 1.261880 +v 0.575856 3.005375 0.982291 +v 0.693109 2.802855 0.623122 +v 0.754211 2.697319 0.213472 +v 0.754211 2.697319 -0.213472 +v 0.693109 2.802855 -0.623123 +v 0.575856 3.005376 -0.982291 +v 0.411950 3.288475 -1.261880 +v 0.214671 3.629218 -1.439240 +v 0.095537 3.582592 1.439240 +v 0.183335 3.199001 1.261880 +v 0.256280 2.880302 0.982291 +v 0.308462 2.652314 0.623122 +v 0.335655 2.533507 0.213472 +v 0.335655 2.533507 -0.213472 +v 0.308462 2.652314 -0.623123 +v 0.256280 2.880302 -0.982291 +v 0.183335 3.199001 -1.261880 +v 0.095537 3.582592 -1.439240 +v -0.032085 3.573055 1.439240 +v -0.061571 3.180699 1.261880 +v -0.086068 2.854718 0.982291 +v -0.103593 2.621521 0.623122 +v -0.112726 2.500000 0.213472 +v -0.112726 2.500000 -0.213472 +v -0.103593 2.621521 -0.623123 +v -0.086068 2.854718 -0.982291 +v -0.061571 3.180699 -1.261880 +v -0.032085 3.573055 -1.439240 +v -0.156857 3.601454 1.439240 +v -0.301005 3.235196 1.261880 +v -0.420769 2.930898 0.982291 +v -0.506444 2.713212 0.623122 +v -0.551090 2.599774 0.213472 +v -0.551090 2.599774 -0.213472 +v -0.506444 2.713212 -0.623123 +v -0.420769 2.930898 -0.982291 +v -0.301005 3.235196 -1.261880 +v -0.156857 3.601454 -1.439240 +v -0.267691 3.665266 1.439240 +v -0.513695 3.357649 1.261880 +v -0.718082 3.102072 0.982291 +v -0.864295 2.919240 0.623122 +v -0.940488 2.823965 0.213472 +v -0.940488 2.823965 -0.213472 +v -0.864295 2.919240 -0.623123 +v -0.718082 3.102072 -0.982291 +v -0.513695 3.357649 -1.261880 +v -0.267691 3.665266 -1.439240 +v -0.354739 3.758819 1.439240 +v -0.680740 3.537178 1.261880 +v -0.951591 3.353031 0.982291 +v -1.145349 3.221298 0.623122 +v -1.246319 3.152651 0.213472 +v -1.246319 3.152651 -0.213472 +v -1.145349 3.221298 -0.623123 +v -0.951591 3.353031 -0.982291 +v -0.680740 3.537178 -1.261880 +v -0.354739 3.758819 -1.439240 +v -0.410268 3.873803 1.439240 +v -0.787298 3.757830 1.261880 +v -1.100546 3.661476 0.982291 +v -1.324635 3.592547 0.623122 +v -1.441409 3.556628 0.213472 +v -1.441409 3.556628 -0.213472 +v -1.324635 3.592547 -0.623123 +v -1.100546 3.661476 -0.982291 +v -0.787298 3.757830 -1.261880 +v -0.410268 3.873803 -1.439240 +v -0.039595 2.492897 0.497466 +v -0.039595 -2.507103 0.497462 +v 0.114914 2.492897 0.472994 +v 0.114914 -2.507103 0.472991 +v 0.254298 2.492897 0.401974 +v 0.254298 -2.507103 0.401971 +v 0.364914 2.492897 0.291358 +v 0.364914 -2.507103 0.291355 +v 0.435934 2.492897 0.151974 +v 0.435934 -2.507103 0.151971 +v 0.460405 2.492897 -0.002534 +v 0.460405 -2.507103 -0.002538 +v 0.435934 2.492897 -0.157043 +v 0.435934 -2.507103 -0.157046 +v 0.364914 2.492897 -0.296427 +v 0.364914 -2.507103 -0.296430 +v 0.254298 2.492897 -0.407043 +v 0.254298 -2.507103 -0.407046 +v 0.114914 2.492897 -0.478063 +v 0.114914 -2.507103 -0.478066 +v -0.039595 2.492897 -0.502534 +v -0.039595 -2.507103 -0.502538 +v -0.194103 2.492897 -0.478063 +v -0.194103 -2.507103 -0.478066 +v -0.333487 2.492897 -0.407043 +v -0.333487 -2.507103 -0.407046 +v -0.444103 2.492897 -0.296427 +v -0.444103 -2.507103 -0.296430 +v -0.515123 2.492897 -0.157042 +v -0.515123 -2.507103 -0.157046 +v -0.539595 2.492897 -0.002534 +v -0.539595 -2.507103 -0.002537 +v -0.515123 2.492897 0.151975 +v -0.515123 -2.507103 0.151971 +v -0.444103 2.492897 0.291359 +v -0.444103 -2.507103 0.291356 +v -0.333487 2.492897 0.401975 +v -0.333487 -2.507103 0.401971 +v -0.194102 2.492897 0.472994 +v -0.194102 -2.507103 0.472991 +v -0.429342 -4.000000 1.439240 +v -0.823902 -4.000000 1.261880 +v -1.151714 -4.000000 0.982291 +v -1.386221 -4.000000 0.623122 +v -1.508424 -4.000000 0.213472 +v -1.508424 -4.000000 -0.213472 +v -1.386221 -4.000000 -0.623123 +v -1.151714 -4.000000 -0.982291 +v -0.823902 -4.000000 -1.261880 +v -0.429342 -4.000000 -1.439240 +v -0.410268 -3.873803 1.439240 +v -0.787298 -3.757830 1.261880 +v -1.100546 -3.661476 0.982291 +v -1.324635 -3.592547 0.623122 +v -1.441409 -3.556627 0.213472 +v -1.441409 -3.556627 -0.213472 +v -1.324635 -3.592547 -0.623123 +v -1.100546 -3.661476 -0.982291 +v -0.787298 -3.757830 -1.261880 +v -0.410268 -3.873803 -1.439240 +v -0.354739 -3.758819 1.439240 +v -0.680740 -3.537177 1.261880 +v -0.951591 -3.353031 0.982291 +v -1.145349 -3.221298 0.623122 +v -1.246319 -3.152650 0.213472 +v -1.246319 -3.152650 -0.213472 +v -1.145349 -3.221298 -0.623123 +v -0.951590 -3.353031 -0.982291 +v -0.680740 -3.537177 -1.261880 +v -0.354739 -3.758819 -1.439240 +v -0.267691 -3.665265 1.439240 +v -0.513694 -3.357649 1.261880 +v -0.718082 -3.102072 0.982291 +v -0.864294 -2.919240 0.623122 +v -0.940487 -2.823964 0.213472 +v -0.940487 -2.823964 -0.213472 +v -0.864295 -2.919240 -0.623123 +v -0.718082 -3.102072 -0.982291 +v -0.513694 -3.357649 -1.261880 +v -0.267691 -3.665265 -1.439240 +v -0.156856 -3.601454 1.439240 +v -0.301005 -3.235196 1.261880 +v -0.420768 -2.930898 0.982291 +v -0.506443 -2.713212 0.623122 +v -0.551089 -2.599774 0.213472 +v -0.551089 -2.599774 -0.213472 +v -0.506443 -2.713212 -0.623123 +v -0.420768 -2.930898 -0.982291 +v -0.301005 -3.235196 -1.261880 +v -0.156856 -3.601454 -1.439240 +v -0.032085 -3.573056 1.439240 +v -0.061570 -3.180699 1.261880 +v -0.086068 -2.854718 0.982291 +v -0.103592 -2.621521 0.623122 +v -0.112725 -2.500000 0.213472 +v -0.112725 -2.500000 -0.213472 +v -0.103593 -2.621521 -0.623123 +v -0.086068 -2.854718 -0.982291 +v -0.061570 -3.180699 -1.261880 +v -0.032085 -3.573056 -1.439240 +v 0.095537 -3.582593 1.439240 +v 0.183335 -3.199001 1.261880 +v 0.256280 -2.880302 0.982291 +v 0.308463 -2.652314 0.623122 +v 0.335656 -2.533507 0.213472 +v 0.335656 -2.533507 -0.213472 +v 0.308463 -2.652314 -0.623123 +v 0.256280 -2.880302 -0.982291 +v 0.183335 -3.199001 -1.261880 +v 0.095537 -3.582593 -1.439240 +v 0.214671 -3.629219 1.439240 +v 0.411951 -3.288476 1.261880 +v 0.575857 -3.005376 0.982291 +v 0.693110 -2.802855 0.623122 +v 0.754212 -2.697320 0.213472 +v 0.754212 -2.697320 -0.213472 +v 0.693110 -2.802855 -0.623123 +v 0.575857 -3.005376 -0.982291 +v 0.411951 -3.288476 -1.261880 +v 0.214671 -3.629218 -1.439240 +v 0.000000 -4.000000 1.500000 +v 0.314730 -3.708790 1.439240 +v 0.603963 -3.441172 1.261880 +v 0.844266 -3.218827 0.982291 +v 1.016171 -3.059767 0.623122 +v 1.105753 -2.976881 0.213472 +v 1.105753 -2.976881 -0.213472 +v 1.016171 -3.059767 -0.623123 +v 0.844265 -3.218827 -0.982291 +v 0.603963 -3.441172 -1.261880 +v 0.314730 -3.708790 -1.439240 +v 0.000000 -4.000000 -1.500000 +v 0.386824 -3.814236 1.439240 +v 0.742310 -3.643522 1.261880 +v 1.037658 -3.501688 0.982291 +v 1.248941 -3.400224 0.623122 +v 1.359043 -3.347350 0.213472 +v 1.359043 -3.347350 -0.213472 +v 1.248941 -3.400223 -0.623123 +v 1.037657 -3.501688 -0.982291 +v 0.742310 -3.643522 -1.261880 +v 0.386824 -3.814236 -1.439240 +v 0.424547 -3.936189 1.439240 +v 0.814699 -3.877548 1.261880 +v 1.138849 -3.828826 0.982291 +v 1.370737 -3.793973 0.623122 +v 1.491576 -3.775810 0.213472 +v 1.491576 -3.775810 -0.213472 +v 1.370737 -3.793972 -0.623123 +v 1.138849 -3.828826 -0.982291 +v 0.814699 -3.877548 -1.261880 +v 0.424547 -3.936189 -1.439240 +v 0.424546 -4.063811 1.439240 +v 0.814699 -4.122453 1.261880 +v 1.138849 -4.171175 0.982291 +v 1.370737 -4.206028 0.623122 +v 1.491575 -4.224191 0.213472 +v 1.491575 -4.224191 -0.213472 +v 1.370737 -4.206028 -0.623123 +v 1.138849 -4.171175 -0.982291 +v 0.814699 -4.122453 -1.261880 +v 0.424547 -4.063811 -1.439240 +v 0.386824 -4.185764 1.439240 +v 0.742309 -4.356478 1.261880 +v 1.037657 -4.498313 0.982291 +v 1.248941 -4.599777 0.623122 +v 1.359042 -4.652651 0.213472 +v 1.359042 -4.652651 -0.213472 +v 1.248941 -4.599777 -0.623123 +v 1.037657 -4.498313 -0.982291 +v 0.742309 -4.356478 -1.261880 +v 0.386824 -4.185764 -1.439240 +v 0.314730 -4.291210 1.439240 +v 0.603962 -4.558829 1.261880 +v 0.844265 -4.781174 0.982291 +v 1.016171 -4.940233 0.623122 +v 1.105752 -5.023120 0.213472 +v 1.105752 -5.023120 -0.213472 +v 1.016171 -4.940233 -0.623123 +v 0.844265 -4.781174 -0.982291 +v 0.603962 -4.558829 -1.261880 +v 0.314730 -4.291210 -1.439240 +v 0.214671 -4.370781 1.439240 +v 0.411950 -4.711525 1.261880 +v 0.575856 -4.994625 0.982291 +v 0.693109 -5.197145 0.623122 +v 0.754211 -5.302681 0.213472 +v 0.754211 -5.302681 -0.213472 +v 0.693109 -5.197145 -0.623123 +v 0.575856 -4.994624 -0.982291 +v 0.411950 -4.711525 -1.261880 +v 0.214671 -4.370781 -1.439240 +v 0.095537 -4.417407 1.439240 +v 0.183335 -4.800999 1.261880 +v 0.256280 -5.119698 0.982291 +v 0.308462 -5.347686 0.623122 +v 0.335655 -5.466493 0.213472 +v 0.335655 -5.466493 -0.213472 +v 0.308462 -5.347686 -0.623123 +v 0.256280 -5.119698 -0.982291 +v 0.183335 -4.800999 -1.261880 +v 0.095537 -4.417408 -1.439240 +v -0.032085 -4.426944 1.439240 +v -0.061571 -4.819301 1.261880 +v -0.086068 -5.145282 0.982291 +v -0.103593 -5.378479 0.623122 +v -0.112726 -5.500000 0.213472 +v -0.112726 -5.500000 -0.213472 +v -0.103593 -5.378479 -0.623123 +v -0.086068 -5.145282 -0.982291 +v -0.061571 -4.819301 -1.261880 +v -0.032085 -4.426945 -1.439240 +v -0.156857 -4.398546 1.439240 +v -0.301005 -4.764804 1.261880 +v -0.420769 -5.069102 0.982291 +v -0.506444 -5.286788 0.623122 +v -0.551090 -5.400226 0.213472 +v -0.551090 -5.400226 -0.213472 +v -0.506444 -5.286788 -0.623123 +v -0.420769 -5.069102 -0.982291 +v -0.301005 -4.764804 -1.261880 +v -0.156857 -4.398546 -1.439240 +v -0.267691 -4.334734 1.439240 +v -0.513695 -4.642351 1.261880 +v -0.718082 -4.897928 0.982291 +v -0.864295 -5.080760 0.623122 +v -0.940488 -5.176035 0.213472 +v -0.940488 -5.176035 -0.213472 +v -0.864295 -5.080760 -0.623123 +v -0.718082 -4.897928 -0.982291 +v -0.513695 -4.642351 -1.261880 +v -0.267691 -4.334734 -1.439240 +v -0.354739 -4.241180 1.439240 +v -0.680740 -4.462822 1.261880 +v -0.951591 -4.646969 0.982291 +v -1.145349 -4.778702 0.623122 +v -1.246319 -4.847349 0.213472 +v -1.246319 -4.847349 -0.213472 +v -1.145349 -4.778702 -0.623123 +v -0.951591 -4.646969 -0.982291 +v -0.680740 -4.462822 -1.261880 +v -0.354739 -4.241180 -1.439240 +v -0.410268 -4.126197 1.439240 +v -0.787298 -4.242170 1.261880 +v -1.100546 -4.338524 0.982291 +v -1.324635 -4.407453 0.623122 +v -1.441409 -4.443372 0.213472 +v -1.441409 -4.443372 -0.213472 +v -1.324635 -4.407453 -0.623123 +v -1.100546 -4.338524 -0.982291 +v -0.787298 -4.242170 -1.261880 +v -0.410268 -4.126197 -1.439240 +# 464 vertices, 0 vertices normals + +f 10 9 19 +f 10 19 20 +f 9 8 18 +f 9 18 19 +f 8 7 17 +f 8 17 18 +f 7 6 16 +f 7 16 17 +f 6 5 15 +f 6 15 16 +f 5 4 14 +f 5 14 15 +f 4 3 13 +f 4 13 14 +f 3 2 12 +f 3 12 13 +f 2 1 11 +f 2 11 12 +f 20 19 29 +f 20 29 30 +f 19 18 28 +f 19 28 29 +f 18 17 27 +f 18 27 28 +f 17 16 26 +f 17 26 27 +f 16 15 25 +f 16 25 26 +f 15 14 24 +f 15 24 25 +f 14 13 23 +f 14 23 24 +f 13 12 22 +f 13 22 23 +f 12 11 21 +f 12 21 22 +f 30 29 39 +f 30 39 40 +f 29 28 38 +f 29 38 39 +f 28 27 37 +f 28 37 38 +f 27 26 36 +f 27 36 37 +f 26 25 35 +f 26 35 36 +f 25 24 34 +f 25 34 35 +f 24 23 33 +f 24 33 34 +f 23 22 32 +f 23 32 33 +f 22 21 31 +f 22 31 32 +f 40 39 49 +f 40 49 50 +f 39 38 48 +f 39 48 49 +f 38 37 47 +f 38 47 48 +f 37 36 46 +f 37 46 47 +f 36 35 45 +f 36 45 46 +f 35 34 44 +f 35 44 45 +f 34 33 43 +f 34 43 44 +f 33 32 42 +f 33 42 43 +f 32 31 41 +f 32 41 42 +f 50 49 59 +f 50 59 60 +f 49 48 58 +f 49 58 59 +f 48 47 57 +f 48 57 58 +f 47 46 56 +f 47 56 57 +f 46 45 55 +f 46 55 56 +f 45 44 54 +f 45 54 55 +f 44 43 53 +f 44 53 54 +f 43 42 52 +f 43 52 53 +f 42 41 51 +f 42 51 52 +f 60 59 69 +f 60 69 70 +f 59 58 68 +f 59 68 69 +f 58 57 67 +f 58 67 68 +f 57 56 66 +f 57 66 67 +f 56 55 65 +f 56 65 66 +f 55 54 64 +f 55 64 65 +f 54 53 63 +f 54 63 64 +f 53 52 62 +f 53 62 63 +f 52 51 61 +f 52 61 62 +f 70 69 79 +f 70 79 80 +f 69 68 78 +f 69 78 79 +f 68 67 77 +f 68 77 78 +f 67 66 76 +f 67 76 77 +f 66 65 75 +f 66 75 76 +f 65 64 74 +f 65 74 75 +f 64 63 73 +f 64 73 74 +f 63 62 72 +f 63 72 73 +f 62 61 71 +f 62 71 72 +f 80 79 90 +f 80 90 91 +f 79 78 89 +f 79 89 90 +f 78 77 88 +f 78 88 89 +f 77 76 87 +f 77 87 88 +f 76 75 86 +f 76 86 87 +f 75 74 85 +f 75 85 86 +f 74 73 84 +f 74 84 85 +f 73 72 83 +f 73 83 84 +f 72 71 82 +f 72 82 83 +f 91 90 101 +f 91 101 102 +f 90 89 100 +f 90 100 101 +f 89 88 99 +f 89 99 100 +f 88 87 98 +f 88 98 99 +f 87 86 97 +f 87 97 98 +f 86 85 96 +f 86 96 97 +f 85 84 95 +f 85 95 96 +f 84 83 94 +f 84 94 95 +f 83 82 93 +f 83 93 94 +f 102 101 111 +f 102 111 112 +f 101 100 110 +f 101 110 111 +f 100 99 109 +f 100 109 110 +f 99 98 108 +f 99 108 109 +f 98 97 107 +f 98 107 108 +f 97 96 106 +f 97 106 107 +f 96 95 105 +f 96 105 106 +f 95 94 104 +f 95 104 105 +f 94 93 103 +f 94 103 104 +f 112 111 121 +f 112 121 122 +f 111 110 120 +f 111 120 121 +f 110 109 119 +f 110 119 120 +f 109 108 118 +f 109 118 119 +f 108 107 117 +f 108 117 118 +f 107 106 116 +f 107 116 117 +f 106 105 115 +f 106 115 116 +f 105 104 114 +f 105 114 115 +f 104 103 113 +f 104 113 114 +f 122 121 131 +f 122 131 132 +f 121 120 130 +f 121 130 131 +f 120 119 129 +f 120 129 130 +f 119 118 128 +f 119 128 129 +f 118 117 127 +f 118 127 128 +f 117 116 126 +f 117 126 127 +f 116 115 125 +f 116 125 126 +f 115 114 124 +f 115 124 125 +f 114 113 123 +f 114 123 124 +f 132 131 141 +f 132 141 142 +f 131 130 140 +f 131 140 141 +f 130 129 139 +f 130 139 140 +f 129 128 138 +f 129 138 139 +f 128 127 137 +f 128 137 138 +f 127 126 136 +f 127 136 137 +f 126 125 135 +f 126 135 136 +f 125 124 134 +f 125 134 135 +f 124 123 133 +f 124 133 134 +f 142 141 151 +f 142 151 152 +f 141 140 150 +f 141 150 151 +f 140 139 149 +f 140 149 150 +f 139 138 148 +f 139 148 149 +f 138 137 147 +f 138 147 148 +f 137 136 146 +f 137 146 147 +f 136 135 145 +f 136 145 146 +f 135 134 144 +f 135 144 145 +f 134 133 143 +f 134 143 144 +f 152 151 161 +f 152 161 162 +f 151 150 160 +f 151 160 161 +f 150 149 159 +f 150 159 160 +f 149 148 158 +f 149 158 159 +f 148 147 157 +f 148 157 158 +f 147 146 156 +f 147 156 157 +f 146 145 155 +f 146 155 156 +f 145 144 154 +f 145 154 155 +f 144 143 153 +f 144 153 154 +f 162 161 171 +f 162 171 172 +f 161 160 170 +f 161 170 171 +f 160 159 169 +f 160 169 170 +f 159 158 168 +f 159 168 169 +f 158 157 167 +f 158 167 168 +f 157 156 166 +f 157 166 167 +f 156 155 165 +f 156 165 166 +f 155 154 164 +f 155 164 165 +f 154 153 163 +f 154 163 164 +f 172 171 181 +f 172 181 182 +f 171 170 180 +f 171 180 181 +f 170 169 179 +f 170 179 180 +f 169 168 178 +f 169 178 179 +f 168 167 177 +f 168 177 178 +f 167 166 176 +f 167 176 177 +f 166 165 175 +f 166 175 176 +f 165 164 174 +f 165 174 175 +f 164 163 173 +f 164 173 174 +f 182 181 191 +f 182 191 192 +f 181 180 190 +f 181 190 191 +f 180 179 189 +f 180 189 190 +f 179 178 188 +f 179 188 189 +f 178 177 187 +f 178 187 188 +f 177 176 186 +f 177 186 187 +f 176 175 185 +f 176 185 186 +f 175 174 184 +f 175 184 185 +f 174 173 183 +f 174 183 184 +f 192 191 201 +f 192 201 202 +f 191 190 200 +f 191 200 201 +f 190 189 199 +f 190 199 200 +f 189 188 198 +f 189 198 199 +f 188 187 197 +f 188 197 198 +f 187 186 196 +f 187 196 197 +f 186 185 195 +f 186 195 196 +f 185 184 194 +f 185 194 195 +f 184 183 193 +f 184 193 194 +f 202 201 211 +f 202 211 212 +f 201 200 210 +f 201 210 211 +f 200 199 209 +f 200 209 210 +f 199 198 208 +f 199 208 209 +f 198 197 207 +f 198 207 208 +f 197 196 206 +f 197 206 207 +f 196 195 205 +f 196 205 206 +f 195 194 204 +f 195 204 205 +f 194 193 203 +f 194 203 204 +f 92 10 20 +f 1 81 11 +f 92 20 30 +f 11 81 21 +f 92 30 40 +f 21 81 31 +f 92 40 50 +f 31 81 41 +f 92 50 60 +f 41 81 51 +f 92 60 70 +f 51 81 61 +f 92 70 80 +f 61 81 71 +f 92 80 91 +f 71 81 82 +f 92 91 102 +f 82 81 93 +f 92 102 112 +f 93 81 103 +f 92 112 122 +f 103 81 113 +f 92 122 132 +f 113 81 123 +f 92 132 142 +f 123 81 133 +f 92 142 152 +f 133 81 143 +f 92 152 162 +f 143 81 153 +f 92 162 172 +f 153 81 163 +f 92 172 182 +f 163 81 173 +f 92 182 192 +f 173 81 183 +f 92 192 202 +f 183 81 193 +f 92 202 212 +f 193 81 203 +f 92 212 10 +f 212 211 9 +f 212 9 10 +f 211 210 8 +f 211 8 9 +f 210 209 7 +f 210 7 8 +f 209 208 6 +f 209 6 7 +f 208 207 5 +f 208 5 6 +f 207 206 4 +f 207 4 5 +f 206 205 3 +f 206 3 4 +f 205 204 2 +f 205 2 3 +f 204 203 1 +f 204 1 2 +f 203 81 1 +f 213 214 216 +f 213 216 215 +f 215 216 218 +f 215 218 217 +f 217 218 220 +f 217 220 219 +f 219 220 222 +f 219 222 221 +f 221 222 224 +f 221 224 223 +f 223 224 226 +f 223 226 225 +f 225 226 228 +f 225 228 227 +f 227 228 230 +f 227 230 229 +f 229 230 232 +f 229 232 231 +f 231 232 234 +f 231 234 233 +f 233 234 236 +f 233 236 235 +f 235 236 238 +f 235 238 237 +f 237 238 240 +f 237 240 239 +f 239 240 242 +f 239 242 241 +f 241 242 244 +f 241 244 243 +f 243 244 246 +f 243 246 245 +f 245 246 248 +f 245 248 247 +f 247 248 250 +f 247 250 249 +f 216 214 252 +f 216 252 250 +f 216 250 248 +f 216 248 246 +f 216 246 244 +f 216 244 242 +f 216 242 240 +f 216 240 238 +f 216 238 236 +f 216 236 234 +f 216 234 232 +f 216 232 230 +f 216 230 228 +f 216 228 226 +f 216 226 224 +f 216 224 222 +f 216 222 220 +f 216 220 218 +f 251 252 214 +f 251 214 213 +f 249 250 252 +f 249 252 251 +f 213 215 217 +f 213 217 219 +f 213 219 221 +f 213 221 223 +f 213 223 225 +f 213 225 227 +f 213 227 229 +f 213 229 231 +f 213 231 233 +f 213 233 235 +f 213 235 237 +f 213 237 239 +f 213 239 241 +f 213 241 243 +f 213 243 245 +f 213 245 247 +f 213 247 249 +f 213 249 251 +f 262 261 271 +f 262 271 272 +f 261 260 270 +f 261 270 271 +f 260 259 269 +f 260 269 270 +f 259 258 268 +f 259 268 269 +f 258 257 267 +f 258 267 268 +f 257 256 266 +f 257 266 267 +f 256 255 265 +f 256 265 266 +f 255 254 264 +f 255 264 265 +f 254 253 263 +f 254 263 264 +f 272 271 281 +f 272 281 282 +f 271 270 280 +f 271 280 281 +f 270 269 279 +f 270 279 280 +f 269 268 278 +f 269 278 279 +f 268 267 277 +f 268 277 278 +f 267 266 276 +f 267 276 277 +f 266 265 275 +f 266 275 276 +f 265 264 274 +f 265 274 275 +f 264 263 273 +f 264 273 274 +f 282 281 291 +f 282 291 292 +f 281 280 290 +f 281 290 291 +f 280 279 289 +f 280 289 290 +f 279 278 288 +f 279 288 289 +f 278 277 287 +f 278 287 288 +f 277 276 286 +f 277 286 287 +f 276 275 285 +f 276 285 286 +f 275 274 284 +f 275 284 285 +f 274 273 283 +f 274 283 284 +f 292 291 301 +f 292 301 302 +f 291 290 300 +f 291 300 301 +f 290 289 299 +f 290 299 300 +f 289 288 298 +f 289 298 299 +f 288 287 297 +f 288 297 298 +f 287 286 296 +f 287 296 297 +f 286 285 295 +f 286 295 296 +f 285 284 294 +f 285 294 295 +f 284 283 293 +f 284 293 294 +f 302 301 311 +f 302 311 312 +f 301 300 310 +f 301 310 311 +f 300 299 309 +f 300 309 310 +f 299 298 308 +f 299 308 309 +f 298 297 307 +f 298 307 308 +f 297 296 306 +f 297 306 307 +f 296 295 305 +f 296 305 306 +f 295 294 304 +f 295 304 305 +f 294 293 303 +f 294 303 304 +f 312 311 321 +f 312 321 322 +f 311 310 320 +f 311 320 321 +f 310 309 319 +f 310 319 320 +f 309 308 318 +f 309 318 319 +f 308 307 317 +f 308 317 318 +f 307 306 316 +f 307 316 317 +f 306 305 315 +f 306 315 316 +f 305 304 314 +f 305 314 315 +f 304 303 313 +f 304 313 314 +f 322 321 331 +f 322 331 332 +f 321 320 330 +f 321 330 331 +f 320 319 329 +f 320 329 330 +f 319 318 328 +f 319 328 329 +f 318 317 327 +f 318 327 328 +f 317 316 326 +f 317 326 327 +f 316 315 325 +f 316 325 326 +f 315 314 324 +f 315 324 325 +f 314 313 323 +f 314 323 324 +f 332 331 342 +f 332 342 343 +f 331 330 341 +f 331 341 342 +f 330 329 340 +f 330 340 341 +f 329 328 339 +f 329 339 340 +f 328 327 338 +f 328 338 339 +f 327 326 337 +f 327 337 338 +f 326 325 336 +f 326 336 337 +f 325 324 335 +f 325 335 336 +f 324 323 334 +f 324 334 335 +f 343 342 353 +f 343 353 354 +f 342 341 352 +f 342 352 353 +f 341 340 351 +f 341 351 352 +f 340 339 350 +f 340 350 351 +f 339 338 349 +f 339 349 350 +f 338 337 348 +f 338 348 349 +f 337 336 347 +f 337 347 348 +f 336 335 346 +f 336 346 347 +f 335 334 345 +f 335 345 346 +f 354 353 363 +f 354 363 364 +f 353 352 362 +f 353 362 363 +f 352 351 361 +f 352 361 362 +f 351 350 360 +f 351 360 361 +f 350 349 359 +f 350 359 360 +f 349 348 358 +f 349 358 359 +f 348 347 357 +f 348 357 358 +f 347 346 356 +f 347 356 357 +f 346 345 355 +f 346 355 356 +f 364 363 373 +f 364 373 374 +f 363 362 372 +f 363 372 373 +f 362 361 371 +f 362 371 372 +f 361 360 370 +f 361 370 371 +f 360 359 369 +f 360 369 370 +f 359 358 368 +f 359 368 369 +f 358 357 367 +f 358 367 368 +f 357 356 366 +f 357 366 367 +f 356 355 365 +f 356 365 366 +f 374 373 383 +f 374 383 384 +f 373 372 382 +f 373 382 383 +f 372 371 381 +f 372 381 382 +f 371 370 380 +f 371 380 381 +f 370 369 379 +f 370 379 380 +f 369 368 378 +f 369 378 379 +f 368 367 377 +f 368 377 378 +f 367 366 376 +f 367 376 377 +f 366 365 375 +f 366 375 376 +f 384 383 393 +f 384 393 394 +f 383 382 392 +f 383 392 393 +f 382 381 391 +f 382 391 392 +f 381 380 390 +f 381 390 391 +f 380 379 389 +f 380 389 390 +f 379 378 388 +f 379 388 389 +f 378 377 387 +f 378 387 388 +f 377 376 386 +f 377 386 387 +f 376 375 385 +f 376 385 386 +f 394 393 403 +f 394 403 404 +f 393 392 402 +f 393 402 403 +f 392 391 401 +f 392 401 402 +f 391 390 400 +f 391 400 401 +f 390 389 399 +f 390 399 400 +f 389 388 398 +f 389 398 399 +f 388 387 397 +f 388 397 398 +f 387 386 396 +f 387 396 397 +f 386 385 395 +f 386 395 396 +f 404 403 413 +f 404 413 414 +f 403 402 412 +f 403 412 413 +f 402 401 411 +f 402 411 412 +f 401 400 410 +f 401 410 411 +f 400 399 409 +f 400 409 410 +f 399 398 408 +f 399 408 409 +f 398 397 407 +f 398 407 408 +f 397 396 406 +f 397 406 407 +f 396 395 405 +f 396 405 406 +f 414 413 423 +f 414 423 424 +f 413 412 422 +f 413 422 423 +f 412 411 421 +f 412 421 422 +f 411 410 420 +f 411 420 421 +f 410 409 419 +f 410 419 420 +f 409 408 418 +f 409 418 419 +f 408 407 417 +f 408 417 418 +f 407 406 416 +f 407 416 417 +f 406 405 415 +f 406 415 416 +f 424 423 433 +f 424 433 434 +f 423 422 432 +f 423 432 433 +f 422 421 431 +f 422 431 432 +f 421 420 430 +f 421 430 431 +f 420 419 429 +f 420 429 430 +f 419 418 428 +f 419 428 429 +f 418 417 427 +f 418 427 428 +f 417 416 426 +f 417 426 427 +f 416 415 425 +f 416 425 426 +f 434 433 443 +f 434 443 444 +f 433 432 442 +f 433 442 443 +f 432 431 441 +f 432 441 442 +f 431 430 440 +f 431 440 441 +f 430 429 439 +f 430 439 440 +f 429 428 438 +f 429 438 439 +f 428 427 437 +f 428 437 438 +f 427 426 436 +f 427 436 437 +f 426 425 435 +f 426 435 436 +f 444 443 453 +f 444 453 454 +f 443 442 452 +f 443 452 453 +f 442 441 451 +f 442 451 452 +f 441 440 450 +f 441 450 451 +f 440 439 449 +f 440 449 450 +f 439 438 448 +f 439 448 449 +f 438 437 447 +f 438 447 448 +f 437 436 446 +f 437 446 447 +f 436 435 445 +f 436 445 446 +f 454 453 463 +f 454 463 464 +f 453 452 462 +f 453 462 463 +f 452 451 461 +f 452 461 462 +f 451 450 460 +f 451 460 461 +f 450 449 459 +f 450 459 460 +f 449 448 458 +f 449 458 459 +f 448 447 457 +f 448 457 458 +f 447 446 456 +f 447 456 457 +f 446 445 455 +f 446 455 456 +f 344 262 272 +f 253 333 263 +f 344 272 282 +f 263 333 273 +f 344 282 292 +f 273 333 283 +f 344 292 302 +f 283 333 293 +f 344 302 312 +f 293 333 303 +f 344 312 322 +f 303 333 313 +f 344 322 332 +f 313 333 323 +f 344 332 343 +f 323 333 334 +f 344 343 354 +f 334 333 345 +f 344 354 364 +f 345 333 355 +f 344 364 374 +f 355 333 365 +f 344 374 384 +f 365 333 375 +f 344 384 394 +f 375 333 385 +f 344 394 404 +f 385 333 395 +f 344 404 414 +f 395 333 405 +f 344 414 424 +f 405 333 415 +f 344 424 434 +f 415 333 425 +f 344 434 444 +f 425 333 435 +f 344 444 454 +f 435 333 445 +f 344 454 464 +f 445 333 455 +f 344 464 262 +f 464 463 261 +f 464 261 262 +f 463 462 260 +f 463 260 261 +f 462 461 259 +f 462 259 260 +f 461 460 258 +f 461 258 259 +f 460 459 257 +f 460 257 258 +f 459 458 256 +f 459 256 257 +f 458 457 255 +f 458 255 256 +f 457 456 254 +f 457 254 255 +f 456 455 253 +f 456 253 254 +f 455 333 253 +# 916 faces, 0 coords texture + +# End of File diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index ab4c1b34..a764b421 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -80,8 +80,12 @@ const ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisi mProxyCollisionShapes = proxyShape; } + // Compute the world-space AABB of the new collision shape + AABB aabb; + newCollisionShape->computeAABB(aabb, mTransform * transform); + // Notify the collision detection about this new collision shape - mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape); + mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape, aabb); mNbCollisionShapes++; @@ -180,7 +184,7 @@ void CollisionBody::updateBroadPhaseState() const { // Recompute the world-space AABB of the collision shape AABB aabb; - shape->getCollisionShape()->computeAABB(aabb, mTransform); + shape->getCollisionShape()->computeAABB(aabb, mTransform *shape->getLocalToBodyTransform()); // Update the broad-phase state for the proxy collision shape mWorld.mCollisionDetection.updateProxyCollisionShape(shape, aabb); diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index ce0e271b..257b8d94 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -136,8 +136,7 @@ void RigidBody::removeJointFromJointsList(MemoryAllocator& memoryAllocator, cons /// parameter is the transformation that transform the local-space of the collision shape into /// the local-space of the body. By default, the second parameter is the identity transform. const ProxyShape* RigidBody::addCollisionShape(const CollisionShape& collisionShape, - decimal mass, - const Transform& transform) { + decimal mass, const Transform& transform) { assert(mass > decimal(0.0)); @@ -157,8 +156,12 @@ const ProxyShape* RigidBody::addCollisionShape(const CollisionShape& collisionSh mProxyCollisionShapes = proxyShape; } + // Compute the world-space AABB of the new collision shape + AABB aabb; + newCollisionShape->computeAABB(aabb, mTransform * transform); + // Notify the collision detection about this new collision shape - mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape); + mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape, aabb); mNbCollisionShapes++; diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index 47bfc913..aeae3fd8 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -88,13 +88,33 @@ void CollisionDetection::computeNarrowPhase() { // For each possible collision pair of bodies map::iterator it; - for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); it++) { + for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) { ContactPointInfo* contactInfo = NULL; OverlappingPair* pair = it->second; ProxyShape* shape1 = pair->getShape1(); ProxyShape* shape2 = pair->getShape2(); + + assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID); + + // Check that the two shapes are overlapping. If the shapes are not overlapping + // anymore, we remove the overlapping pair. + if (!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) { + + std::map::iterator itToRemove = it; + ++it; + + // Destroy the overlapping pair + itToRemove->second->OverlappingPair::~OverlappingPair(); + mWorld->mMemoryAllocator.release(itToRemove->second, sizeof(OverlappingPair)); + mOverlappingPairs.erase(itToRemove); + continue; + } + else { + ++it; + } + CollisionBody* const body1 = shape1->getBody(); CollisionBody* const body2 = shape2->getBody(); @@ -119,8 +139,6 @@ void CollisionDetection::computeNarrowPhase() { // Use the narrow-phase collision detection algorithm to check // if there really is a collision - const Transform transform1 = body1->getTransform() * shape1->getLocalToBodyTransform(); - const Transform transform2 = body2->getTransform() * shape2->getLocalToBodyTransform(); if (narrowPhaseAlgorithm.testCollision(shape1, shape2, contactInfo)) { assert(contactInfo != NULL); @@ -141,9 +159,14 @@ void CollisionDetection::computeNarrowPhase() { } // Allow the broadphase to notify the collision detection about an overlapping pair. -/// This method is called by a broad-phase collision detection algorithm +/// This method is called by the broad-phase collision detection algorithm void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2) { + assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID); + + // If the two proxy collision shapes are from the same body, skip it + if (shape1->getBody()->getID() == shape2->getBody()->getID()) return; + // Compute the overlapping pair ID overlappingpairid pairID = OverlappingPair::computeID(shape1, shape2); @@ -157,28 +180,6 @@ void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, Pro std::pair::iterator, bool> check = mOverlappingPairs.insert(make_pair(pairID, newPair)); assert(check.second); - - /* TODO : DELETE THIS - // Get the pair of body index - bodyindexpair indexPair = addedPair->getBodiesIndexPair(); - - // If the overlapping pair already exists, we don't do anything - if (mOverlappingPairs.count(indexPair) > 0) return; - - // Create the corresponding broad-phase pair object - BroadPhasePair* broadPhasePair = new (mWorld->mMemoryAllocator.allocate(sizeof(BroadPhasePair))) - BroadPhasePair(addedPair->body1, addedPair->body2); - assert(broadPhasePair != NULL); - - // Add the pair into the set of overlapping pairs (if not there yet) - pair::iterator, bool> check = mOverlappingPairs.insert( - make_pair(indexPair, - broadPhasePair)); - assert(check.second); - - // Notify the world about the new broad-phase overlapping pair - mWorld->notifyAddedOverlappingPair(broadPhasePair); - */ } // Remove a body from the collision detection diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index 790b2286..0b64e5e9 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -121,7 +121,7 @@ class CollisionDetection { ~CollisionDetection(); /// Add a proxy collision shape to the collision detection - void addProxyCollisionShape(ProxyShape* proxyShape); + void addProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb); /// Remove a proxy collision shape from the collision detection void removeProxyCollisionShape(ProxyShape* proxyShape); @@ -162,10 +162,11 @@ inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm( } // Add a body to the collision detection -inline void CollisionDetection::addProxyCollisionShape(ProxyShape* proxyShape) { +inline void CollisionDetection::addProxyCollisionShape(ProxyShape* proxyShape, + const AABB& aabb) { // Add the body to the broad-phase - mBroadPhaseAlgorithm.addProxyCollisionShape(proxyShape); + mBroadPhaseAlgorithm.addProxyCollisionShape(proxyShape, aabb); mIsCollisionShapesAdded = true; } diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.cpp b/src/collision/broadphase/BroadPhaseAlgorithm.cpp index 2b554ae9..f6e88301 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.cpp +++ b/src/collision/broadphase/BroadPhaseAlgorithm.cpp @@ -38,11 +38,11 @@ BroadPhaseAlgorithm::BroadPhaseAlgorithm(CollisionDetection& collisionDetection) // Allocate memory for the array of non-static bodies IDs mMovedShapes = (int*) malloc(mNbAllocatedMovedShapes * sizeof(int)); - assert(mMovedShapes); + assert(mMovedShapes != NULL); // Allocate memory for the array of potential overlapping pairs mPotentialPairs = (BroadPair*) malloc(mNbAllocatedPotentialPairs * sizeof(BroadPair)); - assert(mPotentialPairs); + assert(mPotentialPairs != NULL); } // Destructor @@ -64,12 +64,14 @@ void BroadPhaseAlgorithm::addMovedCollisionShape(int broadPhaseID) { mNbAllocatedMovedShapes *= 2; int* oldArray = mMovedShapes; mMovedShapes = (int*) malloc(mNbAllocatedMovedShapes * sizeof(int)); - assert(mMovedShapes); + assert(mMovedShapes != NULL); memcpy(mMovedShapes, oldArray, mNbMovedShapes * sizeof(int)); free(oldArray); } // Store the broad-phase ID into the array of bodies that have moved + assert(mNbMovedShapes < mNbAllocatedMovedShapes); + assert(mMovedShapes != NULL); mMovedShapes[mNbMovedShapes] = broadPhaseID; mNbMovedShapes++; } @@ -88,7 +90,7 @@ void BroadPhaseAlgorithm::removeMovedCollisionShape(int broadPhaseID) { mNbAllocatedMovedShapes /= 2; int* oldArray = mMovedShapes; mMovedShapes = (int*) malloc(mNbAllocatedMovedShapes * sizeof(int)); - assert(mMovedShapes); + assert(mMovedShapes != NULL); uint nbElements = 0; for (uint i=0; imBroadPhaseID); + const AABB& aabb2 = mDynamicAABBTree.getFatAABB(shape2->mBroadPhaseID); + + // Check if the two AABBs are overlapping + return aabb1.testCollision(aabb2); +} + } #endif diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index 971bd788..305aeadf 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -106,45 +106,24 @@ void DynamicAABBTree::releaseNode(int nodeID) { assert(mNbNodes > 0); assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); + assert(mNodes[nodeID].height >= 0); mNodes[nodeID].nextNodeID = mFreeNodeID; mNodes[nodeID].height = -1; mFreeNodeID = nodeID; mNbNodes--; - - // Deallocate nodes memory here if the number of allocated nodes is large - // compared to the number of nodes in the tree - if ((mNbNodes < mNbAllocatedNodes / 4) && mNbNodes > 8) { - - // Allocate less nodes in the tree - mNbAllocatedNodes /= 2; - TreeNode* oldNodes = mNodes; - mNodes = (TreeNode*) malloc(mNbAllocatedNodes * sizeof(TreeNode)); - assert(mNodes); - memcpy(mNodes, oldNodes, mNbNodes * sizeof(TreeNode)); - free(oldNodes); - - // Initialize the allocated nodes - for (int i=mNbNodes; imBroadPhaseID = nodeID; @@ -179,6 +159,7 @@ bool DynamicAABBTree::updateObject(int nodeID, const AABB& newAABB) { assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); assert(mNodes[nodeID].isLeaf()); + assert(mNodes[nodeID].height >= 0); // If the new AABB is still inside the fat AABB of the node if (mNodes[nodeID].aabb.contains(newAABB)) { @@ -212,6 +193,8 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { return; } + assert(mRootNodeID != TreeNode::NULL_TREE_NODE); + // Find the best sibling node for the new node AABB newNodeAABB = mNodes[nodeID].aabb; int currentNodeID = mRootNodeID; @@ -278,6 +261,7 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { mNodes[newParentNode].proxyShape = NULL; mNodes[newParentNode].aabb.mergeTwoAABBs(mNodes[siblingNode].aabb, newNodeAABB); mNodes[newParentNode].height = mNodes[siblingNode].height + 1; + assert(mNodes[newParentNode].height > 0); // If the sibling node was not the root node if (oldParentNode != TreeNode::NULL_TREE_NODE) { @@ -287,6 +271,10 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { else { mNodes[oldParentNode].rightChildID = newParentNode; } + mNodes[newParentNode].leftChildID = siblingNode; + mNodes[newParentNode].rightChildID = nodeID; + mNodes[siblingNode].parentID = newParentNode; + mNodes[nodeID].parentID = newParentNode; } else { // If the sibling node was the root node mNodes[newParentNode].leftChildID = siblingNode; @@ -302,6 +290,7 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { // Balance the sub-tree of the current node if it is not balanced currentNodeID = balanceSubTreeAtNode(currentNodeID); + assert(mNodes[nodeID].isLeaf()); int leftChild = mNodes[currentNodeID].leftChildID; int rightChild = mNodes[currentNodeID].rightChildID; @@ -311,18 +300,25 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { // Recompute the height of the node in the tree mNodes[currentNodeID].height = std::max(mNodes[leftChild].height, mNodes[rightChild].height) + 1; + assert(mNodes[currentNodeID].height > 0); // Recompute the AABB of the node mNodes[currentNodeID].aabb.mergeTwoAABBs(mNodes[leftChild].aabb, mNodes[rightChild].aabb); currentNodeID = mNodes[currentNodeID].parentID; } + + assert(mNodes[nodeID].isLeaf()); + + // Check the structure of the tree + check(); } // Remove a leaf node from the tree void DynamicAABBTree::removeLeafNode(int nodeID) { assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); + assert(mNodes[nodeID].isLeaf()); // If we are removing the root node (root node is a leaf in this case) if (mRootNodeID == nodeID) { @@ -371,18 +367,21 @@ void DynamicAABBTree::removeLeafNode(int nodeID) { mNodes[rightChildID].aabb); mNodes[currentNodeID].height = std::max(mNodes[leftChildID].height, mNodes[rightChildID].height) + 1; + assert(mNodes[currentNodeID].height > 0); currentNodeID = mNodes[currentNodeID].parentID; } - } else { // If the parent of the node to remove is the root node // The sibling node becomes the new root node mRootNodeID = siblingNodeID; mNodes[siblingNodeID].parentID = TreeNode::NULL_TREE_NODE; - releaseNode(nodeID); + releaseNode(parentNodeID); } + + // Check the structure of the tree + check(); } // Balance the sub-tree of a given node using left or right rotations. @@ -453,6 +452,8 @@ int DynamicAABBTree::balanceSubTreeAtNode(int nodeID) { // Recompute the height of node A and C nodeA->height = std::max(nodeB->height, nodeG->height) + 1; nodeC->height = std::max(nodeA->height, nodeF->height) + 1; + assert(nodeA->height > 0); + assert(nodeC->height > 0); } else { // If the right node C was higher than left node B because of node G nodeC->rightChildID = nodeGID; @@ -466,6 +467,8 @@ int DynamicAABBTree::balanceSubTreeAtNode(int nodeID) { // Recompute the height of node A and C nodeA->height = std::max(nodeB->height, nodeF->height) + 1; nodeC->height = std::max(nodeA->height, nodeG->height) + 1; + assert(nodeA->height > 0); + assert(nodeC->height > 0); } // Return the new root of the sub-tree @@ -513,6 +516,8 @@ int DynamicAABBTree::balanceSubTreeAtNode(int nodeID) { // Recompute the height of node A and B nodeA->height = std::max(nodeC->height, nodeG->height) + 1; nodeB->height = std::max(nodeA->height, nodeF->height) + 1; + assert(nodeA->height > 0); + assert(nodeB->height > 0); } else { // If the left node B was higher than right node C because of node G nodeB->rightChildID = nodeGID; @@ -526,6 +531,8 @@ int DynamicAABBTree::balanceSubTreeAtNode(int nodeID) { // Recompute the height of node A and B nodeA->height = std::max(nodeC->height, nodeF->height) + 1; nodeB->height = std::max(nodeA->height, nodeG->height) + 1; + assert(nodeA->height > 0); + assert(nodeB->height > 0); } // Return the new root of the sub-tree @@ -576,3 +583,74 @@ void DynamicAABBTree::reportAllShapesOverlappingWith(int nodeID, const AABB& aab } } } + +// Check if the tree structure is valid (for debugging purpose) +void DynamicAABBTree::check() const { + + // Recursively check each node + checkNode(mRootNodeID); + + int nbFreeNodes = 0; + int freeNodeID = mFreeNodeID; + + // Check the free nodes + while(freeNodeID != TreeNode::NULL_TREE_NODE) { + assert(0 <= freeNodeID && freeNodeID < mNbAllocatedNodes); + freeNodeID = mNodes[freeNodeID].nextNodeID; + nbFreeNodes++; + } + + assert(mNbNodes + nbFreeNodes == mNbAllocatedNodes); +} + +// Check if the node structure is valid (for debugging purpose) +void DynamicAABBTree::checkNode(int nodeID) const { + + if (nodeID == TreeNode::NULL_TREE_NODE) return; + + // If it is the root + if (nodeID == mRootNodeID) { + assert(mNodes[nodeID].parentID == TreeNode::NULL_TREE_NODE); + } + + // Get the children nodes + TreeNode* pNode = mNodes + nodeID; + int leftChild = pNode->leftChildID; + int rightChild = pNode->rightChildID; + + assert(pNode->height >= 0); + assert(pNode->aabb.getVolume() > 0); + + // If the current node is a leaf + if (pNode->isLeaf()) { + + // Check that there are no children + assert(leftChild == TreeNode::NULL_TREE_NODE); + assert(rightChild == TreeNode::NULL_TREE_NODE); + assert(pNode->height == 0); + } + else { + + // Check that the children node IDs are valid + assert(0 <= leftChild && leftChild < mNbAllocatedNodes); + assert(0 <= rightChild && rightChild < mNbAllocatedNodes); + + // Check that the children nodes have the correct parent node + assert(mNodes[leftChild].parentID == nodeID); + assert(mNodes[rightChild].parentID == nodeID); + + // Check the height of node + int height = 1 + std::max(mNodes[leftChild].height, mNodes[rightChild].height); + assert(mNodes[nodeID].height == height); + + // Check the AABB of the node + AABB aabb; + aabb.mergeTwoAABBs(mNodes[leftChild].aabb, mNodes[rightChild].aabb); + assert(aabb.getMin() == mNodes[nodeID].aabb.getMin()); + assert(aabb.getMax() == mNodes[nodeID].aabb.getMax()); + + // Recursively check the children nodes + checkNode(leftChild); + checkNode(rightChild); + } +} diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h index 2488b816..207ebf8a 100644 --- a/src/collision/broadphase/DynamicAABBTree.h +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -123,6 +123,12 @@ class DynamicAABBTree { /// Balance the sub-tree of a given node using left or right rotations. int balanceSubTreeAtNode(int nodeID); + /// Check if the tree structure is valid (for debugging purpose) + void check() const; + + /// Check if the node structure is valid (for debugging purpose) + void checkNode(int nodeID) const; + public: // -------------------- Methods -------------------- // @@ -134,7 +140,7 @@ class DynamicAABBTree { ~DynamicAABBTree(); /// Add an object into the tree - void addObject(ProxyShape* proxyShape); + void addObject(ProxyShape* proxyShape, const AABB& aabb); /// Remove an object from the tree void removeObject(int nodeID);