From 43b818573a1b497ec7e0bce1d0a7b037faf2ec8c Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 21 Oct 2019 07:22:18 +0200 Subject: [PATCH] Improve rendering of testbed application (flat shading, 3 light sources, ...) --- testbed/common/Box.cpp | 11 +- testbed/common/ConvexMesh.cpp | 48 +- testbed/common/ConvexMesh.h | 12 +- testbed/common/PhysicsObject.cpp | 8 +- testbed/meshes/convexmesh.obj | 304 ++++-- testbed/meshes/cube.obj | 52 +- .../opengl-framework/src/MeshReaderWriter.cpp | 103 +- .../opengl-framework/src/MeshReaderWriter.h | 11 + testbed/opengl-framework/src/Shader.h | 17 +- .../CollisionDetectionScene.cpp | 700 ++++++------- .../collisionshapes/CollisionShapesScene.cpp | 24 +- .../scenes/concavemesh/ConcaveMeshScene.cpp | 24 +- testbed/scenes/cubes/CubesScene.cpp | 278 ++--- testbed/scenes/cubestack/CubeStackScene.cpp | 8 +- .../scenes/heightfield/HeightFieldScene.cpp | 24 +- testbed/scenes/joints/JointsScene.cpp | 28 +- testbed/scenes/raycast/RaycastScene.cpp | 28 +- testbed/shaders/phong.frag | 218 ++-- testbed/shaders/phong.vert | 142 +-- testbed/src/Main.cpp | 113 +- testbed/src/SceneDemo.cpp | 982 ++++++++++-------- testbed/src/SceneDemo.h | 384 +++---- testbed/src/TestbedApplication.cpp | 786 +++++++------- testbed/src/TestbedApplication.h | 520 +++++----- 24 files changed, 2588 insertions(+), 2237 deletions(-) mode change 100755 => 100644 testbed/scenes/collisiondetection/CollisionDetectionScene.cpp diff --git a/testbed/common/Box.cpp b/testbed/common/Box.cpp index 6d685086..78cd90d9 100644 --- a/testbed/common/Box.cpp +++ b/testbed/common/Box.cpp @@ -84,12 +84,6 @@ Box::Box(const openglframework::Vector3& size, float mass, reactphysics3d::Dynam const std::string& meshFolderPath) : PhysicsObject(meshFolderPath + "cube.obj") { - // Load the mesh from a file - openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "cube.obj", *this); - - // Calculate the normals of the mesh - calculateNormals(); - // Initialize the size of the box mSize[0] = size.x * 0.5f; mSize[1] = size.y * 0.5f; @@ -200,8 +194,7 @@ void Box::render(openglframework::Shader& shader, const openglframework::Matrix4 } // Create the Vertex Buffer Objects used to render to box with OpenGL. -/// We create two VBOs (one for vertices and one for indices) to render all the boxes -/// in the simulation. +/// We create two VBOs (one for vertices and one for indices) to render the box void Box::createVBOAndVAO() { // Create the VBO for the vertices data @@ -227,7 +220,7 @@ void Box::createVBOAndVAO() { mVBOTextureCoords.unbind(); } - // Create th VBO for the indices data + // Create the VBO for the indices data mVBOIndices.create(); mVBOIndices.bind(); size_t sizeIndices = mIndices[0].size() * sizeof(unsigned int); diff --git a/testbed/common/ConvexMesh.cpp b/testbed/common/ConvexMesh.cpp index 95e41dd1..c146a447 100644 --- a/testbed/common/ConvexMesh.cpp +++ b/testbed/common/ConvexMesh.cpp @@ -25,6 +25,7 @@ // Libraries #include "ConvexMesh.h" +#include // Constructor ConvexMesh::ConvexMesh(rp3d::CollisionWorld* world, const std::string& meshPath) @@ -39,6 +40,19 @@ ConvexMesh::ConvexMesh(rp3d::CollisionWorld* world, const std::string& meshPath) mPolygonFaces = new rp3d::PolygonVertexArray::PolygonFace[getNbFaces(0)]; rp3d::PolygonVertexArray::PolygonFace* face = mPolygonFaces; for (int f=0; f < getNbFaces(0); f++) { + + for (int v = 0; v < 3; v++) { + + const openglframework::Vector3 vertex = mVertices[mIndices[0][f*3 + v]]; + int vIndex = findVertexIndex(mConvexMeshVertices, vertex); + if (vIndex == -1) { + vIndex = mConvexMeshVertices.size(); + mConvexMeshVertices.push_back(vertex); + } + + mConvexMeshIndices.push_back(vIndex); + } + face->indexBase = f * 3; face->nbVertices = 3; face++; @@ -46,8 +60,8 @@ ConvexMesh::ConvexMesh(rp3d::CollisionWorld* world, const std::string& meshPath) // Create the polygon vertex array mPolygonVertexArray = - new rp3d::PolygonVertexArray(getNbVertices(), &(mVertices[0]), sizeof(openglframework::Vector3), - &(mIndices[0][0]), sizeof(int), + new rp3d::PolygonVertexArray(mConvexMeshVertices.size(), &(mConvexMeshVertices[0]), sizeof(openglframework::Vector3), + &(mConvexMeshIndices[0]), sizeof(int), getNbFaces(0), mPolygonFaces, rp3d::PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE, rp3d::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE); @@ -86,6 +100,19 @@ ConvexMesh::ConvexMesh(float mass, rp3d::DynamicsWorld* dynamicsWorld, const std mPolygonFaces = new rp3d::PolygonVertexArray::PolygonFace[getNbFaces(0)]; rp3d::PolygonVertexArray::PolygonFace* face = mPolygonFaces; for (int f=0; f < getNbFaces(0); f++) { + + for (int v = 0; v < 3; v++) { + + const openglframework::Vector3 vertex = mVertices[mIndices[0][f*3 + v]]; + int vIndex = findVertexIndex(mConvexMeshVertices, vertex); + if (vIndex == -1) { + vIndex = mConvexMeshVertices.size(); + mConvexMeshVertices.push_back(vertex); + } + + mConvexMeshIndices.push_back(vIndex); + } + face->indexBase = f * 3; face->nbVertices = 3; face++; @@ -93,8 +120,8 @@ ConvexMesh::ConvexMesh(float mass, rp3d::DynamicsWorld* dynamicsWorld, const std // Create the polygon vertex array mPolygonVertexArray = - new rp3d::PolygonVertexArray(getNbVertices(), &(mVertices[0]), sizeof(openglframework::Vector3), - &(mIndices[0][0]), sizeof(int), + new rp3d::PolygonVertexArray(mConvexMeshVertices.size(), &(mConvexMeshVertices[0]), sizeof(openglframework::Vector3), + &(mConvexMeshIndices[0]), sizeof(int), getNbFaces(0), mPolygonFaces, rp3d::PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE, rp3d::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE); @@ -254,3 +281,16 @@ void ConvexMesh::createVBOAndVAO() { // Unbind the VAO mVAO.unbind(); } + +// Return the index of a given vertex in the mesh +int ConvexMesh::findVertexIndex(const std::vector& vertices, const openglframework::Vector3& vertex) { + + for (int i = 0; i < vertices.size(); i++) { + if (vertices[i] == vertex) { + return i; + } + } + + return -1; +} + diff --git a/testbed/common/ConvexMesh.h b/testbed/common/ConvexMesh.h index cc8c1599..921d273b 100644 --- a/testbed/common/ConvexMesh.h +++ b/testbed/common/ConvexMesh.h @@ -69,11 +69,21 @@ class ConvexMesh : public PhysicsObject { /// Vertex Array Object for the vertex data openglframework::VertexArrayObject mVAO; + /// Array with the vertices of the convex mesh + /// (only the vertices used for the physics shape, not duplicate vertices used for rendering) + std::vector mConvexMeshVertices; + + /// Array with the vertex indices of the convex mesh (used for the physics shape) + std::vector mConvexMeshIndices; + // -------------------- Methods -------------------- // - // Create the Vertex Buffer Objects used to render with OpenGL. + /// Create the Vertex Buffer Objects used to render with OpenGL. void createVBOAndVAO(); + /// Return the index of a given vertex in the mesh + int findVertexIndex(const std::vector& vertices, const openglframework::Vector3& vertex); + public : // -------------------- Methods -------------------- // diff --git a/testbed/common/PhysicsObject.cpp b/testbed/common/PhysicsObject.cpp index ca23caef..d53f397b 100644 --- a/testbed/common/PhysicsObject.cpp +++ b/testbed/common/PhysicsObject.cpp @@ -40,8 +40,12 @@ PhysicsObject::PhysicsObject(const std::string& meshPath) : PhysicsObject() { // Load the mesh from a file openglframework::MeshReaderWriter::loadMeshFromFile(meshPath, *this); - // Calculate the normals of the mesh - calculateNormals(); + // If the mesh file do not have normals + if (mNormals.empty()) { + + // Calculate the normals of the mesh + calculateNormals(); + } } // Compute the new transform matrix diff --git a/testbed/meshes/convexmesh.obj b/testbed/meshes/convexmesh.obj index 7a194f13..11b64c24 100644 --- a/testbed/meshes/convexmesh.obj +++ b/testbed/meshes/convexmesh.obj @@ -1,125 +1,205 @@ -# Blender v2.66 (sub 0) OBJ File: '' +# Blender v2.80 (sub 75) OBJ File: '' # www.blender.org -v 0.000000 -1.000000 0.000000 -v 0.723607 -0.447220 0.525725 -v -0.276388 -0.447220 0.850649 -v -0.894426 -0.447216 0.000000 -v -0.276388 -0.447220 -0.850649 -v 0.723607 -0.447220 -0.525725 -v 0.276388 0.447220 0.850649 -v -0.723607 0.447220 0.525725 -v -0.723607 0.447220 -0.525725 -v 0.276388 0.447220 -0.850649 -v 0.894426 0.447216 0.000000 -v 0.000000 1.000000 0.000000 +v 0.000000 -1.000000 -0.000000 v 0.425323 -0.850654 0.309011 -v 0.262869 -0.525738 0.809012 v -0.162456 -0.850654 0.499995 -v 0.425323 -0.850654 -0.309011 -v 0.850648 -0.525736 0.000000 -v -0.688189 -0.525736 0.499997 -v -0.525730 -0.850652 0.000000 -v -0.688189 -0.525736 -0.499997 +v 0.723607 -0.447220 0.525725 +v 0.850648 -0.525736 -0.000000 +v -0.525730 -0.850652 -0.000000 v -0.162456 -0.850654 -0.499995 -v 0.262869 -0.525738 -0.809012 -v 0.951058 0.000000 -0.309013 -v 0.951058 0.000000 0.309013 -v 0.587786 0.000000 0.809017 -v 0.000000 0.000000 1.000000 -v -0.587786 0.000000 0.809017 -v -0.951058 0.000000 0.309013 -v -0.951058 0.000000 -0.309013 +v 0.425323 -0.850654 -0.309011 +v 0.951058 -0.000000 0.309013 +v -0.276388 -0.447220 0.850649 +v 0.262869 -0.525738 0.809012 +v 0.000000 -0.000000 1.000000 +v -0.894426 -0.447216 -0.000000 +v -0.688189 -0.525736 0.499997 +v -0.951058 -0.000000 0.309013 +v -0.276388 -0.447220 -0.850649 +v -0.688189 -0.525736 -0.499997 v -0.587786 0.000000 -0.809017 -v 0.000000 0.000000 -1.000000 +v 0.723607 -0.447220 -0.525725 +v 0.262869 -0.525738 -0.809012 v 0.587786 0.000000 -0.809017 +v 0.587786 -0.000000 0.809017 +v -0.587786 -0.000000 0.809017 +v -0.951058 0.000000 -0.309013 +v 0.000000 0.000000 -1.000000 +v 0.951058 0.000000 -0.309013 +v 0.276388 0.447220 0.850649 v 0.688189 0.525736 0.499997 +v 0.162456 0.850654 0.499995 +v -0.723607 0.447220 0.525725 v -0.262869 0.525738 0.809012 +v -0.425323 0.850654 0.309011 +v -0.723607 0.447220 -0.525725 v -0.850648 0.525736 0.000000 +v -0.425323 0.850654 -0.309011 +v 0.276388 0.447220 -0.850649 v -0.262869 0.525738 -0.809012 +v 0.162456 0.850654 -0.499995 +v 0.894426 0.447216 0.000000 v 0.688189 0.525736 -0.499997 v 0.525730 0.850652 0.000000 -v 0.162456 0.850654 0.499995 -v -0.425323 0.850654 0.309011 -v -0.425323 0.850654 -0.309011 -v 0.162456 0.850654 -0.499995 +v 0.000000 1.000000 0.000000 +vn 0.1024 -0.9435 0.3151 +vn 0.7002 -0.6617 0.2680 +vn -0.2680 -0.9435 0.1947 +vn -0.2680 -0.9435 -0.1947 +vn 0.1024 -0.9435 -0.3151 +vn 0.9050 -0.3304 0.2680 +vn 0.0247 -0.3304 0.9435 +vn -0.8897 -0.3304 0.3151 +vn -0.5746 -0.3304 -0.7488 +vn 0.5346 -0.3304 -0.7779 +vn 0.8026 -0.1256 0.5831 +vn -0.3066 -0.1256 0.9435 +vn -0.9921 -0.1256 -0.0000 +vn -0.3066 -0.1256 -0.9435 +vn 0.8026 -0.1256 -0.5831 +vn 0.4089 0.6617 0.6284 +vn -0.4713 0.6617 0.5831 +vn -0.7002 0.6617 -0.2680 +vn 0.0385 0.6617 -0.7488 +vn 0.7240 0.6617 -0.1947 +vn -0.0385 -0.6617 0.7488 +vn 0.1876 -0.7947 0.5773 +vn 0.4713 -0.6617 0.5831 +vn 0.7002 -0.6617 -0.2680 +vn 0.6071 -0.7947 0.0000 +vn 0.3313 -0.9435 -0.0000 +vn -0.7240 -0.6617 0.1947 +vn -0.4911 -0.7947 0.3568 +vn -0.4089 -0.6617 0.6284 +vn -0.4089 -0.6617 -0.6284 +vn -0.4911 -0.7947 -0.3568 +vn -0.7240 -0.6617 -0.1947 +vn 0.4713 -0.6617 -0.5831 +vn 0.1876 -0.7947 -0.5773 +vn -0.0385 -0.6617 -0.7488 +vn 0.9921 0.1256 0.0000 +vn 0.9822 -0.1876 -0.0000 +vn 0.9050 -0.3304 -0.2680 +vn 0.3066 0.1256 0.9435 +vn 0.3035 -0.1876 0.9342 +vn 0.5346 -0.3304 0.7779 +vn -0.8026 0.1256 0.5831 +vn -0.7947 -0.1876 0.5773 +vn -0.5746 -0.3304 0.7488 +vn -0.8026 0.1256 -0.5831 +vn -0.7947 -0.1876 -0.5773 +vn -0.8897 -0.3304 -0.3151 +vn 0.3066 0.1256 -0.9435 +vn 0.3035 -0.1876 -0.9342 +vn 0.0247 -0.3304 -0.9435 +vn 0.5746 0.3304 0.7488 +vn 0.7947 0.1876 0.5773 +vn 0.8897 0.3304 0.3151 +vn -0.5346 0.3304 0.7779 +vn -0.3035 0.1876 0.9342 +vn -0.0247 0.3304 0.9435 +vn -0.9050 0.3304 -0.2680 +vn -0.9822 0.1876 0.0000 +vn -0.9050 0.3304 0.2680 +vn -0.0247 0.3304 -0.9435 +vn -0.3035 0.1876 -0.9342 +vn -0.5346 0.3304 -0.7779 +vn 0.8897 0.3304 -0.3151 +vn 0.7947 0.1876 -0.5773 +vn 0.5746 0.3304 -0.7488 +vn 0.2680 0.9435 0.1947 +vn 0.4911 0.7947 0.3568 +vn 0.7240 0.6617 0.1947 +vn -0.1024 0.9435 0.3151 +vn -0.1876 0.7947 0.5773 +vn 0.0385 0.6617 0.7488 +vn -0.3313 0.9435 0.0000 +vn -0.6071 0.7947 0.0000 +vn -0.7002 0.6617 0.2680 +vn -0.1024 0.9435 -0.3151 +vn -0.1876 0.7947 -0.5773 +vn -0.4713 0.6617 -0.5831 +vn 0.2680 0.9435 -0.1947 +vn 0.4911 0.7947 -0.3568 +vn 0.4089 0.6617 -0.6284 s off -f 1 13 15 -f 2 13 17 -f 1 15 19 -f 1 19 21 -f 1 21 16 -f 2 17 24 -f 3 14 26 -f 4 18 28 -f 5 20 30 -f 6 22 32 -f 2 24 25 -f 3 26 27 -f 4 28 29 -f 5 30 31 -f 6 32 23 -f 7 33 39 -f 8 34 40 -f 9 35 41 -f 10 36 42 -f 11 37 38 -f 15 14 3 -f 15 13 14 -f 13 2 14 -f 17 16 6 -f 17 13 16 -f 13 1 16 -f 19 18 4 -f 19 15 18 -f 15 3 18 -f 21 20 5 -f 21 19 20 -f 19 4 20 -f 16 22 6 -f 16 21 22 -f 21 5 22 -f 24 23 11 -f 24 17 23 -f 17 6 23 -f 26 25 7 -f 26 14 25 -f 14 2 25 -f 28 27 8 -f 28 18 27 -f 18 3 27 -f 30 29 9 -f 30 20 29 -f 20 4 29 -f 32 31 10 -f 32 22 31 -f 22 5 31 -f 25 33 7 -f 25 24 33 -f 24 11 33 -f 27 34 8 -f 27 26 34 -f 26 7 34 -f 29 35 9 -f 29 28 35 -f 28 8 35 -f 31 36 10 -f 31 30 36 -f 30 9 36 -f 23 37 11 -f 23 32 37 -f 32 10 37 -f 39 38 12 -f 39 33 38 -f 33 11 38 -f 40 39 12 -f 40 34 39 -f 34 7 39 -f 41 40 12 -f 41 35 40 -f 35 8 40 -f 42 41 12 -f 42 36 41 -f 36 9 41 -f 38 42 12 -f 38 37 42 -f 37 10 42 +f 1//1 2//1 3//1 +f 4//2 2//2 5//2 +f 1//3 3//3 6//3 +f 1//4 6//4 7//4 +f 1//5 7//5 8//5 +f 4//6 5//6 9//6 +f 10//7 11//7 12//7 +f 13//8 14//8 15//8 +f 16//9 17//9 18//9 +f 19//10 20//10 21//10 +f 4//11 9//11 22//11 +f 10//12 12//12 23//12 +f 13//13 15//13 24//13 +f 16//14 18//14 25//14 +f 19//15 21//15 26//15 +f 27//16 28//16 29//16 +f 30//17 31//17 32//17 +f 33//18 34//18 35//18 +f 36//19 37//19 38//19 +f 39//20 40//20 41//20 +f 3//21 11//21 10//21 +f 3//22 2//22 11//22 +f 2//23 4//23 11//23 +f 5//24 8//24 19//24 +f 5//25 2//25 8//25 +f 2//26 1//26 8//26 +f 6//27 14//27 13//27 +f 6//28 3//28 14//28 +f 3//29 10//29 14//29 +f 7//30 17//30 16//30 +f 7//31 6//31 17//31 +f 6//32 13//32 17//32 +f 8//33 20//33 19//33 +f 8//34 7//34 20//34 +f 7//35 16//35 20//35 +f 9//36 26//36 39//36 +f 9//37 5//37 26//37 +f 5//38 19//38 26//38 +f 12//39 22//39 27//39 +f 12//40 11//40 22//40 +f 11//41 4//41 22//41 +f 15//42 23//42 30//42 +f 15//43 14//43 23//43 +f 14//44 10//44 23//44 +f 18//45 24//45 33//45 +f 18//46 17//46 24//46 +f 17//47 13//47 24//47 +f 21//48 25//48 36//48 +f 21//49 20//49 25//49 +f 20//50 16//50 25//50 +f 22//51 28//51 27//51 +f 22//52 9//52 28//52 +f 9//53 39//53 28//53 +f 23//54 31//54 30//54 +f 23//55 12//55 31//55 +f 12//56 27//56 31//56 +f 24//57 34//57 33//57 +f 24//58 15//58 34//58 +f 15//59 30//59 34//59 +f 25//60 37//60 36//60 +f 25//61 18//61 37//61 +f 18//62 33//62 37//62 +f 26//63 40//63 39//63 +f 26//64 21//64 40//64 +f 21//65 36//65 40//65 +f 29//66 41//66 42//66 +f 29//67 28//67 41//67 +f 28//68 39//68 41//68 +f 32//69 29//69 42//69 +f 32//70 31//70 29//70 +f 31//71 27//71 29//71 +f 35//72 32//72 42//72 +f 35//73 34//73 32//73 +f 34//74 30//74 32//74 +f 38//75 35//75 42//75 +f 38//76 37//76 35//76 +f 37//77 33//77 35//77 +f 41//78 38//78 42//78 +f 41//79 40//79 38//79 +f 40//80 36//80 38//80 diff --git a/testbed/meshes/cube.obj b/testbed/meshes/cube.obj index 167925a5..a5ef7cfa 100644 --- a/testbed/meshes/cube.obj +++ b/testbed/meshes/cube.obj @@ -1,17 +1,43 @@ -# Blender v2.72 (sub 0) OBJ File: '' +# Blender v2.80 (sub 75) OBJ File: '' # www.blender.org -v -1.000000 -1.000000 1.000000 -v -1.000000 -1.000000 -1.000000 -v 1.000000 -1.000000 -1.000000 -v 1.000000 -1.000000 1.000000 -v -1.000000 1.000000 1.000000 -v -1.000000 1.000000 -1.000000 v 1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 -1.000000 v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 1.000000 +vt 0.375000 0.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.375000 0.250000 +vt 0.625000 0.250000 +vt 0.625000 0.500000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.375000 0.750000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.125000 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.750000 +vt 0.125000 0.750000 +vt 0.625000 0.500000 +vt 0.875000 0.500000 +vt 0.875000 0.750000 +vn 0.0000 1.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 -1.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 s off -f 5 6 2 1 -f 6 7 3 2 -f 7 8 4 3 -f 8 5 1 4 -f 1 2 3 4 -f 8 7 6 5 +f 1/1/1 5/2/1 7/3/1 3/4/1 +f 4/5/2 3/6/2 7/7/2 8/8/2 +f 8/8/3 7/7/3 5/9/3 6/10/3 +f 6/10/4 2/11/4 4/12/4 8/13/4 +f 2/14/5 1/15/5 3/16/5 4/17/5 +f 6/18/6 5/19/6 1/20/6 2/11/6 diff --git a/testbed/opengl-framework/src/MeshReaderWriter.cpp b/testbed/opengl-framework/src/MeshReaderWriter.cpp index 275226ae..321a1282 100644 --- a/testbed/opengl-framework/src/MeshReaderWriter.cpp +++ b/testbed/opengl-framework/src/MeshReaderWriter.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include using namespace openglframework; using namespace std; @@ -112,6 +114,7 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) { std::vector normalsIndices; std::vector uvsIndices; + // ---------- Collect the data from the file ---------- // // For each line of the file @@ -142,7 +145,7 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) { line = buffer; found1 = (int)line.find("/"); bool isFaceQuad = false; - int foundNext = (int)line.substr(found1+1).find("/"); + found2 = (int)line.substr(found1+1).find("/"); // If the face definition is of the form "f v1 v2 v3 v4" if(found1 == string::npos) { @@ -150,11 +153,21 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) { if (nbVertices == 4) isFaceQuad = true; } // If the face definition is of the form "f v1// v2// v3// v4//" - else if (foundNext == 0) { + else if (found2 == 0 && (int)line.substr(found1+found2+1).find(" ") == 0) { int nbVertices = sscanf(buffer.c_str(), "%*s %d// %d// %d// %d//", &id1, &id2, &id3, &id4); if (nbVertices == 4) isFaceQuad = true; } - else { // If the face definition contains vertices and texture coordinates + else { // If the face definition contains vertices and (texture coordinates or normals) + + tId1 = -1; + tId2 = -1; + tId3 = -1; + tId4 = -1; + + nId1 = -1; + nId2 = -1; + nId3 = -1; + nId4 = -1; //get the part of the string until the second index tmp = line.substr(found1+1); @@ -166,6 +179,7 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) { if(found2 == string::npos) { int n = sscanf(buffer.c_str(), "%*s %d/%d %d/%d %d/%d %d/%d", &id1, &tId1, &id2, &tId2, &id3, &tId3, &id4, &tId4); if (n == 8) isFaceQuad = true; + uvsIndices.push_back(tId1-1); uvsIndices.push_back(tId2-1); uvsIndices.push_back(tId3-1); @@ -174,8 +188,11 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) { else { tmp = line.substr(found1+1); found2 = (int)tmp.find("/"); + if (found2 > 1000) { + int test = 2; + } - // If the face definition is of the form "f vert1/normal1 vert2/normal2 ..." + // If the face definition is of the form "f vert1//normal1 vert2//normal2 ..." if(found2 == 0) { int n = sscanf(buffer.c_str(), "%*s %d//%d %d//%d %d//%d %d//%d", &id1, &nId1, &id2, &nId2, &id3, &nId3, &id4, &nId4); if (n == 8) isFaceQuad = true; @@ -213,39 +230,84 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) { // Destroy the current mesh meshToCreate.destroy(); + // This is used to create duplicate vertices if a vertex with index "i" from a face does not + // have same texture coordinates or normals as a previous vertex with index "i". + unordered_map, uint> mapVertNormTexToVertexIndex; + // Mesh data vector > meshIndices; + vector meshVertices; vector meshNormals; - if (!normals.empty()) meshNormals = vector(vertices.size(), Vector3(0, 0, 0)); + //if (!normals.empty()) meshNormals = vector(vertices.size(), Vector3(0, 0, 0)); vector meshUVs; - if (!uvs.empty()) meshUVs = vector(vertices.size(), Vector2(0, 0)); + //if (!uvs.empty()) meshUVs = vector(vertices.size(), Vector2(0, 0)); // We cannot load mesh with several parts for the moment uint meshPart = 0; + const bool hasNormals = !normalsIndices.empty() && !normals.empty(); + const bool hasUvs = !uvsIndices.empty() && !uvs.empty(); + // Fill in the vertex indices // We also triangulate each quad face meshIndices.push_back(std::vector()); for(size_t i = 0, j = 0; i < verticesIndices.size(); j++) { - // Get the current vertex IDs - uint i1 = verticesIndices[i]; - uint i2 = verticesIndices[i+1]; - uint i3 = verticesIndices[i+2]; + // 3 if the current vertices form a triangle and 4 if they form a quad + const int nbVertices = isQuad[j] ? 4 : 3; + int newVerticesIndices[4] = { -1, -1, -1, -1 }; + + // For each vertex, we check if there is already a vertex with same UV and normals. + for (int v = 0; v < nbVertices; v++) { + + int normalIndex = hasNormals ? normalsIndices[i + v] : -1; + int uvIndex = hasUvs ? uvsIndices[i + v] : -1; + + // If the vertex with same UV and normal doesn't exist yet in the map + tuple key = std::make_tuple(verticesIndices[i+v], normalIndex, uvIndex); + auto itFound = mapVertNormTexToVertexIndex.find(key); + if (itFound == mapVertNormTexToVertexIndex.end()) { + + // Create a new vertex + newVerticesIndices[v]= meshVertices.size(); + meshVertices.push_back(vertices[verticesIndices[i+v]]); + if (hasNormals) { + meshNormals.push_back(normals[normalsIndices[i+v]]); + } + if (hasUvs) { + meshUVs.push_back(uvs[uvsIndices[i+v]]); + } + + mapVertNormTexToVertexIndex.insert(std::make_pair(key, newVerticesIndices[v])); + } + else { + // Get the vertex index to use + newVerticesIndices[v] = itFound->second; + } + } + + // Get the current vertex IDs + uint i1 = newVerticesIndices[0]; + uint i2 = newVerticesIndices[1]; + uint i3 = newVerticesIndices[2]; + uint i4 = newVerticesIndices[3]; + + /* // Add the vertex normal - if (!normalsIndices.empty() && !normals.empty()) { + if (hasNormals) { meshNormals[i1] = normals[normalsIndices[i]]; meshNormals[i2] = normals[normalsIndices[i+1]]; meshNormals[i3] = normals[normalsIndices[i+2]]; } // Add the vertex UV texture coordinates - if (!uvsIndices.empty() && !uvs.empty()) { + if (hasUvs) { meshUVs[i1] = uvs[uvsIndices[i]]; meshUVs[i2] = uvs[uvsIndices[i+1]]; meshUVs[i3] = uvs[uvsIndices[i+2]]; } + */ // If the current vertex not in a quad (it is part of a triangle) if (!isQuad[j]) { @@ -259,11 +321,10 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) { } else { // If the current vertex is in a quad - Vector3 v1 = vertices[i1]; - Vector3 v2 = vertices[i2]; - Vector3 v3 = vertices[i3]; - uint i4 = verticesIndices[i+3]; - Vector3 v4 = vertices[i4]; + Vector3 v1 = meshVertices[i1]; + Vector3 v2 = meshVertices[i2]; + Vector3 v3 = meshVertices[i3]; + Vector3 v4 = meshVertices[i4]; Vector3 v13 = v3-v1; Vector3 v12 = v2-v1; @@ -288,6 +349,7 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) { meshIndices[meshPart].push_back(i4); } + /* // Add the vertex normal if (!normalsIndices.empty() && !normals.empty()) { meshNormals[i4] = normals[normalsIndices[i]]; @@ -297,17 +359,18 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) { if (!uvsIndices.empty() && !uvs.empty()) { meshUVs[i4] = uvs[uvsIndices[i]]; } + */ i+=4; } } - assert(meshNormals.empty() || meshNormals.size() == vertices.size()); - assert(meshUVs.empty() || meshUVs.size() == vertices.size()); + assert(meshNormals.empty() || meshNormals.size() == meshVertices.size()); + assert(meshUVs.empty() || meshUVs.size() == meshVertices.size()); // Set the data to the mesh meshToCreate.setIndices(meshIndices); - meshToCreate.setVertices(vertices); + meshToCreate.setVertices(meshVertices); meshToCreate.setNormals(meshNormals); meshToCreate.setUVs(meshUVs); } diff --git a/testbed/opengl-framework/src/MeshReaderWriter.h b/testbed/opengl-framework/src/MeshReaderWriter.h index 7b85758c..509fbe58 100644 --- a/testbed/opengl-framework/src/MeshReaderWriter.h +++ b/testbed/opengl-framework/src/MeshReaderWriter.h @@ -93,4 +93,15 @@ class VertexMergingDataComparison { } +namespace std { + template<> + struct hash> + { + size_t operator()(const std::tuple& key) const + { + return std::get<0>(key) ^ std::get<1>(key) ^ std::get<2>(key); + } + }; +} + #endif diff --git a/testbed/opengl-framework/src/Shader.h b/testbed/opengl-framework/src/Shader.h index daaad6be..c01c880c 100644 --- a/testbed/opengl-framework/src/Shader.h +++ b/testbed/opengl-framework/src/Shader.h @@ -95,6 +95,11 @@ class Shader { // to set it, an assert will occur) void setIntUniform(const std::string& variableName, int value, bool errorIfMissing = true) const; + // Set an array of int uniform values to this shader (be careful if the uniform is not + // used in the shader, the compiler will remove it, then when you will try + // to set it, an assert will occur) + void setIntArrayUniform(const std::string& variableName, GLint* values, int nbValues, bool errorIfMissing = true) const; + // Set a vector 2 uniform value to this shader (be careful if the uniform is not // used in the shader, the compiler will remove it, then when you will try // to set it, an assert will occur) @@ -159,7 +164,7 @@ inline GLint Shader::getUniformLocation(const std::string& variableName, bool er std::cerr << "Error in vertex shader " << mFilenameVertexShader << " or in fragment shader" << mFilenameFragmentShader << " : No Uniform variable : " << variableName << std::endl; - throw std::logic_error("Error in Shader"); + //throw std::logic_error("Error in Shader"); } return location; @@ -209,6 +214,16 @@ inline void Shader::setIntUniform(const std::string& variableName, int value, bo } } +// Set an array of int uniform values to this shader (be careful if the uniform is not +// used in the shader, the compiler will remove it, then when you will try +// to set it, an assert will occur) +inline void Shader::setIntArrayUniform(const std::string& variableName, GLint* values, int nbValues, bool errorIfMissing) const { + assert(mProgramObjectID != 0); + GLint location = getUniformLocation(variableName, errorIfMissing); + if (location != -1) { + glUniform1iv(location, nbValues, values); + } +} // Set a vector 2 uniform value to this shader (be careful if the uniform is not // used in the shader, the compiler will remove it, then when you will try // to set it, an assert will occur) diff --git a/testbed/scenes/collisiondetection/CollisionDetectionScene.cpp b/testbed/scenes/collisiondetection/CollisionDetectionScene.cpp old mode 100755 new mode 100644 index ea57959c..ffc59487 --- a/testbed/scenes/collisiondetection/CollisionDetectionScene.cpp +++ b/testbed/scenes/collisiondetection/CollisionDetectionScene.cpp @@ -1,350 +1,350 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://www.reactphysics3d.com * -* Copyright (c) 2010-2016 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 "CollisionDetectionScene.h" -#include "constraint/ContactPoint.h" -#include "collision/ContactManifold.h" - -// Namespaces -using namespace openglframework; -using namespace collisiondetectionscene; - -// Constructor -CollisionDetectionScene::CollisionDetectionScene(const std::string& name, EngineSettings& settings) - : SceneDemo(name, settings, SCENE_RADIUS, false), mMeshFolderPath("meshes/"), - mContactManager(mPhongShader, mMeshFolderPath), - mAreNormalsDisplayed(false) { - - mSelectedShapeIndex = 0; - mIsContactPointsDisplayed = true; - mIsWireframeEnabled = true; - - // Compute the radius and the center of the scene - openglframework::Vector3 center(0, 0, 0); - - // Set the center of the scene - setScenePosition(center, SCENE_RADIUS); - - rp3d::WorldSettings worldSettings; - worldSettings.worldName = name; - - // Create the dynamics world for the physics simulation - mPhysicsWorld = new rp3d::CollisionWorld(worldSettings); - - // ---------- Sphere 1 ---------- // - - // Create a sphere and a corresponding collision body in the dynamics world - mSphere1 = new Sphere(4, mPhysicsWorld, mMeshFolderPath); - mAllShapes.push_back(mSphere1); - - // Set the color - mSphere1->setColor(mGreyColorDemo); - mSphere1->setSleepingColor(mRedColorDemo); - //mSphere1->setScaling(0.5f); - mPhysicsObjects.push_back(mSphere1); - - // ---------- Sphere 2 ---------- // - - // Create a sphere and a corresponding collision body in the dynamics world - mSphere2 = new Sphere(2, mPhysicsWorld, mMeshFolderPath); - mAllShapes.push_back(mSphere2); - - // Set the color - mSphere2->setColor(mGreyColorDemo); - mSphere2->setSleepingColor(mRedColorDemo); - mPhysicsObjects.push_back(mSphere2); - - - // ---------- Capsule 1 ---------- // - - // Create a cylinder and a corresponding collision body in the dynamics world - mCapsule1 = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, mPhysicsWorld, mMeshFolderPath); - mAllShapes.push_back(mCapsule1); - - // Set the color - mCapsule1->setColor(mGreyColorDemo); - mCapsule1->setSleepingColor(mRedColorDemo); - mPhysicsObjects.push_back(mCapsule1); - - // ---------- Capsule 2 ---------- // - - // Create a cylinder and a corresponding collision body in the dynamics world - mCapsule2 = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, mPhysicsWorld, mMeshFolderPath); - mAllShapes.push_back(mCapsule2); - - // Set the color - mCapsule2->setColor(mGreyColorDemo); - mCapsule2->setSleepingColor(mRedColorDemo); - mPhysicsObjects.push_back(mCapsule2); - - // ---------- Concave Mesh ---------- // - - // Create a convex mesh and a corresponding collision body in the dynamics world - mConcaveMesh = new ConcaveMesh(mPhysicsWorld, mMeshFolderPath + "city.obj"); - mAllShapes.push_back(mConcaveMesh); - - // Set the color - mConcaveMesh->setColor(mGreyColorDemo); - mConcaveMesh->setSleepingColor(mRedColorDemo); - mPhysicsObjects.push_back(mConcaveMesh); - - // ---------- Box 1 ---------- // - - // Create a cylinder and a corresponding collision body in the dynamics world - mBox1 = new Box(BOX_SIZE, mPhysicsWorld, mMeshFolderPath); - mAllShapes.push_back(mBox1); - - // Set the color - mBox1->setColor(mGreyColorDemo); - mBox1->setSleepingColor(mRedColorDemo); - mPhysicsObjects.push_back(mBox1); - - // ---------- Box 2 ---------- // - - // Create a cylinder and a corresponding collision body in the dynamics world - mBox2 = new Box(openglframework::Vector3(3, 2, 5), mPhysicsWorld, mMeshFolderPath); - mAllShapes.push_back(mBox2); - - // Set the color - mBox2->setColor(mGreyColorDemo); - mBox2->setSleepingColor(mRedColorDemo); - mPhysicsObjects.push_back(mBox2); - - // ---------- Convex Mesh ---------- // - - // Create a convex mesh and a corresponding collision body in the dynamics world - mConvexMesh = new ConvexMesh(mPhysicsWorld, mMeshFolderPath + "convexmesh.obj"); - mAllShapes.push_back(mConvexMesh); - - // Set the color - mConvexMesh->setColor(mGreyColorDemo); - mConvexMesh->setSleepingColor(mRedColorDemo); - mPhysicsObjects.push_back(mConvexMesh); - - // ---------- Heightfield ---------- // - - // Create a convex mesh and a corresponding collision body in the dynamics world - mHeightField = new HeightField(mPhysicsWorld); - - // Set the color - mHeightField->setColor(mGreyColorDemo); - mHeightField->setSleepingColor(mRedColorDemo); - mPhysicsObjects.push_back(mHeightField); - - mAllShapes[mSelectedShapeIndex]->setColor(mBlueColorDemo); -} - -// Reset the scene -void CollisionDetectionScene::reset() { - - mSphere1->setTransform(rp3d::Transform(rp3d::Vector3(15, 5, 0), rp3d::Quaternion::identity())); - mSphere2->setTransform(rp3d::Transform(rp3d::Vector3(0, 6, 0), rp3d::Quaternion::identity())); - mCapsule1->setTransform(rp3d::Transform(rp3d::Vector3(-8, 7, 0), rp3d::Quaternion::identity())); - mCapsule2->setTransform(rp3d::Transform(rp3d::Vector3(11, -8, 0), rp3d::Quaternion::identity())); - mBox1->setTransform(rp3d::Transform(rp3d::Vector3(-4, -7, 0), rp3d::Quaternion::identity())); - mBox2->setTransform(rp3d::Transform(rp3d::Vector3(0, 9, 0), rp3d::Quaternion::identity())); - mConvexMesh->setTransform(rp3d::Transform(rp3d::Vector3(-5, 0, 0), rp3d::Quaternion::identity())); - mConcaveMesh->setTransform(rp3d::Transform(rp3d::Vector3(0, 15, 0), rp3d::Quaternion::identity())); - mHeightField->setTransform(rp3d::Transform(rp3d::Vector3(0, -22, 0), rp3d::Quaternion::identity())); -} - -// Destructor -CollisionDetectionScene::~CollisionDetectionScene() { - - // Destroy the box rigid body from the dynamics world - //mPhysicsWorld->destroyCollisionBody(mBox->getCollisionBody()); - //delete mBox; - - // Destroy the spheres - mPhysicsWorld->destroyCollisionBody(mSphere1->getCollisionBody()); - delete mSphere1; - - mPhysicsWorld->destroyCollisionBody(mSphere2->getCollisionBody()); - delete mSphere2; - - mPhysicsWorld->destroyCollisionBody(mCapsule1->getCollisionBody()); - delete mCapsule1; - - mPhysicsWorld->destroyCollisionBody(mCapsule2->getCollisionBody()); - delete mCapsule2; - - mPhysicsWorld->destroyCollisionBody(mBox1->getCollisionBody()); - delete mBox1; - - mPhysicsWorld->destroyCollisionBody(mBox2->getCollisionBody()); - delete mBox2; - - mPhysicsWorld->destroyCollisionBody(mConvexMesh->getCollisionBody()); - delete mConvexMesh; - - mPhysicsWorld->destroyCollisionBody(mConcaveMesh->getCollisionBody()); - delete mConcaveMesh; - - mPhysicsWorld->destroyCollisionBody(mHeightField->getCollisionBody()); - delete mHeightField; - - mContactManager.resetPoints(); - - // Destroy the static data for the visual contact points - VisualContactPoint::destroyStaticData(); - - // Destroy the collision world - delete mPhysicsWorld; -} - -// Take a step for the simulation -void CollisionDetectionScene::update() { - - mContactManager.resetPoints(); - - mPhysicsWorld->testCollision(&mContactManager); - - SceneDemo::update(); -} - -void CollisionDetectionScene::selectNextShape() { - - uint previousIndex = mSelectedShapeIndex; - mSelectedShapeIndex++; - if (mSelectedShapeIndex >= mAllShapes.size()) { - mSelectedShapeIndex = 0; - } - - mAllShapes[previousIndex]->setColor(mGreyColorDemo); - mAllShapes[mSelectedShapeIndex]->setColor(mBlueColorDemo); -} - -// Called when a keyboard event occurs -bool CollisionDetectionScene::keyboardEvent(int key, int scancode, int action, int mods) { - - // If the space key has been pressed - if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) { - selectNextShape(); - return true; - } - - float stepDist = 0.2f; - float stepAngle = 15 * (3.14f / 180.0f); - - if (key == GLFW_KEY_RIGHT && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setPosition(transform.getPosition() + rp3d::Vector3(stepDist, 0, 0)); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - else if (key == GLFW_KEY_LEFT && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setPosition(transform.getPosition() + rp3d::Vector3(-stepDist, 0, 0)); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - else if (key == GLFW_KEY_UP && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setPosition(transform.getPosition() + rp3d::Vector3(0, stepDist, 0)); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - else if (key == GLFW_KEY_DOWN && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setPosition(transform.getPosition() + rp3d::Vector3(0, -stepDist, 0)); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - else if (key == GLFW_KEY_Z && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setPosition(transform.getPosition() + rp3d::Vector3(0, 0, stepDist)); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - else if (key == GLFW_KEY_H && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setPosition(transform.getPosition() + rp3d::Vector3(0, 0, -stepDist)); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - else if (key == GLFW_KEY_A && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, stepAngle, 0) * transform.getOrientation()); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - else if (key == GLFW_KEY_D && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, -stepAngle, 0) * transform.getOrientation()); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - else if (key == GLFW_KEY_W && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setOrientation(rp3d::Quaternion::fromEulerAngles(stepAngle, 0, 0) * transform.getOrientation()); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - else if (key == GLFW_KEY_S && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setOrientation(rp3d::Quaternion::fromEulerAngles(-stepAngle, 0, 0) * transform.getOrientation()); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - else if (key == GLFW_KEY_F && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, 0, stepAngle) * transform.getOrientation()); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - else if (key == GLFW_KEY_G && action == GLFW_PRESS) { - rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); - transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, 0, -stepAngle) * transform.getOrientation()); - mAllShapes[mSelectedShapeIndex]->setTransform(transform); - } - - return false; -} - -// This method will be called for each reported contact point -void ContactManager::notifyContact(const CollisionCallbackInfo& collisionCallbackInfo) { - - // For each contact manifold - rp3d::ContactManifoldListElement* manifoldElement = collisionCallbackInfo.contactManifoldElements; - while (manifoldElement != nullptr) { - - // Get the contact manifold - rp3d::ContactManifold* contactManifold = manifoldElement->getContactManifold(); - - // For each contact point - rp3d::ContactPoint* contactPoint = contactManifold->getContactPoints(); - while (contactPoint != nullptr) { - - // Contact normal - rp3d::Vector3 normal = contactPoint->getNormal(); - openglframework::Vector3 contactNormal(normal.x, normal.y, normal.z); - - rp3d::Vector3 point1 = contactPoint->getLocalPointOnShape1(); - point1 = collisionCallbackInfo.proxyShape1->getLocalToWorldTransform() * point1; - - openglframework::Vector3 position1(point1.x, point1.y, point1.z); - mContactPoints.push_back(ContactPoint(position1, contactNormal, openglframework::Color::red())); - - rp3d::Vector3 point2 = contactPoint->getLocalPointOnShape2(); - point2 = collisionCallbackInfo.proxyShape2->getLocalToWorldTransform() * point2; - openglframework::Vector3 position2(point2.x, point2.y, point2.z); - mContactPoints.push_back(ContactPoint(position2, contactNormal, openglframework::Color::blue())); - - contactPoint = contactPoint->getNext(); - } - - manifoldElement = manifoldElement->getNext(); - } -} +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2016 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 "CollisionDetectionScene.h" +#include "constraint/ContactPoint.h" +#include "collision/ContactManifold.h" + +// Namespaces +using namespace openglframework; +using namespace collisiondetectionscene; + +// Constructor +CollisionDetectionScene::CollisionDetectionScene(const std::string& name, EngineSettings& settings) + : SceneDemo(name, settings, SCENE_RADIUS, false), mMeshFolderPath("meshes/"), + mContactManager(mPhongShader, mMeshFolderPath), + mAreNormalsDisplayed(false) { + + mSelectedShapeIndex = 0; + mIsContactPointsDisplayed = true; + mIsWireframeEnabled = true; + + // Compute the radius and the center of the scene + openglframework::Vector3 center(0, 0, 0); + + // Set the center of the scene + setScenePosition(center, SCENE_RADIUS); + + rp3d::WorldSettings worldSettings; + worldSettings.worldName = name; + + // Create the dynamics world for the physics simulation + mPhysicsWorld = new rp3d::CollisionWorld(worldSettings); + + // ---------- Sphere 1 ---------- // + + // Create a sphere and a corresponding collision body in the dynamics world + mSphere1 = new Sphere(4, mPhysicsWorld, mMeshFolderPath); + mAllShapes.push_back(mSphere1); + + // Set the color + mSphere1->setColor(mObjectColorDemo); + mSphere1->setSleepingColor(mSleepingColorDemo); + //mSphere1->setScaling(0.5f); + mPhysicsObjects.push_back(mSphere1); + + // ---------- Sphere 2 ---------- // + + // Create a sphere and a corresponding collision body in the dynamics world + mSphere2 = new Sphere(2, mPhysicsWorld, mMeshFolderPath); + mAllShapes.push_back(mSphere2); + + // Set the color + mSphere2->setColor(mObjectColorDemo); + mSphere2->setSleepingColor(mSleepingColorDemo); + mPhysicsObjects.push_back(mSphere2); + + + // ---------- Capsule 1 ---------- // + + // Create a cylinder and a corresponding collision body in the dynamics world + mCapsule1 = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, mPhysicsWorld, mMeshFolderPath); + mAllShapes.push_back(mCapsule1); + + // Set the color + mCapsule1->setColor(mObjectColorDemo); + mCapsule1->setSleepingColor(mSleepingColorDemo); + mPhysicsObjects.push_back(mCapsule1); + + // ---------- Capsule 2 ---------- // + + // Create a cylinder and a corresponding collision body in the dynamics world + mCapsule2 = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, mPhysicsWorld, mMeshFolderPath); + mAllShapes.push_back(mCapsule2); + + // Set the color + mCapsule2->setColor(mObjectColorDemo); + mCapsule2->setSleepingColor(mSleepingColorDemo); + mPhysicsObjects.push_back(mCapsule2); + + // ---------- Concave Mesh ---------- // + + // Create a convex mesh and a corresponding collision body in the dynamics world + mConcaveMesh = new ConcaveMesh(mPhysicsWorld, mMeshFolderPath + "city.obj"); + mAllShapes.push_back(mConcaveMesh); + + // Set the color + mConcaveMesh->setColor(mObjectColorDemo); + mConcaveMesh->setSleepingColor(mSleepingColorDemo); + mPhysicsObjects.push_back(mConcaveMesh); + + // ---------- Box 1 ---------- // + + // Create a cylinder and a corresponding collision body in the dynamics world + mBox1 = new Box(BOX_SIZE, mPhysicsWorld, mMeshFolderPath); + mAllShapes.push_back(mBox1); + + // Set the color + mBox1->setColor(mObjectColorDemo); + mBox1->setSleepingColor(mSleepingColorDemo); + mPhysicsObjects.push_back(mBox1); + + // ---------- Box 2 ---------- // + + // Create a cylinder and a corresponding collision body in the dynamics world + mBox2 = new Box(openglframework::Vector3(3, 2, 5), mPhysicsWorld, mMeshFolderPath); + mAllShapes.push_back(mBox2); + + // Set the color + mBox2->setColor(mObjectColorDemo); + mBox2->setSleepingColor(mSleepingColorDemo); + mPhysicsObjects.push_back(mBox2); + + // ---------- Convex Mesh ---------- // + + // Create a convex mesh and a corresponding collision body in the dynamics world + mConvexMesh = new ConvexMesh(mPhysicsWorld, mMeshFolderPath + "convexmesh.obj"); + mAllShapes.push_back(mConvexMesh); + + // Set the color + mConvexMesh->setColor(mObjectColorDemo); + mConvexMesh->setSleepingColor(mSleepingColorDemo); + mPhysicsObjects.push_back(mConvexMesh); + + // ---------- Heightfield ---------- // + + // Create a convex mesh and a corresponding collision body in the dynamics world + mHeightField = new HeightField(mPhysicsWorld); + + // Set the color + mHeightField->setColor(mObjectColorDemo); + mHeightField->setSleepingColor(mSleepingColorDemo); + mPhysicsObjects.push_back(mHeightField); + + mAllShapes[mSelectedShapeIndex]->setColor(mObjectColorDemo); +} + +// Reset the scene +void CollisionDetectionScene::reset() { + + mSphere1->setTransform(rp3d::Transform(rp3d::Vector3(15, 5, 0), rp3d::Quaternion::identity())); + mSphere2->setTransform(rp3d::Transform(rp3d::Vector3(0, 6, 0), rp3d::Quaternion::identity())); + mCapsule1->setTransform(rp3d::Transform(rp3d::Vector3(-8, 7, 0), rp3d::Quaternion::identity())); + mCapsule2->setTransform(rp3d::Transform(rp3d::Vector3(11, -8, 0), rp3d::Quaternion::identity())); + mBox1->setTransform(rp3d::Transform(rp3d::Vector3(-4, -7, 0), rp3d::Quaternion::identity())); + mBox2->setTransform(rp3d::Transform(rp3d::Vector3(0, 9, 0), rp3d::Quaternion::identity())); + mConvexMesh->setTransform(rp3d::Transform(rp3d::Vector3(-5, 0, 0), rp3d::Quaternion::identity())); + mConcaveMesh->setTransform(rp3d::Transform(rp3d::Vector3(0, 15, 0), rp3d::Quaternion::identity())); + mHeightField->setTransform(rp3d::Transform(rp3d::Vector3(0, -22, 0), rp3d::Quaternion::identity())); +} + +// Destructor +CollisionDetectionScene::~CollisionDetectionScene() { + + // Destroy the box rigid body from the dynamics world + //mPhysicsWorld->destroyCollisionBody(mBox->getCollisionBody()); + //delete mBox; + + // Destroy the spheres + mPhysicsWorld->destroyCollisionBody(mSphere1->getCollisionBody()); + delete mSphere1; + + mPhysicsWorld->destroyCollisionBody(mSphere2->getCollisionBody()); + delete mSphere2; + + mPhysicsWorld->destroyCollisionBody(mCapsule1->getCollisionBody()); + delete mCapsule1; + + mPhysicsWorld->destroyCollisionBody(mCapsule2->getCollisionBody()); + delete mCapsule2; + + mPhysicsWorld->destroyCollisionBody(mBox1->getCollisionBody()); + delete mBox1; + + mPhysicsWorld->destroyCollisionBody(mBox2->getCollisionBody()); + delete mBox2; + + mPhysicsWorld->destroyCollisionBody(mConvexMesh->getCollisionBody()); + delete mConvexMesh; + + mPhysicsWorld->destroyCollisionBody(mConcaveMesh->getCollisionBody()); + delete mConcaveMesh; + + mPhysicsWorld->destroyCollisionBody(mHeightField->getCollisionBody()); + delete mHeightField; + + mContactManager.resetPoints(); + + // Destroy the static data for the visual contact points + VisualContactPoint::destroyStaticData(); + + // Destroy the collision world + delete mPhysicsWorld; +} + +// Take a step for the simulation +void CollisionDetectionScene::update() { + + mContactManager.resetPoints(); + + mPhysicsWorld->testCollision(&mContactManager); + + SceneDemo::update(); +} + +void CollisionDetectionScene::selectNextShape() { + + uint previousIndex = mSelectedShapeIndex; + mSelectedShapeIndex++; + if (mSelectedShapeIndex >= mAllShapes.size()) { + mSelectedShapeIndex = 0; + } + + mAllShapes[previousIndex]->setColor(mObjectColorDemo); + mAllShapes[mSelectedShapeIndex]->setColor(mSelectedObjectColorDemo); +} + +// Called when a keyboard event occurs +bool CollisionDetectionScene::keyboardEvent(int key, int scancode, int action, int mods) { + + // If the space key has been pressed + if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) { + selectNextShape(); + return true; + } + + float stepDist = 0.2f; + float stepAngle = 15 * (3.14f / 180.0f); + + if (key == GLFW_KEY_RIGHT && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setPosition(transform.getPosition() + rp3d::Vector3(stepDist, 0, 0)); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + else if (key == GLFW_KEY_LEFT && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setPosition(transform.getPosition() + rp3d::Vector3(-stepDist, 0, 0)); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + else if (key == GLFW_KEY_UP && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setPosition(transform.getPosition() + rp3d::Vector3(0, stepDist, 0)); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + else if (key == GLFW_KEY_DOWN && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setPosition(transform.getPosition() + rp3d::Vector3(0, -stepDist, 0)); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + else if (key == GLFW_KEY_Z && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setPosition(transform.getPosition() + rp3d::Vector3(0, 0, stepDist)); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + else if (key == GLFW_KEY_H && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setPosition(transform.getPosition() + rp3d::Vector3(0, 0, -stepDist)); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + else if (key == GLFW_KEY_A && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, stepAngle, 0) * transform.getOrientation()); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + else if (key == GLFW_KEY_D && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, -stepAngle, 0) * transform.getOrientation()); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + else if (key == GLFW_KEY_W && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setOrientation(rp3d::Quaternion::fromEulerAngles(stepAngle, 0, 0) * transform.getOrientation()); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + else if (key == GLFW_KEY_S && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setOrientation(rp3d::Quaternion::fromEulerAngles(-stepAngle, 0, 0) * transform.getOrientation()); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + else if (key == GLFW_KEY_F && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, 0, stepAngle) * transform.getOrientation()); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + else if (key == GLFW_KEY_G && action == GLFW_PRESS) { + rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); + transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, 0, -stepAngle) * transform.getOrientation()); + mAllShapes[mSelectedShapeIndex]->setTransform(transform); + } + + return false; +} + +// This method will be called for each reported contact point +void ContactManager::notifyContact(const CollisionCallbackInfo& collisionCallbackInfo) { + + // For each contact manifold + rp3d::ContactManifoldListElement* manifoldElement = collisionCallbackInfo.contactManifoldElements; + while (manifoldElement != nullptr) { + + // Get the contact manifold + rp3d::ContactManifold* contactManifold = manifoldElement->getContactManifold(); + + // For each contact point + rp3d::ContactPoint* contactPoint = contactManifold->getContactPoints(); + while (contactPoint != nullptr) { + + // Contact normal + rp3d::Vector3 normal = contactPoint->getNormal(); + openglframework::Vector3 contactNormal(normal.x, normal.y, normal.z); + + rp3d::Vector3 point1 = contactPoint->getLocalPointOnShape1(); + point1 = collisionCallbackInfo.proxyShape1->getLocalToWorldTransform() * point1; + + openglframework::Vector3 position1(point1.x, point1.y, point1.z); + mContactPoints.push_back(ContactPoint(position1, contactNormal, openglframework::Color::red())); + + rp3d::Vector3 point2 = contactPoint->getLocalPointOnShape2(); + point2 = collisionCallbackInfo.proxyShape2->getLocalToWorldTransform() * point2; + openglframework::Vector3 position2(point2.x, point2.y, point2.z); + mContactPoints.push_back(ContactPoint(position2, contactNormal, openglframework::Color::blue())); + + contactPoint = contactPoint->getNext(); + } + + manifoldElement = manifoldElement->getNext(); + } +} diff --git a/testbed/scenes/collisionshapes/CollisionShapesScene.cpp b/testbed/scenes/collisionshapes/CollisionShapesScene.cpp index cffe7b50..c89cbfc1 100644 --- a/testbed/scenes/collisionshapes/CollisionShapesScene.cpp +++ b/testbed/scenes/collisionshapes/CollisionShapesScene.cpp @@ -57,8 +57,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin Dumbbell* dumbbell = new Dumbbell(getDynamicsWorld(), meshFolderPath); // Set the box color - dumbbell->setColor(mDemoColors[i % mNbDemoColors]); - dumbbell->setSleepingColor(mRedColorDemo); + dumbbell->setColor(mObjectColorDemo); + dumbbell->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = dumbbell->getRigidBody()->getMaterial(); @@ -76,8 +76,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin Box* box = new Box(BOX_SIZE, BOX_MASS, getDynamicsWorld(), mMeshFolderPath); // Set the box color - box->setColor(mDemoColors[i % mNbDemoColors]); - box->setSleepingColor(mRedColorDemo); + box->setColor(mObjectColorDemo); + box->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = box->getRigidBody()->getMaterial(); @@ -98,8 +98,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin sphere->getRigidBody()->getMaterial().setRollingResistance(rp3d::decimal(0.08)); // Set the box color - sphere->setColor(mDemoColors[i % mNbDemoColors]); - sphere->setSleepingColor(mRedColorDemo); + sphere->setColor(mObjectColorDemo); + sphere->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = sphere->getRigidBody()->getMaterial(); @@ -120,8 +120,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin capsule->getRigidBody()->getMaterial().setRollingResistance(rp3d::decimal(0.08f)); // Set the box color - capsule->setColor(mDemoColors[i % mNbDemoColors]); - capsule->setSleepingColor(mRedColorDemo); + capsule->setColor(mObjectColorDemo); + capsule->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = capsule->getRigidBody()->getMaterial(); @@ -139,8 +139,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin ConvexMesh* mesh = new ConvexMesh(MESH_MASS, getDynamicsWorld(), meshFolderPath + "convexmesh.obj"); // Set the box color - mesh->setColor(mDemoColors[i % mNbDemoColors]); - mesh->setSleepingColor(mRedColorDemo); + mesh->setColor(mObjectColorDemo); + mesh->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = mesh->getRigidBody()->getMaterial(); @@ -157,8 +157,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin mPhysicsObjects.push_back(mFloor); // Set the box color - mFloor->setColor(mGreyColorDemo); - mFloor->setSleepingColor(mGreyColorDemo); + mFloor->setColor(mFloorColorDemo); + mFloor->setSleepingColor(mFloorColorDemo); // The floor must be a static rigid body mFloor->getRigidBody()->setType(rp3d::BodyType::STATIC); diff --git a/testbed/scenes/concavemesh/ConcaveMeshScene.cpp b/testbed/scenes/concavemesh/ConcaveMeshScene.cpp index 31a06c0f..15f09d01 100644 --- a/testbed/scenes/concavemesh/ConcaveMeshScene.cpp +++ b/testbed/scenes/concavemesh/ConcaveMeshScene.cpp @@ -58,8 +58,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett Dumbbell* dumbbell = new Dumbbell(getDynamicsWorld(), meshFolderPath); // Set the box color - dumbbell->setColor(mDemoColors[i % mNbDemoColors]); - dumbbell->setSleepingColor(mRedColorDemo); + dumbbell->setColor(mObjectColorDemo); + dumbbell->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = dumbbell->getRigidBody()->getMaterial(); @@ -77,8 +77,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett Box* box = new Box(BOX_SIZE, BOX_MASS, getDynamicsWorld(), mMeshFolderPath); // Set the box color - box->setColor(mDemoColors[i % mNbDemoColors]); - box->setSleepingColor(mRedColorDemo); + box->setColor(mObjectColorDemo); + box->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = box->getRigidBody()->getMaterial(); @@ -99,8 +99,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett sphere->getRigidBody()->getMaterial().setRollingResistance(rp3d::decimal(0.08)); // Set the box color - sphere->setColor(mDemoColors[i % mNbDemoColors]); - sphere->setSleepingColor(mRedColorDemo); + sphere->setColor(mObjectColorDemo); + sphere->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = sphere->getRigidBody()->getMaterial(); @@ -121,8 +121,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett capsule->getRigidBody()->getMaterial().setRollingResistance(rp3d::decimal(0.08)); // Set the box color - capsule->setColor(mDemoColors[i % mNbDemoColors]); - capsule->setSleepingColor(mRedColorDemo); + capsule->setColor(mObjectColorDemo); + capsule->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = capsule->getRigidBody()->getMaterial(); @@ -140,8 +140,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett ConvexMesh* mesh = new ConvexMesh(MESH_MASS, getDynamicsWorld(), meshFolderPath + "convexmesh.obj"); // Set the box color - mesh->setColor(mDemoColors[i % mNbDemoColors]); - mesh->setSleepingColor(mRedColorDemo); + mesh->setColor(mObjectColorDemo); + mesh->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = mesh->getRigidBody()->getMaterial(); @@ -164,8 +164,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett mConcaveMesh->getRigidBody()->setType(rp3d::BodyType::STATIC); // Set the box color - mConcaveMesh->setColor(mGreyColorDemo); - mConcaveMesh->setSleepingColor(mGreyColorDemo); + mConcaveMesh->setColor(mFloorColorDemo); + mConcaveMesh->setSleepingColor(mFloorColorDemo); mPhysicsObjects.push_back(mConcaveMesh); diff --git a/testbed/scenes/cubes/CubesScene.cpp b/testbed/scenes/cubes/CubesScene.cpp index ab363c0b..ab9689b9 100644 --- a/testbed/scenes/cubes/CubesScene.cpp +++ b/testbed/scenes/cubes/CubesScene.cpp @@ -1,139 +1,139 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://www.reactphysics3d.com * -* Copyright (c) 2010-2016 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 "CubesScene.h" - -// Namespaces -using namespace openglframework; -using namespace cubesscene; - -// Constructor -CubesScene::CubesScene(const std::string& name, EngineSettings& settings) - : SceneDemo(name, settings, SCENE_RADIUS) { - - // Compute the radius and the center of the scene - openglframework::Vector3 center(0, 5, 0); - - // Set the center of the scene - setScenePosition(center, SCENE_RADIUS); - - // Gravity vector in the dynamics world - rp3d::Vector3 gravity(0, rp3d::decimal(-9.81), 0); - - rp3d::WorldSettings worldSettings; - worldSettings.worldName = name; - - // Create the dynamics world for the physics simulation - mPhysicsWorld = new rp3d::DynamicsWorld(gravity, worldSettings); - - // Create all the cubes of the scene - for (int i=0; isetColor(mDemoColors[i % mNbDemoColors]); - cube->setSleepingColor(mRedColorDemo); - - // Change the material properties of the rigid body - rp3d::Material& material = cube->getRigidBody()->getMaterial(); - material.setBounciness(rp3d::decimal(0.4)); - - // Add the box the list of box in the scene - mBoxes.push_back(cube); - mPhysicsObjects.push_back(cube); - } - - // ------------------------- FLOOR ----------------------- // - - // Create the floor - mFloor = new Box(FLOOR_SIZE, FLOOR_MASS, getDynamicsWorld(), mMeshFolderPath); - mFloor->setColor(mGreyColorDemo); - mFloor->setSleepingColor(mGreyColorDemo); - - // The floor must be a static rigid body - mFloor->getRigidBody()->setType(rp3d::BodyType::STATIC); - mPhysicsObjects.push_back(mFloor); - - // Get the physics engine parameters - mEngineSettings.isGravityEnabled = getDynamicsWorld()->isGravityEnabled(); - rp3d::Vector3 gravityVector = getDynamicsWorld()->getGravity(); - mEngineSettings.gravity = openglframework::Vector3(gravityVector.x, gravityVector.y, gravityVector.z); - mEngineSettings.isSleepingEnabled = getDynamicsWorld()->isSleepingEnabled(); - mEngineSettings.sleepLinearVelocity = getDynamicsWorld()->getSleepLinearVelocity(); - mEngineSettings.sleepAngularVelocity = getDynamicsWorld()->getSleepAngularVelocity(); - mEngineSettings.nbPositionSolverIterations = getDynamicsWorld()->getNbIterationsPositionSolver(); - mEngineSettings.nbVelocitySolverIterations = getDynamicsWorld()->getNbIterationsVelocitySolver(); - mEngineSettings.timeBeforeSleep = getDynamicsWorld()->getTimeBeforeSleep(); -} - -// Destructor -CubesScene::~CubesScene() { - - // Destroy all the cubes of the scene - for (std::vector::iterator it = mBoxes.begin(); it != mBoxes.end(); ++it) { - - // Destroy the corresponding rigid body from the dynamics world - getDynamicsWorld()->destroyRigidBody((*it)->getRigidBody()); - - // Destroy the cube - delete (*it); - } - - // Destroy the rigid body of the floor - getDynamicsWorld()->destroyRigidBody(mFloor->getRigidBody()); - - // Destroy the floor - delete mFloor; - - // Destroy the dynamics world - delete getDynamicsWorld(); -} - -// Reset the scene -void CubesScene::reset() { - - float radius = 2.0f; - - // Create all the cubes of the scene - std::vector::iterator it; - int i = 0; - for (it = mBoxes.begin(); it != mBoxes.end(); ++it) { - - // Position of the cubes - float angle = i * 30.0f; - rp3d::Vector3 position(radius * std::cos(angle), - 10 + i * (BOX_SIZE.y + 0.3f), - 0); - - (*it)->setTransform(rp3d::Transform(position, rp3d::Quaternion::identity())); - - i++; - } - - mFloor->setTransform(rp3d::Transform(rp3d::Vector3::zero(), rp3d::Quaternion::identity())); -} +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2016 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 "CubesScene.h" + +// Namespaces +using namespace openglframework; +using namespace cubesscene; + +// Constructor +CubesScene::CubesScene(const std::string& name, EngineSettings& settings) + : SceneDemo(name, settings, SCENE_RADIUS) { + + // Compute the radius and the center of the scene + openglframework::Vector3 center(0, 5, 0); + + // Set the center of the scene + setScenePosition(center, SCENE_RADIUS); + + // Gravity vector in the dynamics world + rp3d::Vector3 gravity(0, rp3d::decimal(-9.81), 0); + + rp3d::WorldSettings worldSettings; + worldSettings.worldName = name; + + // Create the dynamics world for the physics simulation + mPhysicsWorld = new rp3d::DynamicsWorld(gravity, worldSettings); + + // Create all the cubes of the scene + for (int i=0; isetColor(mObjectColorDemo); + cube->setSleepingColor(mSleepingColorDemo); + + // Change the material properties of the rigid body + rp3d::Material& material = cube->getRigidBody()->getMaterial(); + material.setBounciness(rp3d::decimal(0.4)); + + // Add the box the list of box in the scene + mBoxes.push_back(cube); + mPhysicsObjects.push_back(cube); + } + + // ------------------------- FLOOR ----------------------- // + + // Create the floor + mFloor = new Box(FLOOR_SIZE, FLOOR_MASS, getDynamicsWorld(), mMeshFolderPath); + mFloor->setColor(mFloorColorDemo); + mFloor->setSleepingColor(mFloorColorDemo); + + // The floor must be a static rigid body + mFloor->getRigidBody()->setType(rp3d::BodyType::STATIC); + mPhysicsObjects.push_back(mFloor); + + // Get the physics engine parameters + mEngineSettings.isGravityEnabled = getDynamicsWorld()->isGravityEnabled(); + rp3d::Vector3 gravityVector = getDynamicsWorld()->getGravity(); + mEngineSettings.gravity = openglframework::Vector3(gravityVector.x, gravityVector.y, gravityVector.z); + mEngineSettings.isSleepingEnabled = getDynamicsWorld()->isSleepingEnabled(); + mEngineSettings.sleepLinearVelocity = getDynamicsWorld()->getSleepLinearVelocity(); + mEngineSettings.sleepAngularVelocity = getDynamicsWorld()->getSleepAngularVelocity(); + mEngineSettings.nbPositionSolverIterations = getDynamicsWorld()->getNbIterationsPositionSolver(); + mEngineSettings.nbVelocitySolverIterations = getDynamicsWorld()->getNbIterationsVelocitySolver(); + mEngineSettings.timeBeforeSleep = getDynamicsWorld()->getTimeBeforeSleep(); +} + +// Destructor +CubesScene::~CubesScene() { + + // Destroy all the cubes of the scene + for (std::vector::iterator it = mBoxes.begin(); it != mBoxes.end(); ++it) { + + // Destroy the corresponding rigid body from the dynamics world + getDynamicsWorld()->destroyRigidBody((*it)->getRigidBody()); + + // Destroy the cube + delete (*it); + } + + // Destroy the rigid body of the floor + getDynamicsWorld()->destroyRigidBody(mFloor->getRigidBody()); + + // Destroy the floor + delete mFloor; + + // Destroy the dynamics world + delete getDynamicsWorld(); +} + +// Reset the scene +void CubesScene::reset() { + + float radius = 2.0f; + + // Create all the cubes of the scene + std::vector::iterator it; + int i = 0; + for (it = mBoxes.begin(); it != mBoxes.end(); ++it) { + + // Position of the cubes + float angle = i * 30.0f; + rp3d::Vector3 position(radius * std::cos(angle), + 10 + i * (BOX_SIZE.y + 0.3f), + 0); + + (*it)->setTransform(rp3d::Transform(position, rp3d::Quaternion::identity())); + + i++; + } + + mFloor->setTransform(rp3d::Transform(rp3d::Vector3::zero(), rp3d::Quaternion::identity())); +} diff --git a/testbed/scenes/cubestack/CubeStackScene.cpp b/testbed/scenes/cubestack/CubeStackScene.cpp index c30674b3..4d4ffb48 100644 --- a/testbed/scenes/cubestack/CubeStackScene.cpp +++ b/testbed/scenes/cubestack/CubeStackScene.cpp @@ -58,8 +58,8 @@ CubeStackScene::CubeStackScene(const std::string& name, EngineSettings& settings Box* cube = new Box(BOX_SIZE, BOX_MASS, getDynamicsWorld(), mMeshFolderPath); // Set the box color - cube->setColor(mDemoColors[i % mNbDemoColors]); - cube->setSleepingColor(mRedColorDemo); + cube->setColor(mObjectColorDemo); + cube->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = cube->getRigidBody()->getMaterial(); @@ -75,8 +75,8 @@ CubeStackScene::CubeStackScene(const std::string& name, EngineSettings& settings // Create the floor mFloor = new Box(FLOOR_SIZE, FLOOR_MASS, getDynamicsWorld(), mMeshFolderPath); - mFloor->setColor(mGreyColorDemo); - mFloor->setSleepingColor(mGreyColorDemo); + mFloor->setColor(mFloorColorDemo); + mFloor->setSleepingColor(mFloorColorDemo); // The floor must be a static rigid body mFloor->getRigidBody()->setType(rp3d::BodyType::STATIC); diff --git a/testbed/scenes/heightfield/HeightFieldScene.cpp b/testbed/scenes/heightfield/HeightFieldScene.cpp index 8b8d489c..e9be88a4 100644 --- a/testbed/scenes/heightfield/HeightFieldScene.cpp +++ b/testbed/scenes/heightfield/HeightFieldScene.cpp @@ -57,8 +57,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett Dumbbell* dumbbell = new Dumbbell(getDynamicsWorld(), meshFolderPath); // Set the box color - dumbbell->setColor(mDemoColors[i % mNbDemoColors]); - dumbbell->setSleepingColor(mRedColorDemo); + dumbbell->setColor(mObjectColorDemo); + dumbbell->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = dumbbell->getRigidBody()->getMaterial(); @@ -76,8 +76,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett Box* box = new Box(BOX_SIZE, BOX_MASS, getDynamicsWorld(), mMeshFolderPath); // Set the box color - box->setColor(mDemoColors[i % mNbDemoColors]); - box->setSleepingColor(mRedColorDemo); + box->setColor(mObjectColorDemo); + box->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = box->getRigidBody()->getMaterial(); @@ -98,8 +98,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett sphere->getRigidBody()->getMaterial().setRollingResistance(0.08f); // Set the box color - sphere->setColor(mDemoColors[i % mNbDemoColors]); - sphere->setSleepingColor(mRedColorDemo); + sphere->setColor(mObjectColorDemo); + sphere->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = sphere->getRigidBody()->getMaterial(); @@ -120,8 +120,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett capsule->getRigidBody()->getMaterial().setRollingResistance(0.08f); // Set the box color - capsule->setColor(mDemoColors[i % mNbDemoColors]); - capsule->setSleepingColor(mRedColorDemo); + capsule->setColor(mObjectColorDemo); + capsule->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = capsule->getRigidBody()->getMaterial(); @@ -139,8 +139,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett ConvexMesh* mesh = new ConvexMesh(MESH_MASS, getDynamicsWorld(), meshFolderPath + "convexmesh.obj"); // Set the box color - mesh->setColor(mDemoColors[i % mNbDemoColors]); - mesh->setSleepingColor(mRedColorDemo); + mesh->setColor(mObjectColorDemo); + mesh->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = mesh->getRigidBody()->getMaterial(); @@ -165,8 +165,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett mPhysicsObjects.push_back(mHeightField); // Set the color - mHeightField->setColor(mGreyColorDemo); - mHeightField->setSleepingColor(mGreyColorDemo); + mHeightField->setColor(mFloorColorDemo); + mHeightField->setSleepingColor(mFloorColorDemo); // Change the material properties of the rigid body rp3d::Material& material = mHeightField->getRigidBody()->getMaterial(); diff --git a/testbed/scenes/joints/JointsScene.cpp b/testbed/scenes/joints/JointsScene.cpp index 736e0252..9a035717 100644 --- a/testbed/scenes/joints/JointsScene.cpp +++ b/testbed/scenes/joints/JointsScene.cpp @@ -214,8 +214,8 @@ void JointsScene::createBallAndSocketJoints() { mBallAndSocketJointChainBoxes[i]->setTransform(rp3d::Transform(positionBox, rp3d::Quaternion::identity())); // Set the box color - mBallAndSocketJointChainBoxes[i]->setColor(mDemoColors[i % mNbDemoColors]); - mBallAndSocketJointChainBoxes[i]->setSleepingColor(mRedColorDemo); + mBallAndSocketJointChainBoxes[i]->setColor(mObjectColorDemo); + mBallAndSocketJointChainBoxes[i]->setSleepingColor(mSleepingColorDemo); // The fist box cannot move (static body) if (i == 0) { @@ -266,8 +266,8 @@ void JointsScene::createSliderJoint() { mSliderJointBottomBox->setTransform(rp3d::Transform(positionBox1, rp3d::Quaternion::identity())); // Set the box color - mSliderJointBottomBox->setColor(mBlueColorDemo); - mSliderJointBottomBox->setSleepingColor(mRedColorDemo); + mSliderJointBottomBox->setColor(mObjectColorDemo); + mSliderJointBottomBox->setSleepingColor(mSleepingColorDemo); // The fist box cannot move mSliderJointBottomBox->getRigidBody()->setType(rp3d::BodyType::STATIC); @@ -288,8 +288,8 @@ void JointsScene::createSliderJoint() { mSliderJointTopBox->setTransform(rp3d::Transform(positionBox2, rp3d::Quaternion::identity())); // Set the box color - mSliderJointTopBox->setColor(mOrangeColorDemo); - mSliderJointTopBox->setSleepingColor(mRedColorDemo); + mSliderJointTopBox->setColor(mObjectColorDemo); + mSliderJointTopBox->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material2 = mSliderJointTopBox->getRigidBody()->getMaterial(); @@ -330,8 +330,8 @@ void JointsScene::createPropellerHingeJoint() { mPropellerBox->setTransform(rp3d::Transform(positionBox1, rp3d::Quaternion::identity())); // Set the box color - mPropellerBox->setColor(mYellowColorDemo); - mPropellerBox->setSleepingColor(mRedColorDemo); + mPropellerBox->setColor(mObjectColorDemo); + mPropellerBox->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material = mPropellerBox->getRigidBody()->getMaterial(); @@ -371,8 +371,8 @@ void JointsScene::createFixedJoints() { mFixedJointBox1->setTransform(rp3d::Transform(positionBox1, rp3d::Quaternion::identity())); // Set the box color - mFixedJointBox1->setColor(mPinkColorDemo); - mFixedJointBox1->setSleepingColor(mRedColorDemo); + mFixedJointBox1->setColor(mObjectColorDemo); + mFixedJointBox1->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material1 = mFixedJointBox1->getRigidBody()->getMaterial(); @@ -389,8 +389,8 @@ void JointsScene::createFixedJoints() { mFixedJointBox2->setTransform(rp3d::Transform(positionBox2, rp3d::Quaternion::identity())); // Set the box color - mFixedJointBox2->setColor(mBlueColorDemo); - mFixedJointBox2->setSleepingColor(mRedColorDemo); + mFixedJointBox2->setColor(mObjectColorDemo); + mFixedJointBox2->setSleepingColor(mSleepingColorDemo); // Change the material properties of the rigid body rp3d::Material& material2 = mFixedJointBox2->getRigidBody()->getMaterial(); @@ -429,8 +429,8 @@ void JointsScene::createFloor() { mFloor = new Box(FLOOR_SIZE, FLOOR_MASS, getDynamicsWorld(), mMeshFolderPath); // Set the box color - mFloor->setColor(mGreyColorDemo); - mFloor->setSleepingColor(mGreyColorDemo); + mFloor->setColor(mFloorColorDemo); + mFloor->setSleepingColor(mFloorColorDemo); // The floor must be a static rigid body mFloor->getRigidBody()->setType(rp3d::BodyType::STATIC); diff --git a/testbed/scenes/raycast/RaycastScene.cpp b/testbed/scenes/raycast/RaycastScene.cpp index 018c28e4..f789726e 100644 --- a/testbed/scenes/raycast/RaycastScene.cpp +++ b/testbed/scenes/raycast/RaycastScene.cpp @@ -56,8 +56,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings) mDumbbell = new Dumbbell(mPhysicsWorld, mMeshFolderPath); // Set the box color - mDumbbell->setColor(mGreyColorDemo); - mDumbbell->setSleepingColor(mRedColorDemo); + mDumbbell->setColor(mObjectColorDemo); + mDumbbell->setSleepingColor(mSleepingColorDemo); mPhysicsObjects.push_back(mDumbbell); // ---------- Box ---------- // @@ -67,8 +67,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings) mBox->getCollisionBody()->setIsActive(false); // Set the box color - mBox->setColor(mGreyColorDemo); - mBox->setSleepingColor(mRedColorDemo); + mBox->setColor(mObjectColorDemo); + mBox->setSleepingColor(mSleepingColorDemo); mPhysicsObjects.push_back(mBox); // ---------- Sphere ---------- // @@ -77,8 +77,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings) mSphere = new Sphere(SPHERE_RADIUS, mPhysicsWorld, mMeshFolderPath); // Set the color - mSphere->setColor(mGreyColorDemo); - mSphere->setSleepingColor(mRedColorDemo); + mSphere->setColor(mObjectColorDemo); + mSphere->setSleepingColor(mSleepingColorDemo); mPhysicsObjects.push_back(mSphere); // ---------- Capsule ---------- // @@ -88,8 +88,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings) mCapsule = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, mPhysicsWorld, mMeshFolderPath); // Set the color - mCapsule->setColor(mGreyColorDemo); - mCapsule->setSleepingColor(mRedColorDemo); + mCapsule->setColor(mObjectColorDemo); + mCapsule->setSleepingColor(mSleepingColorDemo); mPhysicsObjects.push_back(mCapsule); // ---------- Convex Mesh ---------- // @@ -98,8 +98,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings) mConvexMesh = new ConvexMesh(mPhysicsWorld, mMeshFolderPath + "convexmesh.obj"); // Set the color - mConvexMesh->setColor(mGreyColorDemo); - mConvexMesh->setSleepingColor(mRedColorDemo); + mConvexMesh->setColor(mObjectColorDemo); + mConvexMesh->setSleepingColor(mSleepingColorDemo); mPhysicsObjects.push_back(mConvexMesh); // ---------- Concave Mesh ---------- // @@ -108,8 +108,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings) mConcaveMesh = new ConcaveMesh(mPhysicsWorld, mMeshFolderPath + "city.obj"); // Set the color - mConcaveMesh->setColor(mGreyColorDemo); - mConcaveMesh->setSleepingColor(mRedColorDemo); + mConcaveMesh->setColor(mObjectColorDemo); + mConcaveMesh->setSleepingColor(mSleepingColorDemo); mPhysicsObjects.push_back(mConcaveMesh); // ---------- Heightfield ---------- // @@ -118,8 +118,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings) mHeightField = new HeightField(mPhysicsWorld); // Set the color - mHeightField->setColor(mGreyColorDemo); - mHeightField->setSleepingColor(mRedColorDemo); + mHeightField->setColor(mObjectColorDemo); + mHeightField->setSleepingColor(mObjectColorDemo); mPhysicsObjects.push_back(mHeightField); // Create the lines that will be used for raycasting diff --git a/testbed/shaders/phong.frag b/testbed/shaders/phong.frag index 73c76ba6..5e7f726a 100644 --- a/testbed/shaders/phong.frag +++ b/testbed/shaders/phong.frag @@ -1,103 +1,115 @@ -#version 330 - -/******************************************************************************** -* OpenGL-Framework * -* Copyright (c) 2015 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. * -* * -********************************************************************************/ - -// Uniform variables -uniform vec3 lightAmbientColor; // Lights ambient color -uniform vec3 light0PosCameraSpace; // Camera-space position of the light -uniform vec3 light0DiffuseColor; // Light 0 diffuse color -uniform sampler2D textureSampler; // Texture -uniform sampler2D shadowMapSampler; // Shadow map texture sampler -uniform bool isTexture; // True if we need to use the texture -uniform vec4 vertexColor; // Vertex color -uniform bool isShadowEnabled; // True if shadow mapping is enabled -uniform vec2 shadowMapDimension; // Shadow map dimension - -// In variables -in vec3 vertexPosCameraSpace; // Camera-space position of the vertex -in vec3 vertexNormalCameraSpace; // Vertex normal in camera-space -in vec2 texCoords; // Texture coordinates -in vec4 shadowMapCoords; // Shadow map texture coords - -// Out variable -out vec4 color; // Output color - -// Texture for PCF Shadow mapping -float textureLookupPCF(sampler2D map, vec2 texCoords, vec2 offset) -{ - vec2 shadowMapScale = vec2(1.0, 1.0) / shadowMapDimension; - return texture(map, texCoords.xy + offset * shadowMapScale).r; -} - -void main() { - - // Compute the ambient term - vec3 ambient = lightAmbientColor; - - // Get the texture color - vec3 textureColor = vertexColor.rgb; - if (isTexture) textureColor = texture(textureSampler, texCoords).rgb; - - // Compute the surface normal vector - vec3 N = normalize(vertexNormalCameraSpace); - - // Compute the diffuse term of light 0 - vec3 L0 = normalize(light0PosCameraSpace - vertexPosCameraSpace); - float diffuseFactor = max(dot(N, L0), 0.0); - vec3 diffuse = light0DiffuseColor * diffuseFactor * textureColor; - - // Compute shadow factor - float shadow = 1.0; - if (isShadowEnabled) { - shadow = 0.0; - float bias = 0.0003; - float shadowBias = -0.000; - vec4 shadowMapUV = shadowMapCoords; - shadowMapUV.z -= shadowBias; - vec4 shadowMapCoordsOverW = shadowMapUV / shadowMapUV.w; - - // PCF Shadow Mapping - for (float i=-1; i<=1; i++) { - for (float j=-1; j<=1; j++) { - float distInShadowMap = textureLookupPCF(shadowMapSampler, shadowMapCoordsOverW.xy, vec2(i, j)) + bias; - if (shadowMapCoords.w > 0) { - shadow += distInShadowMap < shadowMapCoordsOverW.z ? 0.5 : 1.0; - } - } - } - shadow /= 9.0; - - /* - float distanceInShadowMap = texture(shadowMapSampler, shadowMapCoordsOverW.xy).r + bias; - if (shadowMapCoords.w > 0) { - shadow = distanceInShadowMap < shadowMapCoordsOverW.z ? 0.5 : 1.0; - } - */ - } - - // Compute the final color - color = vec4(ambient + shadow * diffuse, 1.0); -} +#version 330 + +/******************************************************************************** +* OpenGL-Framework * +* Copyright (c) 2015 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. * +* * +********************************************************************************/ + +// Uniform variables +uniform vec3 lightAmbientColor; // Lights ambient color +uniform vec3 light0PosCameraSpace; // Camera-space position of the light 0 +uniform vec3 light1PosCameraSpace; // Camera-space position of the light 1 +uniform vec3 light2PosCameraSpace; // Camera-space position of the light 2 +uniform vec3 light0DiffuseColor; // Light 0 diffuse color +uniform vec3 light1DiffuseColor; // Light 1 diffuse color +uniform vec3 light2DiffuseColor; // Light 2 diffuse color +uniform sampler2D textureSampler; // Texture +uniform sampler2D shadowMapSampler[3]; // Shadow map texture sampler +uniform bool isTexture; // True if we need to use the texture +uniform vec4 vertexColor; // Vertex color +uniform bool isShadowEnabled; // True if shadow mapping is enabled +uniform vec2 shadowMapDimension; // Shadow map dimension + +// In variables +in vec3 vertexPosCameraSpace; // Camera-space position of the vertex +in vec3 vertexNormalCameraSpace; // Vertex normal in camera-space +in vec2 texCoords; // Texture coordinates +in vec4 shadowMapCoords[3]; // Shadow map texture coords + +// Out variable +out vec4 color; // Output color + +// Texture for PCF Shadow mapping +float textureLookupPCF(sampler2D map, vec2 texCoords, vec2 offset) +{ + vec2 shadowMapScale = vec2(1.0, 1.0) / shadowMapDimension; + return texture(map, texCoords.xy + offset * shadowMapScale).r; +} + +void main() { + + // Compute the ambient term + vec3 ambient = lightAmbientColor; + + // Get the texture color + vec3 textureColor = vertexColor.rgb; + if (isTexture) textureColor = texture(textureSampler, texCoords).rgb; + + // Compute the surface normal vector + vec3 N = normalize(vertexNormalCameraSpace); + + color = vec4(ambient, 1); + + vec3 lightPosCameraSpace[3]; + lightPosCameraSpace[0] = light0PosCameraSpace; + lightPosCameraSpace[1] = light1PosCameraSpace; + lightPosCameraSpace[2] = light2PosCameraSpace; + vec3 lightDiffuseColor[3]; + lightDiffuseColor[0] = light0DiffuseColor; + lightDiffuseColor[1] = light1DiffuseColor; + lightDiffuseColor[2] = light2DiffuseColor; + + // For each light source + for (int l=0; l < 3; l++) { + + // Compute the diffuse term of light 0 + vec3 L0 = normalize(lightPosCameraSpace[l] - vertexPosCameraSpace); + float diffuseFactor = max(dot(N, L0), 0.0); + vec3 diffuse = lightDiffuseColor[l] * diffuseFactor * textureColor; + + // Compute shadow factor + float shadow = 1.0; + if (isShadowEnabled) { + shadow = 0.0; + float bias = 0.0003; + float shadowBias = -0.000; + vec4 shadowMapUV = shadowMapCoords[l]; + shadowMapUV.z -= shadowBias; + vec4 shadowMapCoordsOverW = shadowMapUV / shadowMapUV.w; + + // PCF Shadow Mapping + for (float i=-1; i<=1; i++) { + for (float j=-1; j<=1; j++) { + float distInShadowMap = textureLookupPCF(shadowMapSampler[l], shadowMapCoordsOverW.xy, vec2(i, j)) + bias; + if (shadowMapCoords[l].w > 0) { + shadow += distInShadowMap < shadowMapCoordsOverW.z ? 0.5 : 1.0; + } + } + } + shadow /= 9.0; + } + + // Compute the final color + color += vec4(shadow * diffuse, 0.0); + } +} diff --git a/testbed/shaders/phong.vert b/testbed/shaders/phong.vert index 491558fb..6cc72075 100644 --- a/testbed/shaders/phong.vert +++ b/testbed/shaders/phong.vert @@ -1,64 +1,78 @@ -#version 330 - -/******************************************************************************** -* OpenGL-Framework * -* Copyright (c) 2015 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. * -* * -********************************************************************************/ - -// Uniform variables -uniform mat4 localToWorldMatrix; // Local-space to world-space matrix -uniform mat4 worldToCameraMatrix; // World-space to camera-space matrix -uniform mat4 worldToLight0CameraMatrix; // World-space to light0 camera-space matrix (for shadow mapping) -uniform mat4 projectionMatrix; // Projection matrix -uniform mat3 normalMatrix; // Normal matrix -uniform mat4 shadowMapProjectionMatrix; // Shadow map projection matrix - -// In variables -in vec4 vertexPosition; -in vec3 vertexNormal; -in vec2 textureCoords; - -// Out variables -out vec3 vertexPosCameraSpace; // Camera-space position of the vertex -out vec3 vertexNormalCameraSpace; // Vertex normal in camera-space -out vec2 texCoords; // Texture coordinates -out vec4 shadowMapCoords; // Shadow map texture coords - -void main() { - - // Compute the vertex position - vec4 positionCameraSpace = worldToCameraMatrix * localToWorldMatrix * vertexPosition; - vertexPosCameraSpace = positionCameraSpace.xyz; - - // Compute the world surface normal - vertexNormalCameraSpace = normalMatrix * vertexNormal; - - // Get the texture coordinates - texCoords = textureCoords; - - // Compute the texture coords of the vertex in the shadow map - shadowMapCoords = shadowMapProjectionMatrix * worldToLight0CameraMatrix * localToWorldMatrix * vertexPosition; - - // Compute the clip-space vertex coordinates - gl_Position = projectionMatrix * positionCameraSpace; -} +#version 330 + +/******************************************************************************** +* OpenGL-Framework * +* Copyright (c) 2015 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. * +* * +********************************************************************************/ + +// Uniform variables +uniform mat4 localToWorldMatrix; // Local-space to world-space matrix +uniform mat4 worldToCameraMatrix; // World-space to camera-space matrix +uniform mat4 worldToLight0CameraMatrix; // World-space to light0 camera-space matrix (for shadow mapping) +uniform mat4 worldToLight1CameraMatrix; // World-space to light1 camera-space matrix (for shadow mapping) +uniform mat4 worldToLight2CameraMatrix; // World-space to light2 camera-space matrix (for shadow mapping) +uniform mat4 projectionMatrix; // Projection matrix +uniform mat3 normalMatrix; // Normal matrix +uniform mat4 shadowMapLight0ProjectionMatrix; // Shadow map projection matrix for light 0 +uniform mat4 shadowMapLight1ProjectionMatrix; // Shadow map projection matrix for light 1 +uniform mat4 shadowMapLight2ProjectionMatrix; // Shadow map projection matrix for light 2 + +// In variables +in vec4 vertexPosition; +in vec3 vertexNormal; +in vec2 textureCoords; + +// Out variables +out vec3 vertexPosCameraSpace; // Camera-space position of the vertex +out vec3 vertexNormalCameraSpace; // Vertex normal in camera-space +out vec2 texCoords; // Texture coordinates +out vec4 shadowMapCoords[3]; // Shadow map texture coords + +void main() { + + // Compute the vertex position + vec4 positionCameraSpace = worldToCameraMatrix * localToWorldMatrix * vertexPosition; + vertexPosCameraSpace = positionCameraSpace.xyz; + + // Compute the world surface normal + vertexNormalCameraSpace = normalMatrix * vertexNormal; + + // Get the texture coordinates + texCoords = textureCoords; + + // Compute the texture coords of the vertex in the shadow map + mat4 worldToLightCameraMatrix[3]; + worldToLightCameraMatrix[0] = worldToLight0CameraMatrix; + worldToLightCameraMatrix[1] = worldToLight1CameraMatrix; + worldToLightCameraMatrix[2] = worldToLight2CameraMatrix; + mat4 shadowMapProjectionMatrix[3]; + shadowMapProjectionMatrix[0] = shadowMapLight0ProjectionMatrix; + shadowMapProjectionMatrix[1] = shadowMapLight1ProjectionMatrix; + shadowMapProjectionMatrix[2] = shadowMapLight2ProjectionMatrix; + for (int l=0; l < 3; l++) { + shadowMapCoords[l] = shadowMapProjectionMatrix[l] * worldToLightCameraMatrix[l] * localToWorldMatrix * vertexPosition; + } + + // Compute the clip-space vertex coordinates + gl_Position = projectionMatrix * positionCameraSpace; +} diff --git a/testbed/src/Main.cpp b/testbed/src/Main.cpp index fbfb9e04..a8b73604 100644 --- a/testbed/src/Main.cpp +++ b/testbed/src/Main.cpp @@ -1,49 +1,64 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://www.reactphysics3d.com * -* Copyright (c) 2010-2016 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 "TestbedApplication.h" -#include "nanogui/nanogui.h" - -using namespace nanogui; - -// Main function -int main(int argc, char** argv) { - - nanogui::init(); - - { - // Create and start the testbed application - bool isFullscreen = false; - nanogui::ref application = new TestbedApplication(isFullscreen); - application->setVisible(true); - - nanogui::mainloop(); - } - - nanogui::shutdown(); - - return 0; -} +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2016 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 "TestbedApplication.h" +#include "nanogui/nanogui.h" + +using namespace nanogui; + +// Main function +int main(int argc, char** argv) { + + nanogui::init(); + + { + bool isFullscreen = false; + + // Get the primary monitor + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + + // Window size + int windowWidth = mode->width; + int windowHeight = mode->height; + + if (!isFullscreen) { + + windowWidth *= 0.9; + windowHeight *= 0.9; + } + + // Create and start the testbed application + nanogui::ref application = new TestbedApplication(isFullscreen, windowWidth, windowHeight); + application->setVisible(true); + + nanogui::mainloop(); + } + + nanogui::shutdown(); + + return 0; +} diff --git a/testbed/src/SceneDemo.cpp b/testbed/src/SceneDemo.cpp index 97d0779e..a75171b0 100644 --- a/testbed/src/SceneDemo.cpp +++ b/testbed/src/SceneDemo.cpp @@ -1,460 +1,522 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://www.reactphysics3d.com * -* Copyright (c) 2010-2016 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 "SceneDemo.h" -#include -#include "AABB.h" -#include "constraint/ContactPoint.h" -#include "collision/ContactManifold.h" - -using namespace openglframework; - -int SceneDemo::shadowMapTextureLevel = 0; -openglframework::Color SceneDemo::mGreyColorDemo = Color(0.70f, 0.70f, 0.7f, 1.0f); -openglframework::Color SceneDemo::mYellowColorDemo = Color(0.9f, 0.88f, 0.145f, 1.0f); -openglframework::Color SceneDemo::mBlueColorDemo = Color(0, 0.66f, 0.95f, 1.0f); -openglframework::Color SceneDemo::mOrangeColorDemo = Color(0.9f, 0.35f, 0, 1.0f); -openglframework::Color SceneDemo::mPinkColorDemo = Color(0.83f, 0.48f, 0.64f, 1.0f); -openglframework::Color SceneDemo::mRedColorDemo = Color(0.95f, 0, 0, 1.0f); -int SceneDemo::mNbDemoColors = 4; -openglframework::Color SceneDemo::mDemoColors[] = {SceneDemo::mYellowColorDemo, SceneDemo::mBlueColorDemo, - SceneDemo::mOrangeColorDemo, SceneDemo::mPinkColorDemo}; - -// Constructor -SceneDemo::SceneDemo(const std::string& name, EngineSettings& settings, float sceneRadius, bool isShadowMappingEnabled) - : Scene(name, settings, isShadowMappingEnabled), mIsShadowMappingInitialized(false), - mDepthShader("shaders/depth.vert", "shaders/depth.frag"), - mPhongShader("shaders/phong.vert", "shaders/phong.frag"), - mColorShader("shaders/color.vert", "shaders/color.frag"), - mQuadShader("shaders/quad.vert", "shaders/quad.frag"), - mVBOQuad(GL_ARRAY_BUFFER), mMeshFolderPath("meshes/"), - mPhysicsWorld(nullptr) { - - shadowMapTextureLevel++; - - // Move the light0 - mLight0.translateWorld(Vector3(-2, 35, 40)); - - // Camera at light0 postion for the shadow map - mShadowMapLightCamera.translateWorld(mLight0.getOrigin()); - mShadowMapLightCamera.rotateLocal(Vector3(1, 0, 0), -PI / 4.0f); - mShadowMapLightCamera.rotateWorld(Vector3(0, 1, 0), PI / 8.0f); - - mShadowMapLightCamera.setDimensions(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT); - mShadowMapLightCamera.setFieldOfView(80.0f); - mShadowMapLightCamera.setSceneRadius(100); - - mShadowMapBiasMatrix.setAllValues(0.5, 0.0, 0.0, 0.5, - 0.0, 0.5, 0.0, 0.5, - 0.0, 0.0, 0.5, 0.5, - 0.0, 0.0, 0.0, 1.0); - - // Create the Shadow map FBO and texture - if (mIsShadowMappingEnabled) { - createShadowMapFBOAndTexture(); - } - - createQuadVBO(); - - // Init rendering for the AABBs - AABB::init(); - - VisualContactPoint::createStaticData(mMeshFolderPath); -} - -// Destructor -SceneDemo::~SceneDemo() { - - mShadowMapTexture.destroy(); - mFBOShadowMap.destroy(); - mVBOQuad.destroy(); - - mDepthShader.destroy(); - mPhongShader.destroy(); - mQuadShader.destroy(); - mColorShader.destroy(); - - // Destroy the contact points - removeAllContactPoints(); - - // Destroy rendering data for the AABB - AABB::destroy(); - - VisualContactPoint::destroyStaticData(); -} - -// Update the scene -void SceneDemo::update() { - - // Update the contact points - updateContactPoints(); - - // Update the position and orientation of the physics objects - for (std::vector::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) { - - // Update the transform used for the rendering - (*it)->updateTransform(mInterpolationFactor); - } -} - -// Update the physics world (take a simulation step) -// Can be called several times per frame -void SceneDemo::updatePhysics() { - - if (getDynamicsWorld() != nullptr) { - - // Take a simulation step - getDynamicsWorld()->update(mEngineSettings.timeStep); - } -} - -// Render the scene (in multiple passes for shadow mapping) -void SceneDemo::render() { - - const Color& diffCol = mLight0.getDiffuseColor(); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - - // ---------- Render the scene to generate the shadow map (first pass) ----------- // - - const Matrix4 shadowMapProjMatrix = mShadowMapLightCamera.getProjectionMatrix(); - const openglframework::Matrix4 worldToLightCameraMatrix = mShadowMapLightCamera.getTransformMatrix().getInverse(); - - // If Shadow Mapping is enabled - if (mIsShadowMappingEnabled) { - - // Culling switching, rendering only backface, this is done to avoid self-shadowing - glCullFace(GL_BACK); - - mFBOShadowMap.bind(); - - // Bind the shader - mDepthShader.bind(); - - // Set the variables of the shader - mDepthShader.setMatrix4x4Uniform("projectionMatrix", shadowMapProjMatrix); - - // Set the viewport to render into the shadow map texture - glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT); - - // Clear previous frame values - glClear(GL_DEPTH_BUFFER_BIT); - - // Disable color rendering, we only want to write to the Z-Buffer - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - - // Render the objects of the scene - renderSinglePass(mDepthShader, worldToLightCameraMatrix); - - // Unbind the shader - mDepthShader.unbind(); - - mFBOShadowMap.unbind(); - - glDisable(GL_POLYGON_OFFSET_FILL); - } - - // ---------- Render the scene for final rendering (second pass) ----------- // - - glCullFace(GL_BACK); - - // Get the world-space to camera-space matrix - const openglframework::Matrix4 worldToCameraMatrix = mCamera.getTransformMatrix().getInverse(); - - mPhongShader.bind(); - - if (mIsShadowMappingEnabled) mShadowMapTexture.bind(); - const GLuint textureUnit = 0; - - // Set the variables of the phong shader - mPhongShader.setMatrix4x4Uniform("projectionMatrix", mCamera.getProjectionMatrix()); - mPhongShader.setMatrix4x4Uniform("shadowMapProjectionMatrix", mShadowMapBiasMatrix * shadowMapProjMatrix); - mPhongShader.setMatrix4x4Uniform("worldToLight0CameraMatrix", worldToLightCameraMatrix); - mPhongShader.setVector3Uniform("light0PosCameraSpace", worldToCameraMatrix * mLight0.getOrigin()); - mPhongShader.setVector3Uniform("lightAmbientColor", Vector3(0.4f, 0.4f, 0.4f)); - mPhongShader.setVector3Uniform("light0DiffuseColor", Vector3(diffCol.r, diffCol.g, diffCol.b)); - mPhongShader.setIntUniform("shadowMapSampler", textureUnit); - mPhongShader.setIntUniform("isShadowEnabled", mIsShadowMappingEnabled); - mPhongShader.setVector2Uniform("shadowMapDimension", Vector2(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT)); - mPhongShader.unbind(); - - // Set the variables of the color shader - mColorShader.bind(); - mColorShader.setMatrix4x4Uniform("projectionMatrix", mCamera.getProjectionMatrix()); - mColorShader.unbind(); - - // Set the viewport to render the scene - glViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight); - - //Enabling color write (previously disabled for light POV z-buffer rendering) - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - // Clear previous frame values - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // Render the objects of the scene - renderSinglePass(mPhongShader, worldToCameraMatrix); - - // Render the contact points - if (mIsContactPointsDisplayed) { - renderContactPoints(mPhongShader, worldToCameraMatrix); - } - - // Render the AABBs - if (mIsAABBsDisplayed) { - renderAABBs(worldToCameraMatrix); - } - - if (mIsShadowMappingEnabled) mShadowMapTexture.unbind(); - mPhongShader.unbind(); - - //drawTextureQuad(); -} - -// Render the scene in a single pass -void SceneDemo::renderSinglePass(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix) { - - if (mIsWireframeEnabled) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } - - // Bind the shader - shader.bind(); - - // Render all the physics objects of the scene - for (std::vector::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) { - (*it)->render(mIsWireframeEnabled ? mColorShader : shader, worldToCameraMatrix); - } - - // Unbind the shader - shader.unbind(); - - if (mIsWireframeEnabled) { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } -} - -// Create the Shadow map FBO and texture -void SceneDemo::createShadowMapFBOAndTexture() { - - // Create the texture for the depth values - mShadowMapTexture.create(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, - GL_UNSIGNED_BYTE, GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, NULL); - - // Create the FBO for the shadow map - mFBOShadowMap.create(0, 0, false); - mFBOShadowMap.bind(); - - // Tell OpenGL that we won't bind a color texture with the currently binded FBO - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - - mFBOShadowMap.attachTexture(GL_DEPTH_ATTACHMENT, mShadowMapTexture.getID()); - mFBOShadowMap.unbind(); - - mIsShadowMappingInitialized = true; -} - -// Used for debugging shadow maps -void SceneDemo::createQuadVBO() { - - mVAOQuad.create(); - mVAOQuad.bind(); - - static const GLfloat quadVertexData[] = { - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, - }; - - mVBOQuad.create(); - mVBOQuad.bind(); - mVBOQuad.copyDataIntoVBO(sizeof(quadVertexData), quadVertexData, GL_STATIC_DRAW); - mVBOQuad.unbind(); - - mVAOQuad.unbind(); -} - -void SceneDemo::drawTextureQuad() { - - glViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - // Clear previous frame values - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - const GLuint textureUnit = 0; - - mVAOQuad.bind(); - mQuadShader.bind(); - mShadowMapTexture.bind(); - mQuadShader.setIntUniform("textureSampler", textureUnit); - mVBOQuad.bind(); - - GLint vertexPositionLoc = mQuadShader.getAttribLocation("vertexPosition"); - glEnableVertexAttribArray(vertexPositionLoc); - - glVertexAttribPointer( - vertexPositionLoc, // attribute 0. No particular reason for 0, but must match the layout in the shader. - 3, // size - GL_FLOAT, // type - GL_FALSE, // normalized? - 0, // stride - (void*)0 // array buffer offset - ); - - // Draw the triangles ! - glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles - - glDisableVertexAttribArray(vertexPositionLoc); - - mVBOQuad.unbind(); - mShadowMapTexture.unbind(); - mQuadShader.unbind(); - mVAOQuad.unbind(); -} - -// Gather and create contact points -void SceneDemo::updateContactPoints() { - - // Remove the previous contact points - removeAllContactPoints(); - - if (mIsContactPointsDisplayed) { - - // Get the current contact points of the scene - std::vector contactPoints = getContactPoints(); - - // For each contact point - std::vector::const_iterator it; - for (it = contactPoints.begin(); it != contactPoints.end(); ++it) { - - // Create a visual contact point for rendering - VisualContactPoint* point = new VisualContactPoint(it->point, mMeshFolderPath, it->point + it->normal, it->color); - mContactPoints.push_back(point); - } - } -} - -// Render the contact points -void SceneDemo::renderContactPoints(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix) { - - // Render all the contact points - for (std::vector::iterator it = mContactPoints.begin(); - it != mContactPoints.end(); ++it) { - (*it)->render(mColorShader, worldToCameraMatrix); - } -} - -// Render the AABBs -void SceneDemo::renderAABBs(const openglframework::Matrix4& worldToCameraMatrix) { - - // For each physics object of the scene - for (std::vector::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) { - - // For each proxy shape of the object - rp3d::ProxyShape* proxyShape = (*it)->getCollisionBody()->getProxyShapesList(); - while (proxyShape != nullptr) { - - // Get the broad-phase AABB corresponding to the proxy shape - rp3d::AABB aabb = mPhysicsWorld->getWorldAABB(proxyShape); - - openglframework::Vector3 aabbCenter(aabb.getCenter().x, aabb.getCenter().y, aabb.getCenter().z); - openglframework::Vector3 aabbMin(aabb.getMin().x, aabb.getMin().y, aabb.getMin().z); - openglframework::Vector3 aabbMax(aabb.getMax().x, aabb.getMax().y, aabb.getMax().z); - - // Render the AABB - AABB::render(aabbCenter, aabbMax - aabbMin, Color::green(), mColorShader, worldToCameraMatrix); - - proxyShape = proxyShape->getNext(); - } - } -} - -void SceneDemo::removeAllContactPoints() { - - // Destroy all the visual contact points - for (std::vector::iterator it = mContactPoints.begin(); - it != mContactPoints.end(); ++it) { - delete (*it); - } - mContactPoints.clear(); -} - -// Return all the contact points of the scene -std::vector SceneDemo::computeContactPointsOfWorld(rp3d::DynamicsWorld* world) { - - std::vector contactPoints; - - // Get the list of contact manifolds from the world - rp3d::List manifolds = world->getContactsList(); - - // For each contact manifold - rp3d::List::Iterator it; - for (it = manifolds.begin(); it != manifolds.end(); ++it) { - - const rp3d::ContactManifold* manifold = *it; - - // For each contact point of the manifold - rp3d::ContactPoint* contactPoint = manifold->getContactPoints(); - while (contactPoint != nullptr) { - - rp3d::Vector3 point = manifold->getShape1()->getLocalToWorldTransform() * contactPoint->getLocalPointOnShape1(); - rp3d::Vector3 normalWorld = contactPoint->getNormal(); - openglframework::Vector3 normal = openglframework::Vector3(normalWorld.x, normalWorld.y, normalWorld.z); - ContactPoint contact(openglframework::Vector3(point.x, point.y, point.z), normal, openglframework::Color::red()); - contactPoints.push_back(contact); - - contactPoint = contactPoint->getNext(); - } - - } - - return contactPoints; -} - -// Update the engine settings -void SceneDemo::updateEngineSettings() { - - if (getDynamicsWorld() != nullptr) { - - // Update the physics engine parameters - getDynamicsWorld()->setIsGratityEnabled(mEngineSettings.isGravityEnabled); - rp3d::Vector3 gravity(mEngineSettings.gravity.x, mEngineSettings.gravity.y, - mEngineSettings.gravity.z); - getDynamicsWorld()->setGravity(gravity); - getDynamicsWorld()->enableSleeping(mEngineSettings.isSleepingEnabled); - getDynamicsWorld()->setSleepLinearVelocity(mEngineSettings.sleepLinearVelocity); - getDynamicsWorld()->setSleepAngularVelocity(mEngineSettings.sleepAngularVelocity); - getDynamicsWorld()->setNbIterationsPositionSolver(mEngineSettings.nbPositionSolverIterations); - getDynamicsWorld()->setNbIterationsVelocitySolver(mEngineSettings.nbVelocitySolverIterations); - getDynamicsWorld()->setTimeBeforeSleep(mEngineSettings.timeBeforeSleep); - } -} +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2016 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 "SceneDemo.h" +#include +#include "AABB.h" +#include "constraint/ContactPoint.h" +#include "collision/ContactManifold.h" + +using namespace openglframework; + +int SceneDemo::shadowMapTextureLevel = 0; +openglframework::Color SceneDemo::mObjectColorDemo = Color(0.76f, 0.67f, 0.47f, 1.0f); +openglframework::Color SceneDemo::mFloorColorDemo = Color(0.47f, 0.48f, 0.49f, 1.0f); +openglframework::Color SceneDemo::mSleepingColorDemo = Color(1.0f, 0.25f, 0.25f, 1.0f); +openglframework::Color SceneDemo::mSelectedObjectColorDemo = Color(0.09f, 0.59f, 0.88f, 1.0f); + +// Constructor +SceneDemo::SceneDemo(const std::string& name, EngineSettings& settings, float sceneRadius, bool isShadowMappingEnabled) + : Scene(name, settings, isShadowMappingEnabled), mIsShadowMappingInitialized(false), + mDepthShader("shaders/depth.vert", "shaders/depth.frag"), + mPhongShader("shaders/phong.vert", "shaders/phong.frag"), + mColorShader("shaders/color.vert", "shaders/color.frag"), + mQuadShader("shaders/quad.vert", "shaders/quad.frag"), + mVBOQuad(GL_ARRAY_BUFFER), mMeshFolderPath("meshes/"), + mPhysicsWorld(nullptr) { + + shadowMapTextureLevel++; + + // Move the lights + float lightsRadius = 30.0f; + float lightsHeight = 20.0f; + mLight0.translateWorld(Vector3(0 * lightsRadius, lightsHeight, 1 * lightsRadius)); + mLight1.translateWorld(Vector3(0.95f * lightsRadius, lightsHeight, -0.3f * lightsRadius)); + mLight2.translateWorld(Vector3(-0.58f * lightsRadius, lightsHeight, -0.81f * lightsRadius)); + + // Set the lights colors + mLight0.setDiffuseColor(Color(0.6f, 0.6f, 0.6f, 1.0f)); + mLight1.setDiffuseColor(Color(0.6f, 0.6f, 0.6f, 1.0f)); + mLight2.setDiffuseColor(Color(0.6f, 0.6f, 0.6f, 1.0f)); + + mShadowMapLightCameras[0].translateWorld(mLight0.getOrigin()); + mShadowMapLightCameras[0].rotateLocal(Vector3(1, 0, 0), -PI / 4.0f); + + mShadowMapLightCameras[1].translateWorld(mLight1.getOrigin()); + mShadowMapLightCameras[1].rotateLocal(Vector3(0, 1, 0), -5.0f * PI/3.7f); + mShadowMapLightCameras[1].rotateLocal(Vector3(1, 0, 0), -PI/4.0f); + + mShadowMapLightCameras[2].translateWorld(mLight2.getOrigin()); + mShadowMapLightCameras[2].rotateLocal(Vector3(0, 1, 0), 5 * PI/4.0f); + mShadowMapLightCameras[2].rotateLocal(Vector3(1, 0 , 0), -PI/4.0f); + + for (int i = 0; i < NB_SHADOW_MAPS; i++) { + mShadowMapLightCameras[i].setDimensions(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT); + mShadowMapLightCameras[i].setFieldOfView(100.0f); + mShadowMapLightCameras[i].setSceneRadius(100); + } + + mShadowMapBiasMatrix.setAllValues(0.5, 0.0, 0.0, 0.5, + 0.0, 0.5, 0.0, 0.5, + 0.0, 0.0, 0.5, 0.5, + 0.0, 0.0, 0.0, 1.0); + + // Create the Shadow map FBO and texture + if (mIsShadowMappingEnabled) { + createShadowMapFBOAndTexture(); + } + + createQuadVBO(); + + // Init rendering for the AABBs + AABB::init(); + + VisualContactPoint::createStaticData(mMeshFolderPath); +} + +// Destructor +SceneDemo::~SceneDemo() { + + + for (int i = 0; i < NB_SHADOW_MAPS; i++) { + mShadowMapTexture[i].destroy(); + mFBOShadowMap[i].destroy(); + } + + mVBOQuad.destroy(); + + mDepthShader.destroy(); + mPhongShader.destroy(); + mQuadShader.destroy(); + mColorShader.destroy(); + + // Destroy the contact points + removeAllContactPoints(); + + // Destroy rendering data for the AABB + AABB::destroy(); + + VisualContactPoint::destroyStaticData(); +} + +// Update the scene +void SceneDemo::update() { + + // Update the contact points + updateContactPoints(); + + // Update the position and orientation of the physics objects + for (std::vector::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) { + + // Update the transform used for the rendering + (*it)->updateTransform(mInterpolationFactor); + } +} + +// Update the physics world (take a simulation step) +// Can be called several times per frame +void SceneDemo::updatePhysics() { + + if (getDynamicsWorld() != nullptr) { + + // Take a simulation step + getDynamicsWorld()->update(mEngineSettings.timeStep); + } +} + +// Render the scene (in multiple passes for shadow mapping) +void SceneDemo::render() { + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + Matrix4 shadowMapProjMatrix[NB_SHADOW_MAPS]; + openglframework::Matrix4 worldToLightCameraMatrix[NB_SHADOW_MAPS]; + for (int i = 0; i < NB_SHADOW_MAPS; i++) { + + shadowMapProjMatrix[i] = mShadowMapLightCameras[i].getProjectionMatrix(); + worldToLightCameraMatrix[i] = mShadowMapLightCameras[i].getTransformMatrix().getInverse(); + } + + // ---------- Render the scene to generate the shadow map (first pass) ----------- // + + // If Shadow Mapping is enabled + if (mIsShadowMappingEnabled) { + + // Culling switching, rendering only backface, this is done to avoid self-shadowing + glCullFace(GL_BACK); + + // For each shadow map + for (int i = 0; i < NB_SHADOW_MAPS; i++) { + + mFBOShadowMap[i].bind(); + + // Bind the shader + mDepthShader.bind(); + + // Set the variables of the shader + mDepthShader.setMatrix4x4Uniform("projectionMatrix", shadowMapProjMatrix[i]); + + // Set the viewport to render into the shadow map texture + glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT); + + // Clear previous frame values + glClear(GL_DEPTH_BUFFER_BIT); + + // Disable color rendering, we only want to write to the Z-Buffer + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + // Render the objects of the scene + renderSinglePass(mDepthShader, worldToLightCameraMatrix[i]); + + // Unbind the shader + mDepthShader.unbind(); + + mFBOShadowMap[i].unbind(); + } + + glDisable(GL_POLYGON_OFFSET_FILL); + } + + // ---------- Render the scene for final rendering (second pass) ----------- // + + glCullFace(GL_BACK); + + // Get the world-space to camera-space matrix + const openglframework::Matrix4 worldToCameraMatrix = mCamera.getTransformMatrix().getInverse(); + + mPhongShader.bind(); + + // Is shadow mapping is enabled + GLint textureUnits[NB_SHADOW_MAPS]; + if (mIsShadowMappingEnabled) { + + for (int i = 0; i < NB_SHADOW_MAPS; i++) { + mShadowMapTexture[i].bind(); + } + for (int i = 0; i < NB_SHADOW_MAPS; i++) { + textureUnits[i] = mShadowMapTexture[i].getUnit(); + } + } + + // Set the variables of the phong shader + mPhongShader.setMatrix4x4Uniform("projectionMatrix", mCamera.getProjectionMatrix()); + mPhongShader.setMatrix4x4Uniform("shadowMapLight0ProjectionMatrix", mShadowMapBiasMatrix * shadowMapProjMatrix[0]); + mPhongShader.setMatrix4x4Uniform("shadowMapLight1ProjectionMatrix", mShadowMapBiasMatrix * shadowMapProjMatrix[1]); + mPhongShader.setMatrix4x4Uniform("shadowMapLight2ProjectionMatrix", mShadowMapBiasMatrix * shadowMapProjMatrix[2]); + mPhongShader.setMatrix4x4Uniform("worldToLight0CameraMatrix", worldToLightCameraMatrix[0]); + mPhongShader.setMatrix4x4Uniform("worldToLight1CameraMatrix", worldToLightCameraMatrix[1]); + mPhongShader.setMatrix4x4Uniform("worldToLight2CameraMatrix", worldToLightCameraMatrix[2]); + mPhongShader.setVector3Uniform("light0PosCameraSpace", worldToCameraMatrix * mLight0.getOrigin()); + mPhongShader.setVector3Uniform("light1PosCameraSpace", worldToCameraMatrix * mLight1.getOrigin()); + mPhongShader.setVector3Uniform("light2PosCameraSpace", worldToCameraMatrix * mLight2.getOrigin()); + mPhongShader.setVector3Uniform("lightAmbientColor", Vector3(0.3f, 0.3f, 0.3f)); + mPhongShader.setVector3Uniform("light0DiffuseColor", Vector3(mLight0.getDiffuseColor().r, mLight0.getDiffuseColor().g, mLight0.getDiffuseColor().b)); + mPhongShader.setVector3Uniform("light1DiffuseColor", Vector3(mLight1.getDiffuseColor().r, mLight1.getDiffuseColor().g, mLight1.getDiffuseColor().b)); + mPhongShader.setVector3Uniform("light2DiffuseColor", Vector3(mLight2.getDiffuseColor().r, mLight2.getDiffuseColor().g, mLight2.getDiffuseColor().b)); + mPhongShader.setIntArrayUniform("shadowMapSampler", textureUnits, NB_SHADOW_MAPS); + mPhongShader.setIntUniform("isShadowEnabled", mIsShadowMappingEnabled); + mPhongShader.setVector2Uniform("shadowMapDimension", Vector2(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT)); + mPhongShader.unbind(); + + // Set the variables of the color shader + mColorShader.bind(); + mColorShader.setMatrix4x4Uniform("projectionMatrix", mCamera.getProjectionMatrix()); + mColorShader.unbind(); + + // Set the viewport to render the scene + glViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight); + + //Enabling color write (previously disabled for light POV z-buffer rendering) + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + // Clear previous frame values + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Render the objects of the scene + renderSinglePass(mPhongShader, worldToCameraMatrix); + + // Render the contact points + if (mIsContactPointsDisplayed) { + renderContactPoints(mPhongShader, worldToCameraMatrix); + } + + // Render the AABBs + if (mIsAABBsDisplayed) { + renderAABBs(worldToCameraMatrix); + } + + // Is shadow mapping is enabled + if (mIsShadowMappingEnabled) { + + for (int i = 0; i < NB_SHADOW_MAPS; i++) { + mShadowMapTexture[i].unbind(); + } + } + + mPhongShader.unbind(); + + //drawTextureQuad(); +} + +// Render the scene in a single pass +void SceneDemo::renderSinglePass(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix) { + + if (mIsWireframeEnabled) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } + + // Bind the shader + shader.bind(); + + // Render all the physics objects of the scene + for (std::vector::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) { + (*it)->render(mIsWireframeEnabled ? mColorShader : shader, worldToCameraMatrix); + } + + // Unbind the shader + shader.unbind(); + + if (mIsWireframeEnabled) { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } +} + +// Create the Shadow map FBO and texture +void SceneDemo::createShadowMapFBOAndTexture() { + + // For each shadow map + for (int i = 0; i < NB_SHADOW_MAPS; i++) { + + // Create the texture for the depth values + mShadowMapTexture[i].create(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, + GL_UNSIGNED_BYTE, GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER, NULL); + + mShadowMapTexture[i].setUnit(i); + + // Make sure that texture lookups outside the texture coords range will not + // treated as beeing in shadow + glBindTexture(GL_TEXTURE_2D, mShadowMapTexture[i].getID()); + GLfloat border[] = { 1.0f, 0.0f, 0.0f, 0.0f }; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border); + glBindTexture(GL_TEXTURE_2D, 0); + + // Create the FBO for the shadow map + mFBOShadowMap[i].create(0, 0, false); + mFBOShadowMap[i].bind(); + + // Tell OpenGL that we won't bind a color texture with the currently binded FBO + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + + mFBOShadowMap[i].attachTexture(GL_DEPTH_ATTACHMENT, mShadowMapTexture[i].getID()); + mFBOShadowMap[i].unbind(); + } + + mIsShadowMappingInitialized = true; +} + +// Used for debugging shadow maps +void SceneDemo::createQuadVBO() { + + mVAOQuad.create(); + mVAOQuad.bind(); + + static const GLfloat quadVertexData[] = { + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + }; + + mVBOQuad.create(); + mVBOQuad.bind(); + mVBOQuad.copyDataIntoVBO(sizeof(quadVertexData), quadVertexData, GL_STATIC_DRAW); + mVBOQuad.unbind(); + + mVAOQuad.unbind(); +} + +void SceneDemo::drawTextureQuad() { + + glViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + // Clear previous frame values + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + + const int SHADOW_MAP_TEXTURE_TO_DRAW = 0; + const GLuint textureUnit = SHADOW_MAP_TEXTURE_TO_DRAW; + + mVAOQuad.bind(); + mQuadShader.bind(); + mShadowMapTexture[SHADOW_MAP_TEXTURE_TO_DRAW].bind(); + mQuadShader.setIntUniform("textureSampler", textureUnit); + mVBOQuad.bind(); + + GLint vertexPositionLoc = mQuadShader.getAttribLocation("vertexPosition"); + glEnableVertexAttribArray(vertexPositionLoc); + + glVertexAttribPointer( + vertexPositionLoc, // attribute 0. No particular reason for 0, but must match the layout in the shader. + 3, // size + GL_FLOAT, // type + GL_FALSE, // normalized? + 0, // stride + (void*)0 // array buffer offset + ); + + // Draw the triangles ! + glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles + + glDisableVertexAttribArray(vertexPositionLoc); + + mVBOQuad.unbind(); + mShadowMapTexture[SHADOW_MAP_TEXTURE_TO_DRAW].unbind(); + mQuadShader.unbind(); + mVAOQuad.unbind(); +} + +// Gather and create contact points +void SceneDemo::updateContactPoints() { + + // Remove the previous contact points + removeAllContactPoints(); + + if (mIsContactPointsDisplayed) { + + // Get the current contact points of the scene + std::vector contactPoints = getContactPoints(); + + // For each contact point + std::vector::const_iterator it; + for (it = contactPoints.begin(); it != contactPoints.end(); ++it) { + + // Create a visual contact point for rendering + VisualContactPoint* point = new VisualContactPoint(it->point, mMeshFolderPath, it->point + it->normal, it->color); + mContactPoints.push_back(point); + } + } +} + +// Render the contact points +void SceneDemo::renderContactPoints(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix) { + + // Render all the contact points + for (std::vector::iterator it = mContactPoints.begin(); + it != mContactPoints.end(); ++it) { + (*it)->render(mColorShader, worldToCameraMatrix); + } +} + +// Render the AABBs +void SceneDemo::renderAABBs(const openglframework::Matrix4& worldToCameraMatrix) { + + // For each physics object of the scene + for (std::vector::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) { + + // For each proxy shape of the object + rp3d::ProxyShape* proxyShape = (*it)->getCollisionBody()->getProxyShapesList(); + while (proxyShape != nullptr) { + + // Get the broad-phase AABB corresponding to the proxy shape + rp3d::AABB aabb = mPhysicsWorld->getWorldAABB(proxyShape); + + openglframework::Vector3 aabbCenter(aabb.getCenter().x, aabb.getCenter().y, aabb.getCenter().z); + openglframework::Vector3 aabbMin(aabb.getMin().x, aabb.getMin().y, aabb.getMin().z); + openglframework::Vector3 aabbMax(aabb.getMax().x, aabb.getMax().y, aabb.getMax().z); + + // Render the AABB + AABB::render(aabbCenter, aabbMax - aabbMin, Color::green(), mColorShader, worldToCameraMatrix); + + proxyShape = proxyShape->getNext(); + } + } +} + +void SceneDemo::removeAllContactPoints() { + + // Destroy all the visual contact points + for (std::vector::iterator it = mContactPoints.begin(); + it != mContactPoints.end(); ++it) { + delete (*it); + } + mContactPoints.clear(); +} + +// Return all the contact points of the scene +std::vector SceneDemo::computeContactPointsOfWorld(rp3d::DynamicsWorld* world) { + + std::vector contactPoints; + + // Get the list of contact manifolds from the world + rp3d::List manifolds = world->getContactsList(); + + // For each contact manifold + rp3d::List::Iterator it; + for (it = manifolds.begin(); it != manifolds.end(); ++it) { + + const rp3d::ContactManifold* manifold = *it; + + // For each contact point of the manifold + rp3d::ContactPoint* contactPoint = manifold->getContactPoints(); + while (contactPoint != nullptr) { + + rp3d::Vector3 point = manifold->getShape1()->getLocalToWorldTransform() * contactPoint->getLocalPointOnShape1(); + rp3d::Vector3 normalWorld = contactPoint->getNormal(); + openglframework::Vector3 normal = openglframework::Vector3(normalWorld.x, normalWorld.y, normalWorld.z); + ContactPoint contact(openglframework::Vector3(point.x, point.y, point.z), normal, openglframework::Color::red()); + contactPoints.push_back(contact); + + contactPoint = contactPoint->getNext(); + } + + } + + return contactPoints; +} + +// Update the engine settings +void SceneDemo::updateEngineSettings() { + + if (getDynamicsWorld() != nullptr) { + + // Update the physics engine parameters + getDynamicsWorld()->setIsGratityEnabled(mEngineSettings.isGravityEnabled); + rp3d::Vector3 gravity(mEngineSettings.gravity.x, mEngineSettings.gravity.y, + mEngineSettings.gravity.z); + getDynamicsWorld()->setGravity(gravity); + getDynamicsWorld()->enableSleeping(mEngineSettings.isSleepingEnabled); + getDynamicsWorld()->setSleepLinearVelocity(mEngineSettings.sleepLinearVelocity); + getDynamicsWorld()->setSleepAngularVelocity(mEngineSettings.sleepAngularVelocity); + getDynamicsWorld()->setNbIterationsPositionSolver(mEngineSettings.nbPositionSolverIterations); + getDynamicsWorld()->setNbIterationsVelocitySolver(mEngineSettings.nbVelocitySolverIterations); + getDynamicsWorld()->setTimeBeforeSleep(mEngineSettings.timeBeforeSleep); + } +} diff --git a/testbed/src/SceneDemo.h b/testbed/src/SceneDemo.h index 95e1ece0..247469f2 100644 --- a/testbed/src/SceneDemo.h +++ b/testbed/src/SceneDemo.h @@ -1,189 +1,195 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://www.reactphysics3d.com * -* Copyright (c) 2010-2016 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 SCENEDEMO_H -#define SCENEDEMO_H - -// Libraries -#include "Scene.h" -#include "VisualContactPoint.h" -#include "reactphysics3d.h" -#include "PhysicsObject.h" - -// Constants -const int SHADOWMAP_WIDTH = 2048; -const int SHADOWMAP_HEIGHT = 2048; - -// Class SceneDemo -// Abstract class that represents a 3D scene for the ReactPhysics3D examples. -// This scene has a single light source with shadow mapping. -class SceneDemo : public Scene { - - protected: - - // -------------------- Attributes -------------------- // - - /// Light 0 - openglframework::Light mLight0; - - /// True if the shadows FBO, textures have been created - bool mIsShadowMappingInitialized; - - /// FBO for the shadow map - openglframework::FrameBufferObject mFBOShadowMap; - - /// Shadow map texture - openglframework::Texture2D mShadowMapTexture; - - static int shadowMapTextureLevel; - - /// All the visual contact points - std::vector mContactPoints; - - /// Shadow map bias matrix - openglframework::Matrix4 mShadowMapBiasMatrix; - - /// Camera at light0 position for the shadow map - openglframework::Camera mShadowMapLightCamera; - - /// Depth shader to render the shadow map - openglframework::Shader mDepthShader; - - /// Phong shader - openglframework::Shader mPhongShader; - - /// Constant color shader - openglframework::Shader mColorShader; - - // TODO : Delete this - openglframework::Shader mQuadShader; - - // TODO : Delete this - openglframework::VertexArrayObject mVAOQuad; - - openglframework::VertexBufferObject mVBOQuad; - - static openglframework::Color mGreyColorDemo; - static openglframework::Color mYellowColorDemo; - static openglframework::Color mBlueColorDemo; - static openglframework::Color mOrangeColorDemo; - static openglframework::Color mPinkColorDemo; - static openglframework::Color mRedColorDemo; - static openglframework::Color mDemoColors[]; - static int mNbDemoColors; - - std::string mMeshFolderPath; - - std::vector mPhysicsObjects; - - rp3d::CollisionWorld* mPhysicsWorld; - - // -------------------- Methods -------------------- // - - // Create the Shadow map FBO and texture - void createShadowMapFBOAndTexture(); - - // Used for debugging shadow maps - void createQuadVBO(); - - // TODO : Delete this - void drawTextureQuad(); - - // Update the contact points - void updateContactPoints(); - - // Render the contact points - void renderContactPoints(openglframework::Shader& shader, - const openglframework::Matrix4& worldToCameraMatrix); - - - /// Render the AABBs - void renderAABBs(const openglframework::Matrix4& worldToCameraMatrix); - - /// Remove all contact points - void removeAllContactPoints(); - - /// Return a reference to the dynamics world - rp3d::DynamicsWorld* getDynamicsWorld(); - - /// Return a reference to the dynamics world - const rp3d::DynamicsWorld* getDynamicsWorld() const; - - public: - - // -------------------- Methods -------------------- // - - /// Constructor - SceneDemo(const std::string& name, EngineSettings& settings, float sceneRadius, bool isShadowMappingEnabled = true); - - /// Destructor - virtual ~SceneDemo() override; - - /// Update the scene - virtual void update() override; - - /// Update the physics world (take a simulation step) - /// Can be called several times per frame - virtual void updatePhysics() override; - - /// Render the scene (possibly in multiple passes for shadow mapping) - virtual void render() override; - - /// Update the engine settings - virtual void updateEngineSettings() override; - - /// Render the scene in a single pass - virtual void renderSinglePass(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix); - - /// Enabled/Disable the shadow mapping - virtual void setIsShadowMappingEnabled(bool isShadowMappingEnabled) override; - - /// Return all the contact points of the scene - std::vector computeContactPointsOfWorld(reactphysics3d::DynamicsWorld *world); -}; - -// Enabled/Disable the shadow mapping -inline void SceneDemo::setIsShadowMappingEnabled(bool isShadowMappingEnabled) { - - Scene::setIsShadowMappingEnabled(isShadowMappingEnabled); - - if (mIsShadowMappingEnabled && !mIsShadowMappingInitialized) { - createShadowMapFBOAndTexture(); - } -} - -// Return a reference to the dynamics world -inline rp3d::DynamicsWorld* SceneDemo::getDynamicsWorld() { - return dynamic_cast(mPhysicsWorld); -} - -// Return a reference to the dynamics world -inline const rp3d::DynamicsWorld* SceneDemo::getDynamicsWorld() const { - return dynamic_cast(mPhysicsWorld); -} - -#endif - - +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2016 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 SCENEDEMO_H +#define SCENEDEMO_H + +// Libraries +#include "Scene.h" +#include "VisualContactPoint.h" +#include "reactphysics3d.h" +#include "PhysicsObject.h" + +// Constants +const int SHADOWMAP_WIDTH = 2048; +const int SHADOWMAP_HEIGHT = 2048; + +// Class SceneDemo +// Abstract class that represents a 3D scene for the ReactPhysics3D examples. +// This scene has a single light source with shadow mapping. +class SceneDemo : public Scene { + + protected: + + // -------------------- Constants -------------------- // + + static constexpr int NB_SHADOW_MAPS = 3; + + // -------------------- Attributes -------------------- // + + /// Light 0 + openglframework::Light mLight0; + + /// Light 1 + openglframework::Light mLight1; + + /// Light 2 + openglframework::Light mLight2; + + /// True if the shadows FBO, textures have been created + bool mIsShadowMappingInitialized; + + /// Array of FBO for the shadow maps + openglframework::FrameBufferObject mFBOShadowMap[NB_SHADOW_MAPS]; + + /// Shadow map texture + openglframework::Texture2D mShadowMapTexture[NB_SHADOW_MAPS]; + + static int shadowMapTextureLevel; + + /// All the visual contact points + std::vector mContactPoints; + + /// Shadow map bias matrix + openglframework::Matrix4 mShadowMapBiasMatrix; + + /// Cameras at lights position for the shadow maps + openglframework::Camera mShadowMapLightCameras[NB_SHADOW_MAPS]; + + /// Depth shader to render the shadow map + openglframework::Shader mDepthShader; + + /// Phong shader + openglframework::Shader mPhongShader; + + /// Constant color shader + openglframework::Shader mColorShader; + + // TODO : Delete this + openglframework::Shader mQuadShader; + + // TODO : Delete this + openglframework::VertexArrayObject mVAOQuad; + + openglframework::VertexBufferObject mVBOQuad; + + static openglframework::Color mObjectColorDemo; + static openglframework::Color mFloorColorDemo; + static openglframework::Color mSleepingColorDemo; + static openglframework::Color mSelectedObjectColorDemo; + + std::string mMeshFolderPath; + + std::vector mPhysicsObjects; + + rp3d::CollisionWorld* mPhysicsWorld; + + // -------------------- Methods -------------------- // + + // Create the Shadow map FBO and texture + void createShadowMapFBOAndTexture(); + + // Used for debugging shadow maps + void createQuadVBO(); + + // TODO : Delete this + void drawTextureQuad(); + + // Update the contact points + void updateContactPoints(); + + // Render the contact points + void renderContactPoints(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix); + + + /// Render the AABBs + void renderAABBs(const openglframework::Matrix4& worldToCameraMatrix); + + /// Remove all contact points + void removeAllContactPoints(); + + /// Return a reference to the dynamics world + rp3d::DynamicsWorld* getDynamicsWorld(); + + /// Return a reference to the dynamics world + const rp3d::DynamicsWorld* getDynamicsWorld() const; + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + SceneDemo(const std::string& name, EngineSettings& settings, float sceneRadius, bool isShadowMappingEnabled = true); + + /// Destructor + virtual ~SceneDemo() override; + + /// Update the scene + virtual void update() override; + + /// Update the physics world (take a simulation step) + /// Can be called several times per frame + virtual void updatePhysics() override; + + /// Render the scene (possibly in multiple passes for shadow mapping) + virtual void render() override; + + /// Update the engine settings + virtual void updateEngineSettings() override; + + /// Render the scene in a single pass + virtual void renderSinglePass(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix); + + /// Enabled/Disable the shadow mapping + virtual void setIsShadowMappingEnabled(bool isShadowMappingEnabled) override; + + /// Return all the contact points of the scene + std::vector computeContactPointsOfWorld(reactphysics3d::DynamicsWorld *world); +}; + +// Enabled/Disable the shadow mapping +inline void SceneDemo::setIsShadowMappingEnabled(bool isShadowMappingEnabled) { + + Scene::setIsShadowMappingEnabled(isShadowMappingEnabled); + + if (mIsShadowMappingEnabled && !mIsShadowMappingInitialized) { + createShadowMapFBOAndTexture(); + } +} + +// Return a reference to the dynamics world +inline rp3d::DynamicsWorld* SceneDemo::getDynamicsWorld() { + return dynamic_cast(mPhysicsWorld); +} + +// Return a reference to the dynamics world +inline const rp3d::DynamicsWorld* SceneDemo::getDynamicsWorld() const { + return dynamic_cast(mPhysicsWorld); +} + +#endif + + diff --git a/testbed/src/TestbedApplication.cpp b/testbed/src/TestbedApplication.cpp index 4a0963f2..9a21261b 100644 --- a/testbed/src/TestbedApplication.cpp +++ b/testbed/src/TestbedApplication.cpp @@ -1,393 +1,393 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://www.reactphysics3d.com * -* Copyright (c) 2010-2016 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 "TestbedApplication.h" -#include "openglframework.h" -#include -#include -#include -#include "cubes/CubesScene.h" -#include "collisiondetection/CollisionDetectionScene.h" -#include "joints/JointsScene.h" -#include "collisionshapes/CollisionShapesScene.h" -#include "heightfield/HeightFieldScene.h" -#include "raycast/RaycastScene.h" -#include "concavemesh/ConcaveMeshScene.h" -#include "cubestack/CubeStackScene.h" - -using namespace openglframework; -using namespace jointsscene; -using namespace cubesscene; -using namespace raycastscene; -using namespace collisionshapesscene; -using namespace trianglemeshscene; -using namespace heightfieldscene; -using namespace collisiondetectionscene; -using namespace cubestackscene; - -// Initialization of static variables -const float TestbedApplication::SCROLL_SENSITIVITY = 0.08f; - -// Constructor -TestbedApplication::TestbedApplication(bool isFullscreen) - : Screen(Vector2i(1280, 800), "Testbed ReactPhysics3D", true, isFullscreen, 8, 8, 24, 8, 8), - mIsInitialized(false), mGui(this), mCurrentScene(nullptr), - mEngineSettings(EngineSettings::defaultSettings()), - mFPS(0), mNbFrames(0), mPreviousTime(0), - mLastTimeComputedFPS(0), mFrameTime(0), mPhysicsTime(0), - mWidth(1280), mHeight(720), - mSinglePhysicsStepEnabled(false), mSinglePhysicsStepDone(false), - mWindowToFramebufferRatio(Vector2(1, 1)), mIsShadowMappingEnabled(true), - mIsContactPointsDisplayed(false), mIsAABBsDisplayed(false), mIsWireframeEnabled(false), - mIsVSyncEnabled(true) { - - init(); - - resizeEvent(Vector2i(0, 0)); -} - -// Destructor -TestbedApplication::~TestbedApplication() { - - // Destroy all the scenes - destroyScenes(); -} - -// Initialize the viewer -void TestbedApplication::init() { - - // Create all the scenes - createScenes(); - - // Initialize the GUI - mGui.init(); - - mTimer.start(); - - mIsInitialized = true; -} - -// Create all the scenes -void TestbedApplication::createScenes() { - - // Cubes scene - CubesScene* cubeScene = new CubesScene("Cubes", mEngineSettings); - mScenes.push_back(cubeScene); - - // Cube Stack scene - CubeStackScene* cubeStackScene = new CubeStackScene("Cube Stack", mEngineSettings); - mScenes.push_back(cubeStackScene); - - // Joints scene - JointsScene* jointsScene = new JointsScene("Joints", mEngineSettings); - mScenes.push_back(jointsScene); - - // Collision shapes scene - CollisionShapesScene* collisionShapesScene = new CollisionShapesScene("Collision Shapes", mEngineSettings); - mScenes.push_back(collisionShapesScene); - - // Heightfield shape scene - HeightFieldScene* heightFieldScene = new HeightFieldScene("Heightfield", mEngineSettings); - mScenes.push_back(heightFieldScene); - - // Raycast scene - RaycastScene* raycastScene = new RaycastScene("Raycast", mEngineSettings); - mScenes.push_back(raycastScene); - - // Collision Detection scene - CollisionDetectionScene* collisionDetectionScene = new CollisionDetectionScene("Collision Detection", mEngineSettings); - mScenes.push_back(collisionDetectionScene); - - // Concave Mesh scene - ConcaveMeshScene* concaveMeshScene = new ConcaveMeshScene("Concave Mesh", mEngineSettings); - mScenes.push_back(concaveMeshScene); - - assert(mScenes.size() > 0); - - const int firstSceneIndex = 0; - - switchScene(mScenes[firstSceneIndex]); -} - -// Remove all the scenes -void TestbedApplication::destroyScenes() { - - for (uint i=0; iupdatePhysics(); -} - -// Update the physics of the current scene -void TestbedApplication::updatePhysics() { - - // Update the elapsed time - mEngineSettings.elapsedTime = mTimer.getPhysicsTime(); - - if (mTimer.isRunning()) { - - // Compute the time since the last update() call and update the timer - mTimer.update(); - - // While the time accumulator is not empty - while(mTimer.isPossibleToTakeStep(mEngineSettings.timeStep)) { - - // Take a physics simulation step - mCurrentScene->updatePhysics(); - - // Update the timer - mTimer.nextStep(mEngineSettings.timeStep); - } - } -} - -void TestbedApplication::update() { - - double currentTime = glfwGetTime(); - - // Update the physics - if (mSinglePhysicsStepEnabled && !mSinglePhysicsStepDone) { - updateSinglePhysicsStep(); - mSinglePhysicsStepDone = true; - } - else { - updatePhysics(); - } - - // Compute the physics update time - mPhysicsTime = glfwGetTime() - currentTime; - - // Compute the interpolation factor - float factor = mTimer.computeInterpolationFactor(mEngineSettings.timeStep); - assert(factor >= 0.0f && factor <= 1.0f); - - // Notify the scene about the interpolation factor - mCurrentScene->setInterpolationFactor(factor); - - // Enable/Disable shadow mapping - mCurrentScene->setIsShadowMappingEnabled(mIsShadowMappingEnabled); - - // Display/Hide contact points - mCurrentScene->setIsContactPointsDisplayed(mIsContactPointsDisplayed); - - // Display/Hide the AABBs - mCurrentScene->setIsAABBsDisplayed(mIsAABBsDisplayed); - - // Enable/Disable wireframe mode - mCurrentScene->setIsWireframeEnabled(mIsWireframeEnabled); - - // Update the scene - mCurrentScene->update(); -} - -void TestbedApplication::drawContents() { - - update(); - - int bufferWidth, bufferHeight; - glfwMakeContextCurrent(mGLFWWindow); - glfwGetFramebufferSize(mGLFWWindow, &bufferWidth, &bufferHeight); - - // Set the viewport of the scene - mCurrentScene->setViewport(0, 0, bufferWidth, bufferHeight); - - // Render the scene - mCurrentScene->render(); - - // Check the OpenGL errors - checkOpenGLErrors(); - - mGui.update(); - - // Compute the current framerate - computeFPS(); -} - -/// Window resize event handler -bool TestbedApplication::resizeEvent(const Vector2i& size) { - - if (!mIsInitialized) return false; - - // Get the framebuffer dimension - int width, height; - glfwGetFramebufferSize(mGLFWWindow, &width, &height); - - // Resize the camera viewport - mCurrentScene->reshape(width, height); - - // Update the window size of the scene - int windowWidth, windowHeight; - glfwGetWindowSize(mGLFWWindow, &windowWidth, &windowHeight); - mCurrentScene->setWindowDimension(windowWidth, windowHeight); - - return true; -} - -// Change the current scene -void TestbedApplication::switchScene(Scene* newScene) { - - if (newScene == mCurrentScene) return; - - mCurrentScene = newScene; - - // Reset the scene - mCurrentScene->reset(); - - mCurrentScene->updateEngineSettings(); - - resizeEvent(Vector2i(0, 0)); -} - -// Notify that the engine settings have changed -void TestbedApplication::notifyEngineSetttingsChanged() { - mCurrentScene->updateEngineSettings(); -} - -// Check the OpenGL errors -void TestbedApplication::checkOpenGLErrorsInternal(const char* file, int line) { - GLenum glError; - - // Get the OpenGL errors - glError = glGetError(); - - // While there are errors - while (glError != GL_NO_ERROR) { - - std::string error; - - switch(glError) { - case GL_INVALID_OPERATION: error="INVALID_OPERATION"; break; - case GL_INVALID_ENUM: error="INVALID_ENUM"; break; - case GL_INVALID_VALUE: error="INVALID_VALUE"; break; - case GL_OUT_OF_MEMORY: error="OUT_OF_MEMORY"; break; - case GL_INVALID_FRAMEBUFFER_OPERATION: error="INVALID_FRAMEBUFFER_OPERATION"; break; - } - - std::cerr << "OpenGL Error #" << error.c_str() << " - " << file << ": " << line << std::endl; - - // Get the next error - glError = glGetError(); - } -} - - -// Compute the FPS -void TestbedApplication::computeFPS() { - - // Note : By default the nanogui library is using glfwWaitEvents() to process - // events and sleep to target a framerate of 50 ms (using a thread - // sleeping). However, for games we prefer to use glfwPollEvents() - // instead and remove the update. Therefore the file common.cpp of the - // nanogui library has been modified to have a faster framerate - - mNbFrames++; - - // Get the number of seconds since start - mCurrentTime = glfwGetTime(); - - // Calculate time passed - mFrameTime = mCurrentTime - mPreviousTime; - double timeInterval = (mCurrentTime - mLastTimeComputedFPS) * 1000.0; - - // Update the FPS counter each second - if(timeInterval > 1000) { - - // calculate the number of frames per second - mFPS = static_cast(mNbFrames) / timeInterval; - mFPS *= 1000.0; - - // Reset frame count - mNbFrames = 0; - - mLastTimeComputedFPS = mCurrentTime; - } - - // Set time - mPreviousTime = mCurrentTime; -} - -bool TestbedApplication::keyboardEvent(int key, int scancode, int action, int modifiers) { - - if (Screen::keyboardEvent(key, scancode, action, modifiers)) { - return true; - } - - // Close application on escape key - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { - glfwSetWindowShouldClose(mGLFWWindow, GL_TRUE); - return true; - } - - return mCurrentScene->keyboardEvent(key, scancode, action, modifiers); -} - -// Handle a mouse button event (default implementation: propagate to children) -bool TestbedApplication::mouseButtonEvent(const Vector2i &p, int button, bool down, int modifiers) { - - if (Screen::mouseButtonEvent(p, button, down, modifiers)) { - return true; - } - - // Get the mouse cursor position - double x, y; - glfwGetCursorPos(mGLFWWindow, &x, &y); - - return mCurrentScene->mouseButtonEvent(button, down, modifiers, x, y); -} - -// Handle a mouse motion event (default implementation: propagate to children) -bool TestbedApplication::mouseMotionEvent(const Vector2i &p, const Vector2i &rel, int button, int modifiers) { - - if (Screen::mouseMotionEvent(p, rel, button, modifiers)) { - return true; - } - - int leftButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_LEFT); - int rightButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_RIGHT); - int middleButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_MIDDLE); - int altKeyState = glfwGetKey(mGLFWWindow, GLFW_KEY_LEFT_ALT); - - return mCurrentScene->mouseMotionEvent(p[0], p[1], leftButtonState, rightButtonState, - middleButtonState, altKeyState); -} - -// Handle a mouse scroll event (default implementation: propagate to children) -bool TestbedApplication::scrollEvent(const Vector2i &p, const Vector2f &rel) { - - if (Screen::scrollEvent(p, rel)) { - return true; - } - - return mCurrentScene->scrollingEvent(rel[0], rel[1], SCROLL_SENSITIVITY); -} +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2016 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 "TestbedApplication.h" +#include "openglframework.h" +#include +#include +#include +#include "cubes/CubesScene.h" +#include "collisiondetection/CollisionDetectionScene.h" +#include "joints/JointsScene.h" +#include "collisionshapes/CollisionShapesScene.h" +#include "heightfield/HeightFieldScene.h" +#include "raycast/RaycastScene.h" +#include "concavemesh/ConcaveMeshScene.h" +#include "cubestack/CubeStackScene.h" + +using namespace openglframework; +using namespace jointsscene; +using namespace cubesscene; +using namespace raycastscene; +using namespace collisionshapesscene; +using namespace trianglemeshscene; +using namespace heightfieldscene; +using namespace collisiondetectionscene; +using namespace cubestackscene; + +// Initialization of static variables +const float TestbedApplication::SCROLL_SENSITIVITY = 0.08f; + +// Constructor +TestbedApplication::TestbedApplication(bool isFullscreen, int windowWidth, int windowHeight) + : Screen(Vector2i(windowWidth, windowHeight), "Testbed ReactPhysics3D", true, isFullscreen, 8, 8, 24, 8, 8), + mIsInitialized(false), mGui(this), mCurrentScene(nullptr), + mEngineSettings(EngineSettings::defaultSettings()), + mFPS(0), mNbFrames(0), mPreviousTime(0), + mLastTimeComputedFPS(0), mFrameTime(0), mPhysicsTime(0), + mWidth(windowWidth), mHeight(windowHeight), + mSinglePhysicsStepEnabled(false), mSinglePhysicsStepDone(false), + mWindowToFramebufferRatio(Vector2(1, 1)), mIsShadowMappingEnabled(true), + mIsContactPointsDisplayed(false), mIsAABBsDisplayed(false), mIsWireframeEnabled(false), + mIsVSyncEnabled(true) { + + init(); + + resizeEvent(Vector2i(0, 0)); +} + +// Destructor +TestbedApplication::~TestbedApplication() { + + // Destroy all the scenes + destroyScenes(); +} + +// Initialize the viewer +void TestbedApplication::init() { + + // Create all the scenes + createScenes(); + + // Initialize the GUI + mGui.init(); + + mTimer.start(); + + mIsInitialized = true; +} + +// Create all the scenes +void TestbedApplication::createScenes() { + + // Cubes scene + CubesScene* cubeScene = new CubesScene("Cubes", mEngineSettings); + mScenes.push_back(cubeScene); + + // Cube Stack scene + CubeStackScene* cubeStackScene = new CubeStackScene("Cube Stack", mEngineSettings); + mScenes.push_back(cubeStackScene); + + // Joints scene + JointsScene* jointsScene = new JointsScene("Joints", mEngineSettings); + mScenes.push_back(jointsScene); + + // Collision shapes scene + CollisionShapesScene* collisionShapesScene = new CollisionShapesScene("Collision Shapes", mEngineSettings); + mScenes.push_back(collisionShapesScene); + + // Heightfield shape scene + HeightFieldScene* heightFieldScene = new HeightFieldScene("Heightfield", mEngineSettings); + mScenes.push_back(heightFieldScene); + + // Raycast scene + RaycastScene* raycastScene = new RaycastScene("Raycast", mEngineSettings); + mScenes.push_back(raycastScene); + + // Collision Detection scene + CollisionDetectionScene* collisionDetectionScene = new CollisionDetectionScene("Collision Detection", mEngineSettings); + mScenes.push_back(collisionDetectionScene); + + // Concave Mesh scene + ConcaveMeshScene* concaveMeshScene = new ConcaveMeshScene("Concave Mesh", mEngineSettings); + mScenes.push_back(concaveMeshScene); + + assert(mScenes.size() > 0); + + const int firstSceneIndex = 0; + + switchScene(mScenes[firstSceneIndex]); +} + +// Remove all the scenes +void TestbedApplication::destroyScenes() { + + for (uint i=0; iupdatePhysics(); +} + +// Update the physics of the current scene +void TestbedApplication::updatePhysics() { + + // Update the elapsed time + mEngineSettings.elapsedTime = mTimer.getPhysicsTime(); + + if (mTimer.isRunning()) { + + // Compute the time since the last update() call and update the timer + mTimer.update(); + + // While the time accumulator is not empty + while(mTimer.isPossibleToTakeStep(mEngineSettings.timeStep)) { + + // Take a physics simulation step + mCurrentScene->updatePhysics(); + + // Update the timer + mTimer.nextStep(mEngineSettings.timeStep); + } + } +} + +void TestbedApplication::update() { + + double currentTime = glfwGetTime(); + + // Update the physics + if (mSinglePhysicsStepEnabled && !mSinglePhysicsStepDone) { + updateSinglePhysicsStep(); + mSinglePhysicsStepDone = true; + } + else { + updatePhysics(); + } + + // Compute the physics update time + mPhysicsTime = glfwGetTime() - currentTime; + + // Compute the interpolation factor + float factor = mTimer.computeInterpolationFactor(mEngineSettings.timeStep); + assert(factor >= 0.0f && factor <= 1.0f); + + // Notify the scene about the interpolation factor + mCurrentScene->setInterpolationFactor(factor); + + // Enable/Disable shadow mapping + mCurrentScene->setIsShadowMappingEnabled(mIsShadowMappingEnabled); + + // Display/Hide contact points + mCurrentScene->setIsContactPointsDisplayed(mIsContactPointsDisplayed); + + // Display/Hide the AABBs + mCurrentScene->setIsAABBsDisplayed(mIsAABBsDisplayed); + + // Enable/Disable wireframe mode + mCurrentScene->setIsWireframeEnabled(mIsWireframeEnabled); + + // Update the scene + mCurrentScene->update(); +} + +void TestbedApplication::drawContents() { + + update(); + + int bufferWidth, bufferHeight; + glfwMakeContextCurrent(mGLFWWindow); + glfwGetFramebufferSize(mGLFWWindow, &bufferWidth, &bufferHeight); + + // Set the viewport of the scene + mCurrentScene->setViewport(0, 0, bufferWidth, bufferHeight); + + // Render the scene + mCurrentScene->render(); + + // Check the OpenGL errors + checkOpenGLErrors(); + + mGui.update(); + + // Compute the current framerate + computeFPS(); +} + +/// Window resize event handler +bool TestbedApplication::resizeEvent(const Vector2i& size) { + + if (!mIsInitialized) return false; + + // Get the framebuffer dimension + int width, height; + glfwGetFramebufferSize(mGLFWWindow, &width, &height); + + // Resize the camera viewport + mCurrentScene->reshape(width, height); + + // Update the window size of the scene + int windowWidth, windowHeight; + glfwGetWindowSize(mGLFWWindow, &windowWidth, &windowHeight); + mCurrentScene->setWindowDimension(windowWidth, windowHeight); + + return true; +} + +// Change the current scene +void TestbedApplication::switchScene(Scene* newScene) { + + if (newScene == mCurrentScene) return; + + mCurrentScene = newScene; + + // Reset the scene + mCurrentScene->reset(); + + mCurrentScene->updateEngineSettings(); + + resizeEvent(Vector2i(0, 0)); +} + +// Notify that the engine settings have changed +void TestbedApplication::notifyEngineSetttingsChanged() { + mCurrentScene->updateEngineSettings(); +} + +// Check the OpenGL errors +void TestbedApplication::checkOpenGLErrorsInternal(const char* file, int line) { + GLenum glError; + + // Get the OpenGL errors + glError = glGetError(); + + // While there are errors + while (glError != GL_NO_ERROR) { + + std::string error; + + switch(glError) { + case GL_INVALID_OPERATION: error="INVALID_OPERATION"; break; + case GL_INVALID_ENUM: error="INVALID_ENUM"; break; + case GL_INVALID_VALUE: error="INVALID_VALUE"; break; + case GL_OUT_OF_MEMORY: error="OUT_OF_MEMORY"; break; + case GL_INVALID_FRAMEBUFFER_OPERATION: error="INVALID_FRAMEBUFFER_OPERATION"; break; + } + + std::cerr << "OpenGL Error #" << error.c_str() << " - " << file << ": " << line << std::endl; + + // Get the next error + glError = glGetError(); + } +} + + +// Compute the FPS +void TestbedApplication::computeFPS() { + + // Note : By default the nanogui library is using glfwWaitEvents() to process + // events and sleep to target a framerate of 50 ms (using a thread + // sleeping). However, for games we prefer to use glfwPollEvents() + // instead and remove the update. Therefore the file common.cpp of the + // nanogui library has been modified to have a faster framerate + + mNbFrames++; + + // Get the number of seconds since start + mCurrentTime = glfwGetTime(); + + // Calculate time passed + mFrameTime = mCurrentTime - mPreviousTime; + double timeInterval = (mCurrentTime - mLastTimeComputedFPS) * 1000.0; + + // Update the FPS counter each second + if(timeInterval > 1000) { + + // calculate the number of frames per second + mFPS = static_cast(mNbFrames) / timeInterval; + mFPS *= 1000.0; + + // Reset frame count + mNbFrames = 0; + + mLastTimeComputedFPS = mCurrentTime; + } + + // Set time + mPreviousTime = mCurrentTime; +} + +bool TestbedApplication::keyboardEvent(int key, int scancode, int action, int modifiers) { + + if (Screen::keyboardEvent(key, scancode, action, modifiers)) { + return true; + } + + // Close application on escape key + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(mGLFWWindow, GL_TRUE); + return true; + } + + return mCurrentScene->keyboardEvent(key, scancode, action, modifiers); +} + +// Handle a mouse button event (default implementation: propagate to children) +bool TestbedApplication::mouseButtonEvent(const Vector2i &p, int button, bool down, int modifiers) { + + if (Screen::mouseButtonEvent(p, button, down, modifiers)) { + return true; + } + + // Get the mouse cursor position + double x, y; + glfwGetCursorPos(mGLFWWindow, &x, &y); + + return mCurrentScene->mouseButtonEvent(button, down, modifiers, x, y); +} + +// Handle a mouse motion event (default implementation: propagate to children) +bool TestbedApplication::mouseMotionEvent(const Vector2i &p, const Vector2i &rel, int button, int modifiers) { + + if (Screen::mouseMotionEvent(p, rel, button, modifiers)) { + return true; + } + + int leftButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_LEFT); + int rightButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_RIGHT); + int middleButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_MIDDLE); + int altKeyState = glfwGetKey(mGLFWWindow, GLFW_KEY_LEFT_ALT); + + return mCurrentScene->mouseMotionEvent(p[0], p[1], leftButtonState, rightButtonState, + middleButtonState, altKeyState); +} + +// Handle a mouse scroll event (default implementation: propagate to children) +bool TestbedApplication::scrollEvent(const Vector2i &p, const Vector2f &rel) { + + if (Screen::scrollEvent(p, rel)) { + return true; + } + + return mCurrentScene->scrollingEvent(rel[0], rel[1], SCROLL_SENSITIVITY); +} diff --git a/testbed/src/TestbedApplication.h b/testbed/src/TestbedApplication.h index c9ca44ee..a72f5cb6 100644 --- a/testbed/src/TestbedApplication.h +++ b/testbed/src/TestbedApplication.h @@ -1,260 +1,260 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://www.reactphysics3d.com * -* Copyright (c) 2010-2016 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 TESTBED_APPLICATION_H -#define TESTBED_APPLICATION_H - -// Libraries -#include "openglframework.h" -#include "Gui.h" -#include "Scene.h" -#include "Timer.h" -#include - -using namespace nanogui; - -// Macro for OpenGL errors -#define checkOpenGLErrors() checkOpenGLErrorsInternal(__FILE__,__LINE__) - -/// Class TestbedApplication -class TestbedApplication : public Screen { - - private : - - // -------------------- Constants -------------------- // - - static const float SCROLL_SENSITIVITY; - - // -------------------- Attributes -------------------- // - - bool mIsInitialized; - - Gui mGui; - - /// Timer - Timer mTimer; - - /// List of 3D scenes - std::vector mScenes; - - /// Current 3D scene - Scene* mCurrentScene; - - /// Physics engine settings - EngineSettings mEngineSettings; - - /// Current number of frames per seconds - double mFPS; - - /// Number of frames during the last second - int mNbFrames; - - /// Current time for fps computation (in seconds) - double mCurrentTime; - - /// Previous time for fps computation (in seconds) - double mPreviousTime; - - /// Last time the FPS have been computed - double mLastTimeComputedFPS; - - /// Update time (in seconds) - double mFrameTime; - - /// Physics update time (in seconds) - double mPhysicsTime; - - /// Width and height of the window - int mWidth, mHeight; - - /// True if the next simulation update is a single physics step - bool mSinglePhysicsStepEnabled; - - /// True if the single physics step has been taken already - bool mSinglePhysicsStepDone; - - openglframework::Vector2 mWindowToFramebufferRatio; - - /// True if shadow mapping is enabled - bool mIsShadowMappingEnabled; - - /// True if contact points are displayed - bool mIsContactPointsDisplayed; - - /// True if the AABBs of physics objects are displayed - bool mIsAABBsDisplayed; - - /// True if the wireframe rendering is enabled - bool mIsWireframeEnabled; - - /// True if vsync is enabled - bool mIsVSyncEnabled; - - // -------------------- Methods -------------------- // - - /// Private copy-constructor (for the singleton class) - TestbedApplication(TestbedApplication const&); - - /// Private assignment operator (for the singleton class) - void operator=(TestbedApplication const&); - - /// Update the physics of the current scene - void updatePhysics(); - - /// Update - void update(); - - /// Update the simulation by taking a single physics step - void updateSinglePhysicsStep(); - - /// Check the OpenGL errors - static void checkOpenGLErrorsInternal(const char* file, int line); - - /// Compute the FPS - void computeFPS(); - - /// Initialize all the scenes - void createScenes(); - - /// Remove all the scenes - void destroyScenes(); - - /// Return the list of the scenes - std::vector getScenes(); - - /// Start/stop the simulation - void togglePlayPauseSimulation(); - - /// Play the simulation - void playSimulation(); - - /// Pause the simulation - void pauseSimulation(); - - /// Restart the simulation - void restartSimulation(); - - /// Set the variable to know if we need to take a single physics step - void toggleTakeSinglePhysicsStep(); - - public : - - // -------------------- Methods -------------------- // - - /// Private constructor (for the singleton class) - TestbedApplication(bool isFullscreen); - - /// Destructor - virtual ~TestbedApplication() override; - - /// Render the content of the application - virtual void drawContents() override; - - /// Window resize event handler - virtual bool resizeEvent(const Vector2i& size) override; - - /// Default keyboard event handler - virtual bool keyboardEvent(int key, int scancode, int action, int modifiers) override; - - /// Handle a mouse button event (default implementation: propagate to children) - virtual bool mouseButtonEvent(const Vector2i &p, int button, bool down, int modifiers) override; - - /// Handle a mouse motion event (default implementation: propagate to children) - virtual bool mouseMotionEvent(const Vector2i &p, const Vector2i &rel, int button, int modifiers) override; - - /// Handle a mouse scroll event (default implementation: propagate to children) - virtual bool scrollEvent(const Vector2i &p, const Vector2f &rel) override; - - /// Initialize the application - void init(); - - /// Change the current scene - void switchScene(Scene* newScene); - - /// Enable/Disable Vertical synchronization - void enableVSync(bool enable); - - /// Notify that the engine settings have changed - void notifyEngineSetttingsChanged(); - - // -------------------- Friendship -------------------- // - - friend class Gui; -}; - -// Return the list of the scenes -inline std::vector TestbedApplication::getScenes() { - return mScenes; -} - -// Toggle play/pause for the simulation -inline void TestbedApplication::togglePlayPauseSimulation() { - - if (mTimer.isRunning()) { - mTimer.stop(); - } - else { - mTimer.start(); - } -} - -// Play the simulation -inline void TestbedApplication::playSimulation() { - if (!mTimer.isRunning()) mTimer.start(); -} - -// Pause the simulation -inline void TestbedApplication::pauseSimulation() { - if (mTimer.isRunning()) mTimer.stop(); -} - -// Restart the simulation -inline void TestbedApplication::restartSimulation() { - mCurrentScene->reset(); - mTimer.start(); -} - -// Take a single step of simulation -inline void TestbedApplication::toggleTakeSinglePhysicsStep() { - mSinglePhysicsStepEnabled = true; - mSinglePhysicsStepDone = false; - - if (mTimer.isRunning()) { - mSinglePhysicsStepEnabled = false; - } -} - -// Enable/Disable Vertical synchronization -inline void TestbedApplication::enableVSync(bool enable) { - mIsVSyncEnabled = enable; - if (mIsVSyncEnabled) { - glfwSwapInterval(1); - } - else { - glfwSwapInterval(0); - } -} - -#endif +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2016 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 TESTBED_APPLICATION_H +#define TESTBED_APPLICATION_H + +// Libraries +#include "openglframework.h" +#include "Gui.h" +#include "Scene.h" +#include "Timer.h" +#include + +using namespace nanogui; + +// Macro for OpenGL errors +#define checkOpenGLErrors() checkOpenGLErrorsInternal(__FILE__,__LINE__) + +/// Class TestbedApplication +class TestbedApplication : public Screen { + + private : + + // -------------------- Constants -------------------- // + + static const float SCROLL_SENSITIVITY; + + // -------------------- Attributes -------------------- // + + bool mIsInitialized; + + Gui mGui; + + /// Timer + Timer mTimer; + + /// List of 3D scenes + std::vector mScenes; + + /// Current 3D scene + Scene* mCurrentScene; + + /// Physics engine settings + EngineSettings mEngineSettings; + + /// Current number of frames per seconds + double mFPS; + + /// Number of frames during the last second + int mNbFrames; + + /// Current time for fps computation (in seconds) + double mCurrentTime; + + /// Previous time for fps computation (in seconds) + double mPreviousTime; + + /// Last time the FPS have been computed + double mLastTimeComputedFPS; + + /// Update time (in seconds) + double mFrameTime; + + /// Physics update time (in seconds) + double mPhysicsTime; + + /// Width and height of the window + int mWidth, mHeight; + + /// True if the next simulation update is a single physics step + bool mSinglePhysicsStepEnabled; + + /// True if the single physics step has been taken already + bool mSinglePhysicsStepDone; + + openglframework::Vector2 mWindowToFramebufferRatio; + + /// True if shadow mapping is enabled + bool mIsShadowMappingEnabled; + + /// True if contact points are displayed + bool mIsContactPointsDisplayed; + + /// True if the AABBs of physics objects are displayed + bool mIsAABBsDisplayed; + + /// True if the wireframe rendering is enabled + bool mIsWireframeEnabled; + + /// True if vsync is enabled + bool mIsVSyncEnabled; + + // -------------------- Methods -------------------- // + + /// Private copy-constructor (for the singleton class) + TestbedApplication(TestbedApplication const&); + + /// Private assignment operator (for the singleton class) + void operator=(TestbedApplication const&); + + /// Update the physics of the current scene + void updatePhysics(); + + /// Update + void update(); + + /// Update the simulation by taking a single physics step + void updateSinglePhysicsStep(); + + /// Check the OpenGL errors + static void checkOpenGLErrorsInternal(const char* file, int line); + + /// Compute the FPS + void computeFPS(); + + /// Initialize all the scenes + void createScenes(); + + /// Remove all the scenes + void destroyScenes(); + + /// Return the list of the scenes + std::vector getScenes(); + + /// Start/stop the simulation + void togglePlayPauseSimulation(); + + /// Play the simulation + void playSimulation(); + + /// Pause the simulation + void pauseSimulation(); + + /// Restart the simulation + void restartSimulation(); + + /// Set the variable to know if we need to take a single physics step + void toggleTakeSinglePhysicsStep(); + + public : + + // -------------------- Methods -------------------- // + + /// Private constructor (for the singleton class) + TestbedApplication(bool isFullscreen, int windowWidth, int windowHeight); + + /// Destructor + virtual ~TestbedApplication() override; + + /// Render the content of the application + virtual void drawContents() override; + + /// Window resize event handler + virtual bool resizeEvent(const Vector2i& size) override; + + /// Default keyboard event handler + virtual bool keyboardEvent(int key, int scancode, int action, int modifiers) override; + + /// Handle a mouse button event (default implementation: propagate to children) + virtual bool mouseButtonEvent(const Vector2i &p, int button, bool down, int modifiers) override; + + /// Handle a mouse motion event (default implementation: propagate to children) + virtual bool mouseMotionEvent(const Vector2i &p, const Vector2i &rel, int button, int modifiers) override; + + /// Handle a mouse scroll event (default implementation: propagate to children) + virtual bool scrollEvent(const Vector2i &p, const Vector2f &rel) override; + + /// Initialize the application + void init(); + + /// Change the current scene + void switchScene(Scene* newScene); + + /// Enable/Disable Vertical synchronization + void enableVSync(bool enable); + + /// Notify that the engine settings have changed + void notifyEngineSetttingsChanged(); + + // -------------------- Friendship -------------------- // + + friend class Gui; +}; + +// Return the list of the scenes +inline std::vector TestbedApplication::getScenes() { + return mScenes; +} + +// Toggle play/pause for the simulation +inline void TestbedApplication::togglePlayPauseSimulation() { + + if (mTimer.isRunning()) { + mTimer.stop(); + } + else { + mTimer.start(); + } +} + +// Play the simulation +inline void TestbedApplication::playSimulation() { + if (!mTimer.isRunning()) mTimer.start(); +} + +// Pause the simulation +inline void TestbedApplication::pauseSimulation() { + if (mTimer.isRunning()) mTimer.stop(); +} + +// Restart the simulation +inline void TestbedApplication::restartSimulation() { + mCurrentScene->reset(); + mTimer.start(); +} + +// Take a single step of simulation +inline void TestbedApplication::toggleTakeSinglePhysicsStep() { + mSinglePhysicsStepEnabled = true; + mSinglePhysicsStepDone = false; + + if (mTimer.isRunning()) { + mSinglePhysicsStepEnabled = false; + } +} + +// Enable/Disable Vertical synchronization +inline void TestbedApplication::enableVSync(bool enable) { + mIsVSyncEnabled = enable; + if (mIsVSyncEnabled) { + glfwSwapInterval(1); + } + else { + glfwSwapInterval(0); + } +} + +#endif