diff --git a/src/collision/shapes/ConcaveMeshShape.h b/src/collision/shapes/ConcaveMeshShape.h index 76bbddbf..0efbcfeb 100644 --- a/src/collision/shapes/ConcaveMeshShape.h +++ b/src/collision/shapes/ConcaveMeshShape.h @@ -100,10 +100,6 @@ class ConcaveMeshRaycastCallback : public DynamicAABBTreeRaycastCallback { } }; -// TODO : Implement raycasting with this collision shape - -// TODO : Make possible for the user to have a scaling factor on the mesh - // Class ConcaveMeshShape /** * This class represents a concave mesh shape. Note that collision detection diff --git a/src/collision/shapes/ConvexMeshShape.cpp b/src/collision/shapes/ConvexMeshShape.cpp index f33af857..c46881a2 100644 --- a/src/collision/shapes/ConvexMeshShape.cpp +++ b/src/collision/shapes/ConvexMeshShape.cpp @@ -30,7 +30,7 @@ using namespace reactphysics3d; -// Constructor to initialize with a array of 3D vertices. +// Constructor to initialize with an array of 3D vertices. /// This method creates an internal copy of the input vertices. /** * @param arrayVertices Array with the vertices of the convex mesh @@ -58,6 +58,77 @@ ConvexMeshShape::ConvexMeshShape(const decimal* arrayVertices, uint nbVertices, recalculateBounds(); } +// Constructor to initialize with a triangle mesh +/// This method creates an internal copy of the input vertices. +/** + * @param triangleVertexArray Array with the vertices and indices of the vertices and triangles of the mesh + * @param isEdgesInformationUsed True if you want to use edges information for collision detection (faster but requires more memory) + * @param margin Collision margin (in meters) around the collision shape + */ +ConvexMeshShape::ConvexMeshShape(TriangleVertexArray* triangleVertexArray, bool isEdgesInformationUsed, decimal margin) + : ConvexShape(CONVEX_MESH, margin), mMinBounds(0, 0, 0), + mMaxBounds(0, 0, 0), mIsEdgesInformationUsed(isEdgesInformationUsed) { + + TriangleVertexArray::VertexDataType vertexType = triangleVertexArray->getVertexDataType(); + TriangleVertexArray::IndexDataType indexType = triangleVertexArray->getIndexDataType(); + unsigned char* verticesStart = triangleVertexArray->getVerticesStart(); + unsigned char* indicesStart = triangleVertexArray->getIndicesStart(); + int vertexStride = triangleVertexArray->getVerticesStride(); + int indexStride = triangleVertexArray->getIndicesStride(); + + // For each vertex of the mesh + for (int v = 0; v < triangleVertexArray->getNbVertices(); v++) { + + // Get the vertices components of the triangle + if (vertexType == TriangleVertexArray::VERTEX_FLOAT_TYPE) { + const float* vertices = (float*)(verticesStart + v * vertexStride); + + Vector3 vertex(vertices[0], vertices[1], vertices[2] ); + vertex = vertex * mScaling; + mVertices.push_back(vertex); + } + else if (vertexType == TriangleVertexArray::VERTEX_DOUBLE_TYPE) { + const double* vertices = (double*)(verticesStart + v * vertexStride); + + Vector3 vertex(vertices[0], vertices[1], vertices[2] ); + vertex = vertex * mScaling; + mVertices.push_back(vertex); + } + } + + // If we need to use the edges information of the mesh + if (mIsEdgesInformationUsed) { + + // For each triangle of the mesh + for (int triangleIndex=0; triangleIndexgetNbTriangles(); triangleIndex++) { + + void* vertexIndexPointer = (indicesStart + triangleIndex * 3 * indexStride); + + uint vertexIndex[3]; + + // For each vertex of the triangle + for (int k=0; k < 3; k++) { + + // Get the index of the current vertex in the triangle + if (indexType == TriangleVertexArray::INDEX_INTEGER_TYPE) { + vertexIndex[k] = ((uint*)vertexIndexPointer)[k]; + } + else if (indexType == TriangleVertexArray::INDEX_SHORT_TYPE) { + vertexIndex[k] = ((unsigned short*)vertexIndexPointer)[k]; + } + } + + // Add information about the edges + addEdge(vertexIndex[0], vertexIndex[1]); + addEdge(vertexIndex[0], vertexIndex[2]); + addEdge(vertexIndex[1], vertexIndex[2]); + } + } + + mNbVertices = mVertices.size(); + recalculateBounds(); +} + // Constructor. /// If you use this constructor, you will need to set the vertices manually one by one using /// the addVertex() method. diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index 94c1f7a9..13b11ee0 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -30,6 +30,7 @@ #include "ConvexShape.h" #include "engine/CollisionWorld.h" #include "mathematics/mathematics.h" +#include "collision/TriangleMesh.h" #include "collision/narrowphase/GJK/GJKAlgorithm.h" #include #include @@ -64,8 +65,6 @@ class CollisionWorld; */ class ConvexMeshShape : public ConvexShape { - // TODO : Implement method setLocalScaling() here - protected : // -------------------- Attributes -------------------- // @@ -121,10 +120,14 @@ class ConvexMeshShape : public ConvexShape { // -------------------- Methods -------------------- // - /// Constructor to initialize with a array of 3D vertices. + /// Constructor to initialize with an array of 3D vertices. ConvexMeshShape(const decimal* arrayVertices, uint nbVertices, int stride, decimal margin = OBJECT_MARGIN); + /// Constructor to initialize with a triangle vertex array + ConvexMeshShape(TriangleVertexArray* triangleVertexArray, bool isEdgesInformationUsed = true, + decimal margin = OBJECT_MARGIN); + /// Constructor. ConvexMeshShape(decimal margin = OBJECT_MARGIN); @@ -215,9 +218,6 @@ inline void ConvexMeshShape::addVertex(const Vector3& vertex) { */ inline void ConvexMeshShape::addEdge(uint v1, uint v2) { - assert(v1 >= 0); - assert(v2 >= 0); - // If the entry for vertex v1 does not exist in the adjacency list if (mEdgesAdjacencyList.count(v1) == 0) { mEdgesAdjacencyList.insert(std::make_pair(v1, std::set())); diff --git a/src/mathematics/Vector2.h b/src/mathematics/Vector2.h index ee0fe7bc..dfc10b65 100644 --- a/src/mathematics/Vector2.h +++ b/src/mathematics/Vector2.h @@ -132,6 +132,9 @@ struct Vector2 { /// Overloaded operator Vector2& operator=(const Vector2& vector); + /// Overloaded less than operator for ordering to be used inside std::set for instance + bool operator<(const Vector2& vector) const; + /// Return a vector taking the minimum components of two vectors static Vector2 min(const Vector2& vector1, const Vector2& vector2); @@ -313,6 +316,11 @@ inline Vector2& Vector2::operator=(const Vector2& vector) { return *this; } +// Overloaded less than operator for ordering to be used inside std::set for instance +inline bool Vector2::operator<(const Vector2& vector) const { + return (x == vector.x ? y < vector.y : x < vector.x); +} + // Return a vector taking the minimum components of two vectors inline Vector2 Vector2::min(const Vector2& vector1, const Vector2& vector2) { return Vector2(std::min(vector1.x, vector2.x), diff --git a/src/mathematics/Vector3.h b/src/mathematics/Vector3.h index d5a9fb97..4ab37db3 100644 --- a/src/mathematics/Vector3.h +++ b/src/mathematics/Vector3.h @@ -144,6 +144,9 @@ struct Vector3 { /// Overloaded operator Vector3& operator=(const Vector3& vector); + /// Overloaded less than operator for ordering to be used inside std::set for instance + bool operator<(const Vector3& vector) const; + /// Return a vector taking the minimum components of two vectors static Vector3 min(const Vector3& vector1, const Vector3& vector2); @@ -341,6 +344,11 @@ inline Vector3& Vector3::operator=(const Vector3& vector) { return *this; } +// Overloaded less than operator for ordering to be used inside std::set for instance +inline bool Vector3::operator<(const Vector3& vector) const { + return (x == vector.x ? (y == vector.y ? z < vector.z : y < vector.y) : x < vector.x); +} + // Return a vector taking the minimum components of two vectors inline Vector3 Vector3::min(const Vector3& vector1, const Vector3& vector2) { return Vector3(std::min(vector1.x, vector2.x), diff --git a/test/tests/collision/TestPointInside.h b/test/tests/collision/TestPointInside.h index 41774082..07a15edf 100644 --- a/test/tests/collision/TestPointInside.h +++ b/test/tests/collision/TestPointInside.h @@ -131,7 +131,7 @@ class TestPointInside : public Test { mConeShape = new ConeShape(2, 6, 0); mConeProxyShape = mConeBody->addCollisionShape(mConeShape, mShapeTransform); - mConvexMeshShape = new ConvexMeshShape(0); // Box of dimension (2, 3, 4) + mConvexMeshShape = new ConvexMeshShape(0.0); // Box of dimension (2, 3, 4) mConvexMeshShape->addVertex(Vector3(-2, -3, -4)); mConvexMeshShape->addVertex(Vector3(2, -3, -4)); mConvexMeshShape->addVertex(Vector3(2, -3, 4)); @@ -142,7 +142,7 @@ class TestPointInside : public Test { mConvexMeshShape->addVertex(Vector3(-2, 3, 4)); mConvexMeshProxyShape = mConvexMeshBody->addCollisionShape(mConvexMeshShape, mShapeTransform); - mConvexMeshShapeBodyEdgesInfo = new ConvexMeshShape(0); + mConvexMeshShapeBodyEdgesInfo = new ConvexMeshShape(0.0); mConvexMeshShapeBodyEdgesInfo->addVertex(Vector3(-2, -3, -4)); mConvexMeshShapeBodyEdgesInfo->addVertex(Vector3(2, -3, -4)); mConvexMeshShapeBodyEdgesInfo->addVertex(Vector3(2, -3, 4)); diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index f90191d6..fef82cb0 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -207,7 +207,7 @@ class TestRaycast : public Test { mConeShape = new ConeShape(2, 6, 0); mConeProxyShape = mConeBody->addCollisionShape(mConeShape, mShapeTransform); - mConvexMeshShape = new ConvexMeshShape(0); // Box of dimension (2, 3, 4) + mConvexMeshShape = new ConvexMeshShape(0.0); // Box of dimension (2, 3, 4) mConvexMeshShape->addVertex(Vector3(-2, -3, -4)); mConvexMeshShape->addVertex(Vector3(2, -3, -4)); mConvexMeshShape->addVertex(Vector3(2, -3, 4)); @@ -218,7 +218,7 @@ class TestRaycast : public Test { mConvexMeshShape->addVertex(Vector3(-2, 3, 4)); mConvexMeshProxyShape = mConvexMeshBody->addCollisionShape(mConvexMeshShape, mShapeTransform); - mConvexMeshShapeEdgesInfo = new ConvexMeshShape(0); + mConvexMeshShapeEdgesInfo = new ConvexMeshShape(0.0); mConvexMeshShapeEdgesInfo->addVertex(Vector3(-2, -3, -4)); mConvexMeshShapeEdgesInfo->addVertex(Vector3(2, -3, -4)); mConvexMeshShapeEdgesInfo->addVertex(Vector3(2, -3, 4)); diff --git a/testbed/CMakeLists.txt b/testbed/CMakeLists.txt index 544d9a7d..3af78d9e 100644 --- a/testbed/CMakeLists.txt +++ b/testbed/CMakeLists.txt @@ -22,9 +22,6 @@ FILE(COPY "meshes/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/meshes/") # Copy the fonts used for the GUI into the build directory FILE(COPY "imgui/DroidSans.ttf" DESTINATION "${EXECUTABLE_OUTPUT_PATH}") -# Enable C++11 features -SET(CMAKE_CXX_FLAGS "-Wall -std=c++0x") - # Headers INCLUDE_DIRECTORIES("src/" ${GLEW_INCLUDE_PATH} "opengl-framework/src/" "glfw/include/" "common/" "scenes/" "imgui/") @@ -95,5 +92,9 @@ SET(SCENES_SOURCES # Create the executable ADD_EXECUTABLE(testbed ${TESTBED_SOURCES} ${SCENES_SOURCES} ${COMMON_SOURCES} ${IMGUI_SOURCES}) +# Enable C++11 features +set_property(TARGET testbed PROPERTY CXX_STANDARD 11) +set_property(TARGET testbed PROPERTY CXX_STANDARD_REQUIRED ON) + # Link with libraries TARGET_LINK_LIBRARIES(testbed reactphysics3d openglframework glfw ${GLFW_LIBRARIES}) diff --git a/testbed/common/ConvexMesh.cpp b/testbed/common/ConvexMesh.cpp index 1e14483d..6c272d36 100644 --- a/testbed/common/ConvexMesh.cpp +++ b/testbed/common/ConvexMesh.cpp @@ -46,36 +46,17 @@ ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, // Compute the scaling matrix mScalingMatrix = openglframework::Matrix4::identity(); - // Convert the vertices array to the rp3d::decimal type - rp3d::decimal* vertices = new rp3d::decimal[3 * mVertices.size()]; - for (int i=0; i < mVertices.size(); i++) { - vertices[3 * i] = static_cast(mVertices[i].x); - vertices[3 * i + 1] = static_cast(mVertices[i].y); - vertices[3 * i + 2] = static_cast(mVertices[i].z); - } + + // Vertex and Indices array for the triangle mesh (data in shared and not copied) + mPhysicsTriangleVertexArray = + new rp3d::TriangleVertexArray(getNbVertices(), &(mVertices[0]), sizeof(openglframework::Vector3), + getNbFaces(0), &(mIndices[0][0]), sizeof(int), + rp3d::TriangleVertexArray::VERTEX_FLOAT_TYPE, + rp3d::TriangleVertexArray::INDEX_INTEGER_TYPE); // Create the collision shape for the rigid body (convex mesh shape) and // do not forget to delete it at the end - mConvexShape = new rp3d::ConvexMeshShape(vertices, mVertices.size(), 3 * sizeof(rp3d::decimal)); - - delete[] vertices; - - // Add the edges information of the mesh into the convex mesh collision shape. - // This is optional but it really speed up the convex mesh collision detection at the - // cost of some additional memory to store the edges inside the collision shape. - for (unsigned int i=0; iaddEdge(v1, v2); - mConvexShape->addEdge(v1, v3); - mConvexShape->addEdge(v2, v3); - } - mConvexShape->setIsEdgesInformationUsed(true);// Enable the fast collision detection with edges + mConvexShape = new rp3d::ConvexMeshShape(mPhysicsTriangleVertexArray); // Initial position and orientation of the rigid body rp3d::Vector3 initPosition(position.x, position.y, position.z); @@ -116,36 +97,16 @@ ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, float mass, // Compute the scaling matrix mScalingMatrix = openglframework::Matrix4::identity(); - // Convert the vertices array to the rp3d::decimal type - rp3d::decimal* vertices = new rp3d::decimal[3 * mVertices.size()]; - for (int i=0; i < mVertices.size(); i++) { - vertices[3 * i] = static_cast(mVertices[i].x); - vertices[3 * i + 1] = static_cast(mVertices[i].y); - vertices[3 * i + 2] = static_cast(mVertices[i].z); - } + // Vertex and Indices array for the triangle mesh (data in shared and not copied) + mPhysicsTriangleVertexArray = + new rp3d::TriangleVertexArray(getNbVertices(), &(mVertices[0]), sizeof(openglframework::Vector3), + getNbFaces(0), &(mIndices[0][0]), sizeof(int), + rp3d::TriangleVertexArray::VERTEX_FLOAT_TYPE, + rp3d::TriangleVertexArray::INDEX_INTEGER_TYPE); // Create the collision shape for the rigid body (convex mesh shape) and do // not forget to delete it at the end - mConvexShape = new rp3d::ConvexMeshShape(vertices, mVertices.size(), 3 * sizeof(rp3d::decimal)); - - delete[] vertices; - - // Add the edges information of the mesh into the convex mesh collision shape. - // This is optional but it really speed up the convex mesh collision detection at the - // cost of some additional memory to store the edges inside the collision shape. - for (unsigned int i=0; iaddEdge(v1, v2); - mConvexShape->addEdge(v1, v3); - mConvexShape->addEdge(v2, v3); - } - mConvexShape->setIsEdgesInformationUsed(true);// Enable the fast collision detection with edges + mConvexShape = new rp3d::ConvexMeshShape(mPhysicsTriangleVertexArray); // Initial position and orientation of the rigid body rp3d::Vector3 initPosition(position.x, position.y, position.z); @@ -179,6 +140,7 @@ ConvexMesh::~ConvexMesh() { mVBOTextureCoords.destroy(); mVAO.destroy(); + delete mPhysicsTriangleVertexArray; delete mConvexShape; } diff --git a/testbed/common/ConvexMesh.h b/testbed/common/ConvexMesh.h index 2017378b..0f66a143 100644 --- a/testbed/common/ConvexMesh.h +++ b/testbed/common/ConvexMesh.h @@ -41,6 +41,8 @@ class ConvexMesh : public openglframework::Mesh, public PhysicsObject { /// Previous transform (for interpolation) rp3d::Transform mPreviousTransform; + rp3d::TriangleVertexArray* mPhysicsTriangleVertexArray; + /// Collision shape rp3d::ConvexMeshShape* mConvexShape; rp3d::ProxyShape* mProxyShape;