diff --git a/cmake/Hunter/config.cmake b/cmake/Hunter/config.cmake --- a/cmake/Hunter/config.cmake +++ b/cmake/Hunter/config.cmake @@ -1,2 +1,1 @@ -hunter_config(Boost VERSION 1.69.0-p0) -hunter_config(utf8 VERSION 2.3.4-p0) \ No newline at end of file +hunter_config(Boost VERSION 1.69.0-p0) \ No newline at end of file diff --git a/include/echo/Physics/BulletCollisionResult.h b/include/echo/Physics/BulletCollisionResult.h --- a/include/echo/Physics/BulletCollisionResult.h +++ b/include/echo/Physics/BulletCollisionResult.h @@ -1,40 +1,40 @@ #ifndef ECHOBULLETMANIFOLDRESULT_H #define ECHOBULLETMANIFOLDRESULT_H #include -#include +#include namespace Echo { class BulletCollisionResult : public CollisionResult, public btManifoldResult { public: BulletCollisionResult(const btCollisionObjectWrapper* body0, const btCollisionObjectWrapper* body1) : btManifoldResult(body0, body1), mNumberOfContactPoints(0), mLastContactPoint(Vector3::ZERO) {} ~BulletCollisionResult(){} virtual Size GetNumberOfContactPoints() const override {return mNumberOfContactPoints;} virtual Vector3 GetLastContactPoint() const override { return mLastContactPoint;} private: /** * Called by bullet to add a contact point. */ virtual void addContactPoint(const btVector3& normalOnBInWorld, const btVector3& pointInWorld, btScalar depth) override { mNumberOfContactPoints++; mLastContactPoint.x = pointInWorld.getX(); mLastContactPoint.y = pointInWorld.getY(); mLastContactPoint.z = pointInWorld.getZ(); btManifoldResult::addContactPoint(normalOnBInWorld, pointInWorld, depth); } Size mNumberOfContactPoints; Vector3 mLastContactPoint; }; } #endif /* BULLETMANIFOLDRESULT_H */ diff --git a/include/echo/Physics/BulletFactory.h b/include/echo/Physics/BulletFactory.h --- a/include/echo/Physics/BulletFactory.h +++ b/include/echo/Physics/BulletFactory.h @@ -1,181 +1,181 @@ #ifndef _ECHOBULLETFACTORY_H_ #define _ECHOBULLETFACTORY_H_ #include #include -#include +#include #include #include #include #include #include #include namespace Echo { /** * A factory class that makes creating physics worlds easier. * This is a higher level interface to building a physics world. You can create a physics world * manually by using bullet directly but keep in mind you'll also need to manage the bullet * objects memory appropriately. The Echo Bullet classes encapsulate bullet objects for common * interfaces and to keep track of the bullet objects so you do not have to. * * This factory will create a world if you do not provide it one during construction. This * provides convenience as you do not explicitly need to create a PhysicsWorld but if you * want to instantiate a factory to create objects for an existing world you can pass one in. * Once used, you can destroy a BulletFactory safely. If any PhysicsBodies have been created * for the world they will have a reference to it, so as long as you keep the PhysicsBody * instances the world will continue to exist. Although for any simulation, something will * need a reference to the world in order to update the simulation (usually a TaskManager since * PhysicsWorld is a TaskGroup). */ class BulletFactory : public PhysicsFactory { public: /** * Default constructor. * Since functions depend on a physics world if one isn't defined a default one will * be created. * @see CreateDefaultDynamicsWorld() for parameter information. */ BulletFactory(AxisAlignedBox worldExtent = AxisAlignedBox(Vector3(-1000, -1000, -1000), Vector3(1000, 1000, 1000)), int maxProxies=8192); BulletFactory(shared_ptr world); ~BulletFactory(); /** * Create a box shape. * @param extents The size of the box, e.g. Vector(1,1,1) creates a unit cube. * @return A BulletPhysicsShape containing a btBoxShape. */ shared_ptr CreateBox(Vector3 extents) override; /** * Create a sphere shape. * @param radius Radius of the sphere. * @return A BulletPhysicsShape containing a btSphereShape. */ shared_ptr CreateSphere(Scalar radius) override; /** * Create a static plane shape. * The shape should be used on a static body (i.e. mass of 0, non moving). * @param planeNormal The normal that defines the face of the plane, Vector3(0,1,0) is a plane facing up. * @param planeConstant The constant that defines where the plan is from the origin. * @return A BulletPhysicsShape containing a btStaticPlaneShape. */ shared_ptr CreateStaticPlane(Vector3 planeNormal, Scalar planeConstant) override; /** * Create a capsule shape. * The capsule is orientated along the Y axis. * @param radius The radius of the capsule. * @param height The height of the capsule from the centre of the two hemisphere ends, so the total * height is height+2*radius. * @return A BulletPhysicsShape containing a btCapsuleShape; */ shared_ptr CreateCapsule(Scalar radius, Scalar height) override; /** * Create a capsule along the X axis. * @see CreateCapsule(). * @return A BulletPhysicsShape containing a btCapsuleShapeX; */ shared_ptr CreateCapsuleX(Scalar radius, Scalar height) override; /** * Create a capsule along the Z axis. * @see CreateCapsule(). * @return A BulletPhysicsShape containing a btCapsuleShapeZ; */ shared_ptr CreateCapsuleZ(Scalar radius, Scalar height) override; /** * Create a collision mesh from the provided mesh. * @param mesh The mesh to copy data from. * @return A BulletPhysicsShape */ shared_ptr CreateMesh(shared_ptr mesh, bool usedForDynamics) override; /** * Create a default dynamics world. * A default world is a btDiscreteDynamicsWorld constructed using: * - btDefaultCollisionConfiguration * - btCollisionDispatcher * - btAxisSweep3 * - btSequentialImpulseConstraintSolver * @param worldExtent world AABB extent. * @param maxProxies The maximum number of objects that can be in the world. * @return A BulletPhysicsWorld. */ shared_ptr CreateDefaulDynamicsWorld(AxisAlignedBox worldExtent = AxisAlignedBox(Vector3(-1000, -1000, -1000), Vector3(1000, 1000, 1000)), int maxProxies=8192) override; /** * Create a rigid body. * This method will create a body for the specified entity using the specified shape. A dynamic * motion state will be created to link the SceneEntity with the body. * The body created will update the entity's position. * @note Once this method returns, if addToWorld is not true, then the object will need to be stored * somewhere otherwise it will be deleted. * @param mass The mass of the object, 0 is static (i.e. does not move). * @param forEntity The entity to link this body with. * @param shape The shape to use. * @param addToWorld if true the body will be added to the world, false if you plan to add it later. * @return The newly created rigid body. */ shared_ptr CreateRigidBody(Scalar mass, shared_ptr forEntity, shared_ptr shape, bool addToWorld = true) override; /** * Create a rigid body for the scene. * Similar to the CreateRigidBody() that includes a SceneEntity parameter, but does not create a * motion state to link an entity with a physics body. This method can be used if you want to * create an "invisible" object in the scene. * @note Once this method returns, if addToWorld is not true, then the object will need to be stored * somewhere otherwise it will be deleted. * @param mass The mass of the object, 0 is static (i.e. does not move). * @param shape The shape to use. * @param addToWorld if true the body will be added to the world, false if you plan to add it later. * @return The newly created rigid body. */ shared_ptr CreateRigidBody(Scalar mass, shared_ptr shape, bool addToWorld = true) override; /** * Create a dynamic motion state for an entity and body. * A motion state is essentially the link between a physics object and a SceneEntity. The Entity * should be given a mesh that matches the body's shape you've provided in order for your * simulation to look correct. For example, you could create a body with a unit cube shape but if * the mesh is a sphere with a radius of 10 then the sphere will behave contrary to how people * might expect. * @param forEntity The entity that will be linked to the body. * @param body The body that will be linked with the entity. * @param activate If true, the motion state will be activated. A motion state can be deactivated * to stop the SceneEntity updating to the physics object. * @return A new motion state. */ shared_ptr CreateDynamicMotionState(shared_ptr forEntity, shared_ptr body, bool activate = true) override; /** * Create a SceneEntity setup with a simple debug drawer. * This method sets the world's debug drawer. * @param debugMod The debug drawing mode. See BulletMeshDebugDrawer and btIDebugDraw for what is supported. * @return A scene entity that, when added to a scene, will draw the physics objects in the scene. */ shared_ptr CreateDebugSceneEntity(int debugMod = (btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb)) override; /** * Get the bullet physics world. * @return The bullet physics world. */ shared_ptr GetWorld() {return mWorld;} private: shared_ptr mWorld; /** * Internal method used to create a dynamics world to avoid a cast in the constructor. * @see CreateDefaulDynamicsWorld(). */ virtual shared_ptr _CreateDefaulDynamicsWorld(AxisAlignedBox worldExtent, int maxProxies); }; } #endif diff --git a/include/echo/Physics/BulletMeshDebugDrawer.h b/include/echo/Physics/BulletMeshDebugDrawer.h --- a/include/echo/Physics/BulletMeshDebugDrawer.h +++ b/include/echo/Physics/BulletMeshDebugDrawer.h @@ -1,94 +1,94 @@ #ifndef _ECHOBULLETMESHDEBUGDRAWER_H_ #define _ECHOBULLETMESHDEBUGDRAWER_H_ -#include +#include #include #include namespace Echo { /** * BulletMeshDebugDrawer will draw lines to a SubMesh which can then be * used to render in a Scene. * @note The class only draws lines. Points are not supported. * @note The class clears after every render so if you have multiple viewports you will only see the debug information in the first one. * @ */ class BulletMeshDebugDrawer : public btIDebugDraw, public Mesh { public: BulletMeshDebugDrawer(); ~BulletMeshDebugDrawer(); /** * Draw a line. * Override from btIDebugDraw. */ virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& colour) override; /** * Drawing contact points is currently unsupported. * Override from btIDebugDraw. */ virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& colour) override; /** * Output a warning to stdout. * override from btIDebugDraw. * @param warningString. */ virtual void reportErrorWarning(const char* warningString) override; /** * Set the debug draw mode. * DBG_DrawWireframe | DBG_DrawAabb is a common combination. See btIDebugDraw for more. * @note not all debug information will be displayed with this drawer. * override from btIDebugDraw. */ virtual void setDebugMode(int debugMode) override; /** * Get the debug draw mode. * override from btIDebugDraw. * @return */ virtual int getDebugMode() const override; /** * Drawing 3D text is currently unsupported. * override from btIDebugDraw. */ virtual void draw3dText(const btVector3& location,const char* textString) override; /** * Mesh Render override. * Clears the mesh data after rendering. */ virtual void Render(RenderContext& renderContext, const Matrix4& world, const Matrix4& worldView, Colour compoundDiffuse) override; /** * Lock the object to prevent it from rendering. * If you're using different threads for rendering and debug drawing you should lock before debug drawing and unlock when you're done. */ void Lock(); /** * Unlock the object to allow it to render. * If you're using different threads for rendering and debug drawing you should lock before debug drawing and unlock when you're done. */ void Unlock(); private: int mDebugMode; Size mNumberOfVertices; Size mNumberOfLines; bool mJustRendered; shared_ptr mSubMesh; shared_ptr mVertexBuffer; VertexBuffer::Accessor mVertices; VertexBuffer::Accessor mColours; shared_ptr< ElementBuffer > mElementBuffer; ElementBuffer::Accessor< ElementBuffer::Line< u32 > > mLines; Mutex mMutex; }; } #endif diff --git a/include/echo/Physics/BulletMotionState.h b/include/echo/Physics/BulletMotionState.h --- a/include/echo/Physics/BulletMotionState.h +++ b/include/echo/Physics/BulletMotionState.h @@ -1,34 +1,34 @@ #ifndef _ECHOBULLETMOTIONSTATE_H_ #define _ECHOBULLETMOTIONSTATE_H_ #include #include -#include +#include namespace Echo { class NodeInterface; /** * BulletMotionState. */ class BulletMotionState : public MotionState, public btMotionState { public: /** * Constructor. * @param body the body the motion state is intended for. * @param nodeInterface Must not be null. */ BulletMotionState(BulletRigidBody& body, shared_ptr nodeInterface); virtual ~BulletMotionState(); virtual void Activate() override; virtual void Deactivate() override; virtual BulletRigidBody& GetBody() override; virtual shared_ptr GetNodeInterface() const override; protected: BulletRigidBody& mBody; shared_ptr mNodeInterface; }; } #endif diff --git a/include/echo/Physics/BulletTypeConverters.h b/include/echo/Physics/BulletTypeConverters.h --- a/include/echo/Physics/BulletTypeConverters.h +++ b/include/echo/Physics/BulletTypeConverters.h @@ -1,30 +1,30 @@ #ifndef _ECHOBULLETTYPECONVERTERS_H_ #define _ECHOBULLETTYPECONVERTERS_H_ #include #include -#include -#include +#include +#include namespace Echo { inline btVector3 Convert(const Vector3& from) { return btVector3(from.x,from.y,from.z); } inline Vector3 Convert(const btVector3& from) { return Vector3(from.getX(),from.getY(),from.getZ()); } inline btQuaternion Convert(const Quaternion& from) { return btQuaternion(from.x,from.y,from.z,from.w); } inline Quaternion Convert(const btQuaternion& from) { return Quaternion(from.getX(),from.getY(),from.getZ(),from.getW()); } } #endif diff --git a/include/echo/UTF8String.h b/include/echo/UTF8String.h --- a/include/echo/UTF8String.h +++ b/include/echo/UTF8String.h @@ -1,345 +1,345 @@ #ifndef _ECHOUTFSTRING_H_ #define _ECHOUTFSTRING_H_ #include #include #include #include -#include +#include namespace Echo { typedef std::vector UTF16String; typedef std::vector UTF32String; /** * UTF8String is a Unicode string that uses UTF-8 encoding. * The class is essentially a C++ wrapper around some of the libutfcpp. * See http://utfcpp.sourceforge.net/ * Feel free to add functionality as needed. * * Example: * UTF8String greeting("coi ro do"); * UTF8String something("\xE2\x88\x83y \xE2\x88\x80x \xC2\xAC(x \xE2\x89\xBA y)"); */ class UTF8String { public: /** * Default constructor. */ UTF8String() : mContent() { } /** * Construct a UTF8String from a null-terminated ASCII character sequence. * The character sequence should not use any extended ASCII characters, this may result in unexpected UTF-8 strings. * @param asciiCharString */ UTF8String(const char* asciiCharString) { std::string asciiString(asciiCharString); std::string utfSafe; utf8::replace_invalid(asciiString.begin(), asciiString.end(), std::back_inserter(utfSafe)); mContent = utfSafe; } /** * Construct a UTF8String from a null-terminated ASCII character sequence. * The character sequence should not use any extended ASCII characters, this may result in unexpected UTF-8 strings. * @param asciiCharString */ UTF8String(const std::string& asciiString) { std::string utfSafe; utf8::replace_invalid(asciiString.begin(), asciiString.end(), std::back_inserter(utfSafe)); mContent = utfSafe; } /** * Copy constructor * @param utfString */ UTF8String(const UTF8String& utfString) : mContent(utfString.mContent) { } /** * Destructor */ ~UTF8String() { } /** * Iterator class. * When an iterator is dereferenced on a valid iterator a UTF-32 code is returned. */ class iterator { public: /** * Constructor used by UTF8String to assign the position. */ iterator(const UTF8String& utf8String, const char* position) : mString(&utf8String) { if(position) { mPosition = position; mCurrent = utf8::next(mPosition,mString->raw_end()); }else { mPosition = 0; mCurrent = 0; } } /** * Copy constructor */ iterator(const iterator& rhs) : mPosition(rhs.mPosition), mString(rhs.mString), mCurrent(rhs.mCurrent) { } /** * Default constructor. */ iterator() : mPosition(0), mString(0), mCurrent(0) { } /** * Prefix */ const iterator& operator++() { try { mCurrent = utf8::next(mPosition,mString->raw_end()); }catch(utf8::not_enough_room) { //Now it's an end iterator. mPosition = 0; mCurrent = 0; } return *this; } /** * Postfix */ iterator operator++(int) { iterator i = *this; operator++(); return i; } bool operator==(const iterator& rhs) { return mPosition==rhs.mPosition; } bool operator!=(const iterator& rhs) { return mPosition!=rhs.mPosition; } iterator& operator=(const iterator& rhs) { if (this == &rhs) return *this; mPosition=rhs.mPosition; mString=rhs.mString; mPosition=rhs.mPosition; return *this; } /** * Dereferencing the iterator returns the UTF32Code. * The returned code will be 0 for invalid iterators. * @return UTF32Code. */ UTF32Code operator*() const {return mCurrent;} private: const char* mPosition; //When const UTF8String* mString; UTF32Code mCurrent; }; /** * Get a iterator pointing to the beginning of the UTF-8 sequence. * @return */ iterator begin() { return iterator(*this, raw_begin()); } iterator end() { //End iterators have a position value of 0. return iterator(*this, 0); } iterator begin() const { return iterator(*this, raw_begin()); } iterator end() const { //End iterators have a position value of 0. return iterator(*this, 0); } size_t Length() const { try { return utf8::distance(mContent.begin(), mContent.end()); } catch(utf8::invalid_code_point except) { ECHO_LOG_ERROR(except.what()); return 0; } } UTF8String& operator=(const UTF8String& rhs) { if (this == &rhs) return *this; mContent=rhs.mContent; return *this; } bool operator==(const UTF8String& rhs) { return mContent==rhs.mContent; } bool operator!=(const UTF8String& rhs) { return mContent!=rhs.mContent; } const UTF8String& operator+=(const UTF8String& rhs) { mContent+=rhs.mContent; return *this; } UTF8String operator+(const UTF8String& rhs) const { UTF8String newString(*this); newString+=rhs; return newString; } const UTF8String& operator+=(const std::string& rhs) { UTF8String utf8rhs(rhs); mContent+=utf8rhs.mContent; return *this; } const UTF8String& operator+=(UTF32Code code) { try { utf8::append(code,std::back_inserter(mContent)); } catch(utf8::invalid_code_point except) { ECHO_LOG_ERROR(except.what()); } return *this; } friend std::ostream& operator<<(std::ostream& o, const UTF8String& s) { //Unix systems tend to be able to handle UTF-8 strings in consoles but might be a problem for other platforms. o << s.mContent; //o << "UTF8String(" << s.Length() << "):" << s.mContent; return o; } /** * Convert to a UTF16String * @return */ operator UTF16String() const { UTF16String utf16String; utf8::utf8to16(mContent.begin(), mContent.end(), std::back_inserter(utf16String)); return utf16String; } /** * Convert to a UTF32String * @return */ operator UTF32String() const { UTF32String utf32String; utf8::utf8to32(mContent.begin(), mContent.end(), std::back_inserter(utf32String)); return utf32String; } UTF8String& operator=(const UTF16String& rhs) { utf8::utf16to8(rhs.begin(), rhs.end(), std::back_inserter(mContent)); return *this; } /** * Allows you to get the UTF-8 sequence. * NOTE: The returned string generally should not be used as a normal string. This method is * made available for situations where you might need the raw data something, like to writing * to a file or sending over a network. * Alternatively if ContainsAllASCIICharacters() returns true then it is safe to use the returned. */ const std::string& GetContent() const {return mContent;} void clear() { mContent.clear(); } /** * Check whether the string contains all ASCII characters. * If it does then it is safe to use GetContent() and store the string as a std::string. * @return true if all characters are ASCII characters, otherwise false. */ bool ContainsAllASCIICharacters() { for(iterator c=begin(); c!=end();++c) { // 0x80 is 128 which is the 8th bit in a byte, this indicates in UTF8 that the code point // contains more code units. http://en.wikipedia.org/wiki/UTF-8 explains how UTF8 is encoded. if(*c>=UTF32Code(0x80)) { return false; } } //no characters >=0x80 were found, it is an ASCII string. return true; } private: std::string mContent; //Use a normal string to simplify operations. friend class iterator; const char* raw_begin() const { return mContent.c_str(); } const char* raw_end() const { return mContent.c_str()+mContent.length(); } }; } #endif diff --git a/src/Physics/BulletFactory.cpp b/src/Physics/BulletFactory.cpp --- a/src/Physics/BulletFactory.cpp +++ b/src/Physics/BulletFactory.cpp @@ -1,175 +1,175 @@ #include #include #include #include #include #include #include #include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -#include -#include -#include -#include +#include +#include +#include +#include namespace Echo { BulletFactory::BulletFactory(AxisAlignedBox worldExtent, int maxProxies) { mWorld = _CreateDefaulDynamicsWorld(worldExtent,maxProxies); } BulletFactory::BulletFactory(shared_ptr world) : mWorld(world) { assert(mWorld && "World must not be null."); } BulletFactory::~BulletFactory() { } shared_ptr BulletFactory::CreateBox(Vector3 extents) { return shared_ptr(new BulletPhysicsShape(new btBoxShape(Convert(extents*0.5f)))); } shared_ptr BulletFactory::CreateSphere(Scalar radius) { return shared_ptr(new BulletPhysicsShape(new btSphereShape(radius))); } shared_ptr BulletFactory::CreateStaticPlane(Vector3 planeNormal, Scalar planeConstant) { return shared_ptr(new BulletPhysicsShape(new btStaticPlaneShape(Convert(planeNormal),planeConstant))); } shared_ptr BulletFactory::CreateCapsule(Scalar radius, Scalar height) { return shared_ptr(new BulletPhysicsShape(new btCapsuleShape(radius,height))); } shared_ptr BulletFactory::CreateCapsuleX(Scalar radius, Scalar height) { return shared_ptr(new BulletPhysicsShape(new btCapsuleShapeX(radius,height))); } shared_ptr BulletFactory::CreateCapsuleZ(Scalar radius, Scalar height) { return shared_ptr(new BulletPhysicsShape(new btCapsuleShapeZ(radius,height))); } shared_ptr BulletFactory::CreateMesh(shared_ptr mesh, bool usedForDynamics) { return shared_ptr(new BulletMeshPhysicsShape(mesh, usedForDynamics ? BulletMeshPhysicsShape::Modes::DYNAMIC_BODY : BulletMeshPhysicsShape::Modes::STATIC_BODY)); } shared_ptr BulletFactory::CreateDefaulDynamicsWorld(AxisAlignedBox worldExtent, int maxProxies) { return _CreateDefaulDynamicsWorld(worldExtent,maxProxies); } shared_ptr BulletFactory::_CreateDefaulDynamicsWorld(AxisAlignedBox worldExtent, int maxProxies) { btCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration(); btCollisionDispatcher* dispatcher=new btCollisionDispatcher(collisionConfiguration); btBroadphaseInterface* pairCache=new btAxisSweep3(Convert(worldExtent.GetMinimum()), Convert(worldExtent.GetMaximum()), maxProxies); btConstraintSolver* constraintSolver=new btSequentialImpulseConstraintSolver(); shared_ptr dynamicsWorld(new btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration)); return shared_ptr(new BulletPhysicsWorld(dynamicsWorld)); } shared_ptr BulletFactory::CreateRigidBody(Scalar mass, shared_ptr forEntity, shared_ptr shape, bool addToWorld) { shared_ptr bulletShape = dynamic_pointer_cast(shape); if(!bulletShape) { ECHO_LOG_ERROR("BulletFactory::CreateRigidBody: provided shape is not a BulletPhysicsShape."); return nullptr; } btRigidBody::btRigidBodyConstructionInfo constructInfo(mass, 0, 0); shared_ptr bulletBody(new btRigidBody(constructInfo)); shared_ptr body(new BulletRigidBody(mWorld,bulletBody)); shared_ptr motionState = dynamic_pointer_cast(CreateDynamicMotionState(forEntity,body,true)); if(!motionState) { // This shouldn't happen, but I want to allow extending of the BulletFactory in the future and in doing so // allow changes to CreateDynamicMotionState(), in which case we'll this method will also want to be overridden. ECHO_LOG_ERROR("BulletFactory::CreateRigidBody: internal error. Unable to create BulletDynamicMotionState."); return nullptr; } body->SetMotionState(motionState); body->SetShape(bulletShape); bulletBody->setCcdMotionThreshold(1); //Continuous Collision Detection won't be performed if the motion exceeds 1 metre. if(addToWorld) { mWorld->AddBody(body); } return body; } shared_ptr BulletFactory::CreateRigidBody(Scalar mass, shared_ptr shape, bool addToWorld) { shared_ptr bulletShape = dynamic_pointer_cast(shape); if(!bulletShape) { ECHO_LOG_ERROR("BulletFactory::CreateRigidBody: provided shape is not a BulletPhysicsShape."); return nullptr; } btRigidBody::btRigidBodyConstructionInfo constructInfo(mass, 0, 0); shared_ptr bulletBody(new btRigidBody(constructInfo)); shared_ptr body(new BulletRigidBody(mWorld,bulletBody)); body->SetShape(bulletShape); bulletBody->setCcdMotionThreshold(1); //Continuous Collision Detection won't be performed if the motion exceeds 1 metre. if(addToWorld) { mWorld->AddBody(body); } return body; } shared_ptr BulletFactory::CreateDynamicMotionState(shared_ptr forEntity, shared_ptr body, bool activate) { shared_ptr bulletBody = dynamic_pointer_cast(body); if(!bulletBody) { ECHO_LOG_ERROR("BulletFactory::CreateDynamicMotionState: passed body is not a BulletRigidBody."); return nullptr; } shared_ptr motionState(new BulletDynamicMotionState(*bulletBody,forEntity)); bulletBody->SetMotionState(motionState); if(activate) { motionState->Activate(); } return motionState; } shared_ptr BulletFactory::CreateDebugSceneEntity(int debugMode) { shared_ptr debugDrawer(new BulletMeshDebugDrawer()); debugDrawer->setDebugMode(debugMode); //Create the scene entity. shared_ptr entity(new SceneEntity()); entity->SetMesh(debugDrawer); //Set the world debug drawer. mWorld->GetDynamicsWorld()->setDebugDrawer(debugDrawer.get()); return entity; } } diff --git a/src/Physics/BulletMeshPhysicsShape.cpp b/src/Physics/BulletMeshPhysicsShape.cpp --- a/src/Physics/BulletMeshPhysicsShape.cpp +++ b/src/Physics/BulletMeshPhysicsShape.cpp @@ -1,104 +1,104 @@ #include #include #include -#include -#include +#include +#include namespace Echo { BulletMeshPhysicsShape::BulletMeshPhysicsShape(shared_ptr mesh, Mode mode) { mIndexVertexArrays = new btTriangleIndexVertexArray(); SetMesh(mesh); switch(mode) { case Modes::DYNAMIC_BODY: { btGImpactMeshShape* collisionShape = new btGImpactMeshShape(mIndexVertexArrays); collisionShape->setLocalScaling(btVector3(1.f, 1.f, 1.f)); collisionShape->setMargin(0.0f); collisionShape->updateBound(); SetCollisionShape(collisionShape); }break; default: case Modes::STATIC_BODY: { btBvhTriangleMeshShape* collisionShape = new btBvhTriangleMeshShape(mIndexVertexArrays, true, true); SetCollisionShape(collisionShape); }break; } } BulletMeshPhysicsShape::~BulletMeshPhysicsShape() { delete mIndexVertexArrays; } void BulletMeshPhysicsShape::SetMesh(shared_ptr mesh) { if(!mesh) { assert(mesh && "Mesh cannot be null"); return; } mMesh = mesh; Size numberOfSubMeshes = mMesh->GetNumberOfSubMeshes(); for(Size s = 0; s < numberOfSubMeshes; ++s) { SubMesh& subMesh=*mMesh->GetSubMesh(s); VertexAttribute* attribute = subMesh.GetVertexBuffer()->GetVertexAttribute("Position"); if(!attribute) { ECHO_LOG_WARNING("Could not find vertex attribute using label \"Position\". Ensure your vertex buffers have a \"Position\" attribute to use them as physics shapes." ); continue; } shared_ptr elementBuffer = subMesh.GetElementBuffer(); if(!elementBuffer) { ECHO_LOG_WARNING("SubMesh is incomplete, ElementBuffer is null"); continue; } if(elementBuffer->GetElementType()!=ElementBuffer::ElementTypes::TRIANGLE && elementBuffer->GetElementType()!=ElementBuffer::ElementTypes::TRIANGLE_STRIP) { ECHO_LOG_WARNING("SubMesh ElementBuffer does not contain compatible triangles."); continue; } btIndexedMesh indexedMesh; indexedMesh.m_numTriangles = elementBuffer->GetNumberOfElements(); indexedMesh.m_triangleIndexBase = reinterpret_cast(elementBuffer->GetDataPointer()); indexedMesh.m_triangleIndexStride = elementBuffer->GetElementStride(); indexedMesh.m_numVertices = subMesh.GetVertexBuffer()->GetNumberOfElements(); indexedMesh.m_vertexStride = subMesh.GetVertexBuffer()->GetStride(); if(attribute->GetWidth()==sizeof(Vector3Double)) { VertexBuffer::Accessor vertices = subMesh.GetVertexBuffer()->GetAccessor("Position"); if(!vertices) { ECHO_LOG_WARNING("Could not find vertices using label \"Position\" unable to use SubMesh as physics shape. Ensure your vertex buffers have a \"Position\" attribute to use them as physics shapes." ); continue; } indexedMesh.m_vertexBase = reinterpret_cast(&(vertices[0])); indexedMesh.m_vertexType = PHY_DOUBLE; }else { VertexBuffer::Accessor vertices = subMesh.GetVertexBuffer()->GetAccessor("Position"); if(!vertices) { ECHO_LOG_WARNING("Could not find vertices using label \"Position\" unable to use SubMesh as physics shape. Ensure your vertex buffers have a \"Position\" attribute to use them as physics shapes." ); continue; } indexedMesh.m_vertexBase = reinterpret_cast(&(vertices[0])); indexedMesh.m_vertexType = PHY_FLOAT; } mIndexVertexArrays->addIndexedMesh(indexedMesh, PHY_SHORT); } } } diff --git a/src/Physics/BulletMotionState.cpp b/src/Physics/BulletMotionState.cpp --- a/src/Physics/BulletMotionState.cpp +++ b/src/Physics/BulletMotionState.cpp @@ -1,44 +1,44 @@ #include #include -#include +#include namespace Echo { BulletMotionState::BulletMotionState(BulletRigidBody& body, shared_ptr nodeInterface) : mBody(body), mNodeInterface(nodeInterface) { assert(nodeInterface && "nodeInterface must not be null"); } BulletMotionState::~BulletMotionState() { if(mBody.GetBulletBody()->getMotionState()==this) { mBody.GetBulletBody()->setMotionState(nullptr); } } void BulletMotionState::Activate() { mBody.GetBulletBody()->setMotionState(this); } void BulletMotionState::Deactivate() { if(mBody.GetBulletBody()->getMotionState()==this) { mBody.GetBulletBody()->setMotionState(nullptr); } } BulletRigidBody& BulletMotionState::GetBody() { return mBody; } shared_ptr BulletMotionState::GetNodeInterface() const { return mNodeInterface; } } diff --git a/src/Physics/BulletPhysicsShape.cpp b/src/Physics/BulletPhysicsShape.cpp --- a/src/Physics/BulletPhysicsShape.cpp +++ b/src/Physics/BulletPhysicsShape.cpp @@ -1,38 +1,38 @@ #include #include -#include -#include +#include +#include namespace Echo { BulletPhysicsShape::BulletPhysicsShape(btCollisionShape* shape) : mShape(shape), mDeleteChildrenIfCompoundShape(true) { assert(mShape && "mShape should not be null"); } BulletPhysicsShape::BulletPhysicsShape() : mShape(0) { } BulletPhysicsShape::~BulletPhysicsShape() { if(mDeleteChildrenIfCompoundShape) { btCompoundShape* compoundShape = dynamic_cast(mShape); if(compoundShape) { Size numberOfChildren = compoundShape->getNumChildShapes(); for(Size i=0;igetChildShape(i); } } } delete mShape; } void BulletPhysicsShape::StoreSubShape(shared_ptr shape) { mSubShapes.push_back(shape); } } diff --git a/src/Physics/BulletPhysicsWorld.cpp b/src/Physics/BulletPhysicsWorld.cpp --- a/src/Physics/BulletPhysicsWorld.cpp +++ b/src/Physics/BulletPhysicsWorld.cpp @@ -1,112 +1,112 @@ #include #include #include #include -#include -#include +#include +#include namespace Echo { //To avoid forward declaring a bullet types in the header void BulletPhysicsWorldNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo); void BulletPhysicsWorldTickCallback(btDynamicsWorld *world, btScalar timeStep); BulletPhysicsWorld::BulletPhysicsWorld() { } BulletPhysicsWorld::BulletPhysicsWorld(shared_ptr dynamicsWorld) { SetDynamicsWorld(dynamicsWorld); } BulletPhysicsWorld::~BulletPhysicsWorld() { } void BulletPhysicsWorld::SetDynamicsWorld(shared_ptr dynamicsWorld) { if(mDynamicsWorld) { btCollisionDispatcher* collisionDispatcher = dynamic_cast(mDynamicsWorld->getDispatcher()); if(collisionDispatcher) { collisionDispatcher->setNearCallback(0); } } mDynamicsWorld = dynamicsWorld; if(mDynamicsWorld) { mDynamicsWorld->setInternalTickCallback(&BulletPhysicsWorldTickCallback,reinterpret_cast(this),false); } } void BulletPhysicsWorld::Update(Seconds lastFrameTime) { TaskGroup::Update(lastFrameTime); if(mDynamicsWorld) { mDynamicsWorld->stepSimulation(lastFrameTime.count()); if(mDynamicsWorld->getDebugDrawer()) { mDynamicsWorld->debugDrawWorld(); } } } void BulletPhysicsWorld::AddBody(shared_ptr body) { shared_ptr bulletBody = dynamic_pointer_cast(body); if(bulletBody && mDynamicsWorld) { mDynamicsWorld->addRigidBody(bulletBody->GetBulletBody().get()); mBodies.insert(body); } } void BulletPhysicsWorld::RemoveBody(shared_ptr body) { shared_ptr bulletBody = dynamic_pointer_cast(body); if(bulletBody && mDynamicsWorld) { mDynamicsWorld->removeRigidBody(bulletBody->GetBulletBody().get()); mBodies.erase(body); } } void BulletPhysicsWorldTickCallback(btDynamicsWorld *world, btScalar timeStep) { int numManifolds = world->getDispatcher()->getNumManifolds(); for (int i = 0; i < numManifolds; i++) { btPersistentManifold* contactManifold = world->getDispatcher()->getManifoldByIndexInternal(i); const btCollisionObject* obA = contactManifold->getBody0(); const btCollisionObject* obB = contactManifold->getBody1(); //Collisions are processed, lets get out of here if our objects do not have user pointers. PhysicsBody* object0 = reinterpret_cast(obA->getUserPointer()); PhysicsBody* object1 = reinterpret_cast(obB->getUserPointer()); SimpleCollisionResult collisionResultA; SimpleCollisionResult collisionResultB; int numContacts = contactManifold->getNumContacts(); for (int j = 0; j < numContacts; j++) { btManifoldPoint& pt = contactManifold->getContactPoint(j); if (pt.getDistance() < 0.f) { const btVector3& ptA = pt.getPositionWorldOnA(); const btVector3& ptB = pt.getPositionWorldOnB(); //const btVector3& normalOnB = pt.m_normalWorldOnB; collisionResultA.AddContactPoint(Convert(ptA)); collisionResultB.AddContactPoint(Convert(ptB)); } } if(object0 && object1) { object1->OnCollide(*object0, collisionResultA); object0->OnCollide(*object1, collisionResultB); } } } } diff --git a/src/Physics/BulletRigidBody.cpp b/src/Physics/BulletRigidBody.cpp --- a/src/Physics/BulletRigidBody.cpp +++ b/src/Physics/BulletRigidBody.cpp @@ -1,243 +1,243 @@ #include #include #include #include #include -#include -#include +#include +#include #include namespace Echo { BulletRigidBody::BulletRigidBody(shared_ptr world, shared_ptr bulletBody) : PhysicsBody(world), mBulletBody(bulletBody) { assert(world && "world must not be null"); assert(bulletBody && "body must not be null"); mBulletBody->setUserPointer(this); } BulletRigidBody::~BulletRigidBody() { mBulletBody->setUserPointer(0); } void BulletRigidBody::SetMotionState(shared_ptr motionState) { mMotionState = motionState; } shared_ptr BulletRigidBody::GetMotionState() const { return mMotionState; } shared_ptr BulletRigidBody::GetShape() const { return mShape; } void BulletRigidBody::SetShape(shared_ptr shape) { mShape = shape; if(mShape) { if(!IsStaticObject() && mBulletBody->getInvMass()!=0.f) { btVector3 intertia; btScalar mass = 1.f / mBulletBody->getInvMass(); mShape->GetBulletShape()->calculateLocalInertia(mass,intertia); mBulletBody->setMassProps(mass,intertia); } mBulletBody->setCollisionShape(mShape->GetBulletShape()); } } Vector3 BulletRigidBody::GetPosition() const { return Convert(mBulletBody->getWorldTransform().getOrigin()); } void BulletRigidBody::SetPosition(const Vector3& position) { mBulletBody->getWorldTransform().setOrigin(Convert(position)); if(mMotionState && mMotionState->GetNodeInterface()) { mMotionState->GetNodeInterface()->SetPosition(position); } } Quaternion BulletRigidBody::GetOrientation() const { return Convert(mBulletBody->getWorldTransform().getRotation()); } void BulletRigidBody::SetOrientation(const Quaternion& orientation) { mBulletBody->getWorldTransform().setRotation(Convert(orientation)); } bool BulletRigidBody::IsInWorld() const { return mBulletBody->isInWorld(); } void BulletRigidBody::SetGravity(const Vector3& acceleration) { mBulletBody->setGravity(Convert(acceleration)); } Vector3 BulletRigidBody::GetGravity() const { return Convert(mBulletBody->getGravity()); } void BulletRigidBody::SetDamping(Scalar linearDamping, Scalar angularDamping) { mBulletBody->setDamping(linearDamping,angularDamping); } Scalar BulletRigidBody::GetLinearDamping() const { return mBulletBody->getLinearDamping(); } Scalar BulletRigidBody::GetAngularDamping() const { return mBulletBody->getAngularDamping(); } Scalar BulletRigidBody::GetLinearSleepingThreshold() const { return mBulletBody->getLinearSleepingThreshold(); } Scalar BulletRigidBody::GetAngularSleepingThreshold() const { return mBulletBody->getAngularSleepingThreshold(); } void BulletRigidBody::ApplyDamping(Seconds timeStep) const { mBulletBody->applyDamping(timeStep.count()); } void BulletRigidBody::SetMassProperties(Scalar mass, const Vector3& inertia) { return mBulletBody->setMassProps(mass, Convert(inertia)); } void BulletRigidBody::SetCentreOfMass(const Vector3& centreOfMass) { mBulletBody->setCenterOfMassTransform(btTransform(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f), Convert(centreOfMass))); } void BulletRigidBody::ApplyCentralForce(const Vector3& force) { mBulletBody->applyCentralForce(Convert(force)); } Vector3 BulletRigidBody::GetTotalForce() const { return Convert(mBulletBody->getTotalForce()); } Vector3 BulletRigidBody::GetTotalTorque() const { return Convert(mBulletBody->getTotalTorque()); } void BulletRigidBody::SetSleepingThresholds(Scalar linear,Scalar angular) { mBulletBody->setSleepingThresholds(linear,angular); } void BulletRigidBody::ApplyTorque(const Vector3& torque) { mBulletBody->applyTorque(Convert(torque)); } void BulletRigidBody::ApplyForce(const Vector3& force, const Vector3& relativePosition) { mBulletBody->applyForce(Convert(force),Convert(relativePosition)); } void BulletRigidBody::ApplyCentralImpulse(const Vector3& impulse) { mBulletBody->applyCentralImpulse(Convert(impulse)); } void BulletRigidBody::ApplyTorqueImpulse(const Vector3& torque) { mBulletBody->applyTorqueImpulse(Convert(torque)); } void BulletRigidBody::ApplyImpulse(const Vector3& impulse, const Vector3& relativePosition) { mBulletBody->applyImpulse(Convert(impulse),Convert(relativePosition)); } void BulletRigidBody::ClearForces() { mBulletBody->clearForces(); } Vector3 BulletRigidBody::GetCentreOfMass() const { return Convert(mBulletBody->getCenterOfMassPosition()); } Vector3 BulletRigidBody::GetLinearVelocity() const { return Convert(mBulletBody->getLinearVelocity()); } Vector3 BulletRigidBody::GetAngularVelocity() const { return Convert(mBulletBody->getAngularVelocity()); } void BulletRigidBody::SetLinearVelocity(const Vector3& linearVelocity) { mBulletBody->setLinearVelocity(Convert(linearVelocity)); } void BulletRigidBody::SetAngularVelocity(const Vector3& angularVelocity) { mBulletBody->setLinearVelocity(Convert(angularVelocity)); } Vector3 BulletRigidBody::GetVelocityInLocalPoint(const Vector3& relativePosition) const { return Convert(mBulletBody->getVelocityInLocalPoint(Convert(relativePosition))); } AxisAlignedBox BulletRigidBody::GetAxisAlignedBox() const { btVector3 aabbMin; btVector3 aabbMax; mBulletBody->getAabb(aabbMin,aabbMax); return AxisAlignedBox(Convert(aabbMin),Convert(aabbMax)); } void BulletRigidBody::SetDeactivationEnabled(bool deactivationEnabled) { if(!deactivationEnabled) { mBulletBody->forceActivationState(DISABLE_DEACTIVATION); }else { if(mBulletBody->getActivationState() & DISABLE_DEACTIVATION) { mBulletBody->forceActivationState(mBulletBody->getActivationState()^DISABLE_DEACTIVATION); } } } bool BulletRigidBody::IsStaticObject() const { return (mBulletBody->getCollisionFlags()&btCollisionObject::CF_STATIC_OBJECT); } }