From 9a7767867bfd93f28c2de7365dac799fccd783b4 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 14 Oct 2016 17:07:13 +0200 Subject: [PATCH] Push the current work on the Physics2D module --- build/scripts/modules/physics2d.lua | 6 + include/Nazara/Physics2D/Collider2D.hpp | 105 ++++++++ include/Nazara/Physics2D/Collider2D.inl | 35 +++ include/Nazara/Physics2D/Config.hpp | 51 ++++ include/Nazara/Physics2D/ConfigCheck.hpp | 18 ++ include/Nazara/Physics2D/Debug.hpp | 8 + include/Nazara/Physics2D/DebugOff.hpp | 9 + include/Nazara/Physics2D/Enums.hpp | 24 ++ include/Nazara/Physics2D/PhysWorld2D.hpp | 46 ++++ include/Nazara/Physics2D/Physics2D.hpp | 33 +++ include/Nazara/Physics2D/RigidBody2D.hpp | 76 ++++++ src/Nazara/Physics2D/Collider2D.cpp | 56 +++++ src/Nazara/Physics2D/Debug/NewOverload.cpp | 31 +++ src/Nazara/Physics2D/PhysWorld2D.cpp | 60 +++++ src/Nazara/Physics2D/Physics2D.cpp | 59 +++++ src/Nazara/Physics2D/RigidBody2D.cpp | 266 +++++++++++++++++++++ 16 files changed, 883 insertions(+) create mode 100644 build/scripts/modules/physics2d.lua create mode 100644 include/Nazara/Physics2D/Collider2D.hpp create mode 100644 include/Nazara/Physics2D/Collider2D.inl create mode 100644 include/Nazara/Physics2D/Config.hpp create mode 100644 include/Nazara/Physics2D/ConfigCheck.hpp create mode 100644 include/Nazara/Physics2D/Debug.hpp create mode 100644 include/Nazara/Physics2D/DebugOff.hpp create mode 100644 include/Nazara/Physics2D/Enums.hpp create mode 100644 include/Nazara/Physics2D/PhysWorld2D.hpp create mode 100644 include/Nazara/Physics2D/Physics2D.hpp create mode 100644 include/Nazara/Physics2D/RigidBody2D.hpp create mode 100644 src/Nazara/Physics2D/Collider2D.cpp create mode 100644 src/Nazara/Physics2D/Debug/NewOverload.cpp create mode 100644 src/Nazara/Physics2D/PhysWorld2D.cpp create mode 100644 src/Nazara/Physics2D/Physics2D.cpp create mode 100644 src/Nazara/Physics2D/RigidBody2D.cpp diff --git a/build/scripts/modules/physics2d.lua b/build/scripts/modules/physics2d.lua new file mode 100644 index 000000000..a7514b8cd --- /dev/null +++ b/build/scripts/modules/physics2d.lua @@ -0,0 +1,6 @@ +MODULE.Name = "Physics2D" + +MODULE.Libraries = { + "NazaraCore", + "chipmunk-s" +} diff --git a/include/Nazara/Physics2D/Collider2D.hpp b/include/Nazara/Physics2D/Collider2D.hpp new file mode 100644 index 000000000..c1cb096b0 --- /dev/null +++ b/include/Nazara/Physics2D/Collider2D.hpp @@ -0,0 +1,105 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 2D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_COLLIDER2D_HPP +#define NAZARA_COLLIDER2D_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +struct cpShape; +struct cpSpace; + +namespace Nz +{ + class Collider2D; + class RigidBody2D; + + using Collider2DConstRef = ObjectRef; + using Collider2DLibrary = ObjectLibrary; + using Collider2DRef = ObjectRef; + + class NAZARA_PHYSICS2D_API Collider2D : public RefCounted + { + friend Collider2DLibrary; + friend RigidBody2D; + + public: + Collider2D() = default; + Collider2D(const Collider2D&) = delete; + Collider2D(Collider2D&&) = delete; + virtual ~Collider2D(); + + virtual float ComputeInertialMatrix(float mass) const = 0; + + virtual ColliderType2D GetType() const = 0; + + Collider2D& operator=(const Collider2D&) = delete; + Collider2D& operator=(Collider2D&&) = delete; + + // Signals: + NazaraSignal(OnColliderRelease, const Collider2D* /*collider*/); + + protected: + virtual std::vector CreateShapes(RigidBody2D* body) const = 0; + + static Collider2DLibrary::LibraryMap s_library; + }; + + class CircleCollider2D; + + using CircleCollider2DConstRef = ObjectRef; + using CircleCollider2DRef = ObjectRef; + + class NAZARA_PHYSICS2D_API CircleCollider2D : public Collider2D + { + public: + CircleCollider2D(float radius, const Vector2f& offset = Vector2f::Zero()); + + float ComputeInertialMatrix(float mass) const override; + + inline float GetRadius() const; + ColliderType2D GetType() const override; + + template static CircleCollider2DRef New(Args&&... args); + + private: + std::vector CreateShapes(RigidBody2D* body) const override; + + Vector2f m_offset; + float m_radius; + }; + + class NullCollider2D; + + using NullCollider2DConstRef = ObjectRef; + using NullCollider2DRef = ObjectRef; + + class NAZARA_PHYSICS2D_API NullCollider2D : public Collider2D + { + public: + NullCollider2D() = default; + + float ComputeInertialMatrix(float mass) const override; + + ColliderType2D GetType() const override; + + template static NullCollider2DRef New(Args&&... args); + + private: + std::vector CreateShapes(RigidBody2D* body) const override; + }; +} + +#include + +#endif // NAZARA_COLLIDER2D_HPP diff --git a/include/Nazara/Physics2D/Collider2D.inl b/include/Nazara/Physics2D/Collider2D.inl new file mode 100644 index 000000000..c5503fdf2 --- /dev/null +++ b/include/Nazara/Physics2D/Collider2D.inl @@ -0,0 +1,35 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline float CircleCollider2D::GetRadius() const + { + return m_radius; + } + + template + CircleCollider2DRef CircleCollider2D::New(Args&&... args) + { + std::unique_ptr object(new CircleCollider2D(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); + } + + template + NullCollider2DRef NullCollider2D::New(Args&&... args) + { + std::unique_ptr object(new NullCollider2D(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); + } + +} + +#include diff --git a/include/Nazara/Physics2D/Config.hpp b/include/Nazara/Physics2D/Config.hpp new file mode 100644 index 000000000..59951806e --- /dev/null +++ b/include/Nazara/Physics2D/Config.hpp @@ -0,0 +1,51 @@ +/* + Nazara Engine - Physics 3D module + + Copyright (C) 2015 Jérôme "Lynix" Leclercq (Lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_CONFIG_PHYSICS2D_HPP +#define NAZARA_CONFIG_PHYSICS2D_HPP + +/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci + +// Utilise un manager de mémoire pour gérer les allocations dynamiques (détecte les leaks au prix d'allocations/libérations dynamiques plus lentes) +#define NAZARA_PHYSICS2D_MANAGE_MEMORY 0 + +// Active les tests de sécurité basés sur le code (Conseillé pour le développement) +#define NAZARA_PHYSICS2D_SAFE 1 + +/// Vérification des valeurs et types de certaines constantes +#include + +#if defined(NAZARA_STATIC) + #define NAZARA_PHYSICS2D_API +#else + #ifdef NAZARA_PHYSICS2D_BUILD + #define NAZARA_PHYSICS2D_API NAZARA_EXPORT + #else + #define NAZARA_PHYSICS2D_API NAZARA_IMPORT + #endif +#endif + +#endif // NAZARA_CONFIG_PHYSICS3D_HPP diff --git a/include/Nazara/Physics2D/ConfigCheck.hpp b/include/Nazara/Physics2D/ConfigCheck.hpp new file mode 100644 index 000000000..6b1c82073 --- /dev/null +++ b/include/Nazara/Physics2D/ConfigCheck.hpp @@ -0,0 +1,18 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_CONFIG_CHECK_PHYSICS_HPP +#define NAZARA_CONFIG_CHECK_PHYSICS_HPP + +/// Ce fichier sert à vérifier la valeur des constantes du fichier Config.hpp + +// On force la valeur de MANAGE_MEMORY en mode debug +#if defined(NAZARA_DEBUG) && !NAZARA_PHYSICS_MANAGE_MEMORY + #undef NAZARA_PHYSICS_MANAGE_MEMORY + #define NAZARA_PHYSICS3D_MANAGE_MEMORY 0 +#endif + +#endif // NAZARA_CONFIG_CHECK_PHYSICS_HPP diff --git a/include/Nazara/Physics2D/Debug.hpp b/include/Nazara/Physics2D/Debug.hpp new file mode 100644 index 000000000..f70a8b570 --- /dev/null +++ b/include/Nazara/Physics2D/Debug.hpp @@ -0,0 +1,8 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#if NAZARA_PHYSICS_MANAGE_MEMORY + #include +#endif diff --git a/include/Nazara/Physics2D/DebugOff.hpp b/include/Nazara/Physics2D/DebugOff.hpp new file mode 100644 index 000000000..595f0ad94 --- /dev/null +++ b/include/Nazara/Physics2D/DebugOff.hpp @@ -0,0 +1,9 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +// On suppose que Debug.hpp a déjà été inclus, tout comme Config.hpp +#if NAZARA_PHYSICS_MANAGE_MEMORY + #undef delete + #undef new +#endif diff --git a/include/Nazara/Physics2D/Enums.hpp b/include/Nazara/Physics2D/Enums.hpp new file mode 100644 index 000000000..529af6f6c --- /dev/null +++ b/include/Nazara/Physics2D/Enums.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 2D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENUMS_PHYSICS2D_HPP +#define NAZARA_ENUMS_PHYSICS2D_HPP + +namespace Nz +{ + enum ColliderType2D + { + ColliderType2D_Box, + ColliderType2D_Convex, + ColliderType2D_Circle, + ColliderType2D_Null, + ColliderType2D_Segment, + + ColliderType2D_Max = ColliderType2D_Segment + }; +} + +#endif // NAZARA_ENUMS_PHYSICS2D_HPP diff --git a/include/Nazara/Physics2D/PhysWorld2D.hpp b/include/Nazara/Physics2D/PhysWorld2D.hpp new file mode 100644 index 000000000..e2705187c --- /dev/null +++ b/include/Nazara/Physics2D/PhysWorld2D.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_PHYSWORLD2D_HPP +#define NAZARA_PHYSWORLD2D_HPP + +#include +#include +#include + +struct cpSpace; + +namespace Nz +{ + class NAZARA_PHYSICS2D_API PhysWorld2D + { + public: + PhysWorld2D(); + PhysWorld2D(const PhysWorld2D&) = delete; + PhysWorld2D(PhysWorld2D&&) = delete; ///TODO + ~PhysWorld2D(); + + Vector2f GetGravity() const; + cpSpace* GetHandle() const; + float GetStepSize() const; + + void SetGravity(const Vector2f& gravity); + void SetSolverModel(unsigned int model); + void SetStepSize(float stepSize); + + void Step(float timestep); + + PhysWorld2D& operator=(const PhysWorld2D&) = delete; + PhysWorld2D& operator=(PhysWorld2D&&) = delete; ///TODO + + private: + cpSpace* m_handle; + float m_stepSize; + float m_timestepAccumulator; + }; +} + +#endif // NAZARA_PHYSWORLD2D_HPP diff --git a/include/Nazara/Physics2D/Physics2D.hpp b/include/Nazara/Physics2D/Physics2D.hpp new file mode 100644 index 000000000..4789d4f50 --- /dev/null +++ b/include/Nazara/Physics2D/Physics2D.hpp @@ -0,0 +1,33 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_PHYSICS2D_HPP +#define NAZARA_PHYSICS2D_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_PHYSICS2D_API Physics2D + { + public: + Physics2D() = delete; + ~Physics2D() = delete; + + static bool Initialize(); + + static bool IsInitialized(); + + static void Uninitialize(); + + private: + static unsigned int s_moduleReferenceCounter; + }; +} + +#endif // NAZARA_PHYSICS2D_HPP diff --git a/include/Nazara/Physics2D/RigidBody2D.hpp b/include/Nazara/Physics2D/RigidBody2D.hpp new file mode 100644 index 000000000..760112674 --- /dev/null +++ b/include/Nazara/Physics2D/RigidBody2D.hpp @@ -0,0 +1,76 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_RIGIDBODY2D_HPP +#define NAZARA_RIGIDBODY2D_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +struct cpBody; + +namespace Nz +{ + class PhysWorld2D; + + class NAZARA_PHYSICS2D_API RigidBody2D + { + public: + RigidBody2D(PhysWorld2D* world, float mass); + RigidBody2D(PhysWorld2D* world, float mass, Collider2DRef geom); + RigidBody2D(const RigidBody2D& object); + RigidBody2D(RigidBody2D&& object); + ~RigidBody2D(); + + void AddForce(const Vector2f& force, CoordSys coordSys = CoordSys_Global); + void AddForce(const Vector2f& force, const Vector2f& point, CoordSys coordSys = CoordSys_Global); + void AddTorque(float torque); + + Rectf GetAABB() const; + float GetAngularVelocity() const; + Vector2f GetCenterOfGravity(CoordSys coordSys = CoordSys_Local) const; + const Collider2DRef& GetGeom() const; + float GetGravityFactor() const; + cpBody* GetHandle() const; + float GetMass() const; + Vector2f GetPosition() const; + float GetRotation() const; + Vector2f GetVelocity() const; + + bool IsMoveable() const; + bool IsSleeping() const; + + void SetAngularVelocity(float angularVelocity); + void SetGeom(Collider2DRef geom); + void SetGravityFactor(float gravityFactor); + void SetMass(float mass); + void SetMassCenter(const Vector2f& center); + void SetPosition(const Vector2f& position); + void SetRotation(float rotation); + void SetVelocity(const Vector2f& velocity); + + RigidBody2D& operator=(const RigidBody2D& object); + RigidBody2D& operator=(RigidBody2D&& object); + + private: + std::vector m_shapes; + Collider2DRef m_geom; + Vector3f m_forceAccumulator; + Vector3f m_torqueAccumulator; + cpBody* m_handle; + PhysWorld2D* m_world; + float m_gravityFactor; + float m_mass; + }; +} + +#endif // NAZARA_RIGIDBODY3D_HPP diff --git a/src/Nazara/Physics2D/Collider2D.cpp b/src/Nazara/Physics2D/Collider2D.cpp new file mode 100644 index 000000000..265c939bf --- /dev/null +++ b/src/Nazara/Physics2D/Collider2D.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + Collider2D::~Collider2D() = default; + + /******************************** CircleCollider2D *********************************/ + + CircleCollider2D::CircleCollider2D(float radius, const Vector2f& offset) : + m_offset(offset), + m_radius(radius) + { + } + + float CircleCollider2D::ComputeInertialMatrix(float mass) const + { + return cpMomentForCircle(mass, 0.f, m_radius, cpv(m_offset.x, m_offset.y)); + } + + ColliderType2D CircleCollider2D::GetType() const + { + return ColliderType2D_Circle; + } + + std::vector CircleCollider2D::CreateShapes(RigidBody2D* body) const + { + std::vector shapes; + shapes.push_back(cpCircleShapeNew(body->GetHandle(), m_radius, cpv(m_offset.x, m_offset.y))); + + return shapes; + } + + /********************************* NullCollider2D **********************************/ + + ColliderType2D NullCollider2D::GetType() const + { + return ColliderType2D_Null; + } + + float NullCollider2D::ComputeInertialMatrix(float mass) const + { + return 0.f; + } + + std::vector NullCollider2D::CreateShapes(RigidBody2D* body) const + { + return std::vector(); + } +} diff --git a/src/Nazara/Physics2D/Debug/NewOverload.cpp b/src/Nazara/Physics2D/Debug/NewOverload.cpp new file mode 100644 index 000000000..18092514c --- /dev/null +++ b/src/Nazara/Physics2D/Debug/NewOverload.cpp @@ -0,0 +1,31 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#if NAZARA_PHYSICS_MANAGE_MEMORY + +#include +#include // Nécessaire ? + +void* operator new(std::size_t size) +{ + return Nz::MemoryManager::Allocate(size, false); +} + +void* operator new[](std::size_t size) +{ + return Nz::MemoryManager::Allocate(size, true); +} + +void operator delete(void* pointer) noexcept +{ + Nz::MemoryManager::Free(pointer, false); +} + +void operator delete[](void* pointer) noexcept +{ + Nz::MemoryManager::Free(pointer, true); +} + +#endif // NAZARA_PHYSICS_MANAGE_MEMORY diff --git a/src/Nazara/Physics2D/PhysWorld2D.cpp b/src/Nazara/Physics2D/PhysWorld2D.cpp new file mode 100644 index 000000000..b133fa03e --- /dev/null +++ b/src/Nazara/Physics2D/PhysWorld2D.cpp @@ -0,0 +1,60 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + PhysWorld2D::PhysWorld2D() : + m_stepSize(0.005f), + m_timestepAccumulator(0.f) + { + m_handle = cpSpaceNew(); + cpSpaceSetUserData(m_handle, this); + } + + PhysWorld2D::~PhysWorld2D() + { + cpSpaceFree(m_handle); + } + + Vector2f PhysWorld2D::GetGravity() const + { + cpVect gravity = cpSpaceGetGravity(m_handle); + return Vector2f(gravity.x, gravity.y); + } + + cpSpace* PhysWorld2D::GetHandle() const + { + return m_handle; + } + + float PhysWorld2D::GetStepSize() const + { + return m_stepSize; + } + + void PhysWorld2D::SetGravity(const Vector2f& gravity) + { + cpSpaceSetGravity(m_handle, cpv(gravity.x, gravity.y)); + } + + void PhysWorld2D::SetStepSize(float stepSize) + { + m_stepSize = stepSize; + } + + void PhysWorld2D::Step(float timestep) + { + m_timestepAccumulator += timestep; + + while (m_timestepAccumulator >= m_stepSize) + { + cpSpaceStep(m_handle, m_stepSize); + m_timestepAccumulator -= m_stepSize; + } + } +} diff --git a/src/Nazara/Physics2D/Physics2D.cpp b/src/Nazara/Physics2D/Physics2D.cpp new file mode 100644 index 000000000..3b380a71f --- /dev/null +++ b/src/Nazara/Physics2D/Physics2D.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + bool Physics2D::Initialize() + { + if (s_moduleReferenceCounter > 0) + { + s_moduleReferenceCounter++; + return true; // Déjà initialisé + } + + // Initialisation des dépendances + if (!Core::Initialize()) + { + NazaraError("Failed to initialize core module"); + return false; + } + + s_moduleReferenceCounter++; + + NazaraNotice("Initialized: Physics2D module"); + return true; + } + + bool Physics2D::IsInitialized() + { + return s_moduleReferenceCounter != 0; + } + + void Physics2D::Uninitialize() + { + if (s_moduleReferenceCounter != 1) + { + // Le module est soit encore utilisé, soit pas initialisé + if (s_moduleReferenceCounter > 1) + s_moduleReferenceCounter--; + + return; + } + + // Libération du module + s_moduleReferenceCounter = 0; + + NazaraNotice("Uninitialized: Physics2D module"); + + // Libération des dépendances + Core::Uninitialize(); + } + + unsigned int Physics2D::s_moduleReferenceCounter = 0; +} diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp new file mode 100644 index 000000000..6406d0b8c --- /dev/null +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -0,0 +1,266 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Physics 3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + RigidBody2D::RigidBody2D(PhysWorld2D* world, float mass) : + RigidBody2D(world, mass, nullptr) + { + } + + RigidBody2D::RigidBody2D(PhysWorld2D* world, float mass, Collider2DRef geom) : + m_geom(), + m_forceAccumulator(Vector3f::Zero()), + m_torqueAccumulator(Vector3f::Zero()), + m_world(world), + m_gravityFactor(1.f), + m_mass(0.f) + { + NazaraAssert(m_world, "Invalid world"); + + m_handle = cpBodyNew(0.f, 0.f); + cpBodySetUserData(m_handle, this); + cpSpaceAddBody(m_world->GetHandle(), m_handle); + + SetGeom(geom); + SetMass(mass); + } + + RigidBody2D::RigidBody2D(const RigidBody2D& object) : + m_geom(object.m_geom), + m_forceAccumulator(Vector3f::Zero()), + m_torqueAccumulator(Vector3f::Zero()), + m_world(object.m_world), + m_gravityFactor(object.m_gravityFactor), + m_mass(0.f) + { + NazaraAssert(m_world, "Invalid world"); + NazaraAssert(m_geom, "Invalid geometry"); + + m_handle = cpBodyNew(0.f, 0.f); + cpBodySetUserData(m_handle, this); + cpSpaceAddBody(m_world->GetHandle(), m_handle); + + SetGeom(object.GetGeom()); + SetMass(object.GetMass()); + } + + RigidBody2D::RigidBody2D(RigidBody2D&& object) : + m_geom(std::move(object.m_geom)), + m_forceAccumulator(std::move(object.m_forceAccumulator)), + m_torqueAccumulator(std::move(object.m_torqueAccumulator)), + m_handle(object.m_handle), + m_world(object.m_world), + m_gravityFactor(object.m_gravityFactor), + m_mass(object.m_mass) + { + object.m_handle = nullptr; + } + + RigidBody2D::~RigidBody2D() + { + if (m_handle) + cpBodyFree(m_handle); + } + + void RigidBody2D::AddForce(const Vector2f& force, CoordSys coordSys) + { + return AddForce(force, GetCenterOfGravity(coordSys), coordSys); + } + + void RigidBody2D::AddForce(const Vector2f& force, const Vector2f& point, CoordSys coordSys) + { + switch (coordSys) + { + case CoordSys_Global: + cpBodyApplyForceAtWorldPoint(m_handle, cpv(force.x, force.y), cpv(force.x, force.y)); + break; + + case CoordSys_Local: + cpBodyApplyForceAtLocalPoint(m_handle, cpv(force.x, force.y), cpv(point.x, point.y)); + break; + } + } + + void RigidBody2D::AddTorque(float torque) + { + cpBodySetTorque(m_handle, cpBodyGetTorque(m_handle) + torque); + } + + Rectf RigidBody2D::GetAABB() const + { + cpBB bb = cpBBNew(0.f, 0.f, 0.f, 0.f); + for (cpShape* shape : m_shapes) + bb = cpBBMerge(bb, cpShapeGetBB(shape)); + + return Rectf(bb.l, bb.t, bb.r - bb.l, bb.b - bb.t); + } + + float RigidBody2D::GetAngularVelocity() const + { + return cpBodyGetAngularVelocity(m_handle); + } + + const Collider2DRef& RigidBody2D::GetGeom() const + { + return m_geom; + } + + float RigidBody2D::GetGravityFactor() const + { + return m_gravityFactor; + } + + cpBody* RigidBody2D::GetHandle() const + { + return m_handle; + } + + float RigidBody2D::GetMass() const + { + return m_mass; + } + + Vector2f RigidBody2D::GetCenterOfGravity(CoordSys coordSys) const + { + cpVect cog = cpBodyGetCenterOfGravity(m_handle); + + switch (coordSys) + { + case CoordSys_Global: + cog = cpBodyLocalToWorld(m_handle, cog); + break; + + case CoordSys_Local: + break; // Nothing to do + } + + return Vector2f(cog.x, cog.y); + } + + Vector2f RigidBody2D::GetPosition() const + { + cpVect pos = cpBodyGetPosition(m_handle); + return Vector2f(pos.x, pos.y); + } + + float RigidBody2D::GetRotation() const + { + return cpBodyGetAngle(m_handle); + } + + Vector2f RigidBody2D::GetVelocity() const + { + cpVect vel = cpBodyGetVelocity(m_handle); + return Vector2f(vel.x, vel.y); + } + + bool RigidBody2D::IsMoveable() const + { + return m_mass > 0.f; + } + + bool RigidBody2D::IsSleeping() const + { + return cpBodyIsSleeping(m_handle) != 0; + } + + void RigidBody2D::SetAngularVelocity(float angularVelocity) + { + cpBodySetAngularVelocity(m_handle, angularVelocity); + } + + void RigidBody2D::SetGeom(Collider2DRef geom) + { + if (m_geom.Get() != geom) + { + for (cpShape* shape : m_shapes) + cpBodyRemoveShape(m_handle, shape); + + if (geom) + m_geom = geom; + else + m_geom = NullCollider2D::New(); + + m_shapes = m_geom->CreateShapes(this); + } + } + + void RigidBody2D::SetGravityFactor(float gravityFactor) + { + m_gravityFactor = gravityFactor; + } + + void RigidBody2D::SetMass(float mass) + { + if (m_mass > 0.f) + { + if (mass > 0.f) + cpBodySetMass(m_handle, mass); + else + cpBodySetType(m_handle, CP_BODY_TYPE_STATIC); + } + else if (mass > 0.f) + { + if (cpBodyGetType(m_handle) == CP_BODY_TYPE_STATIC) + cpBodySetType(m_handle, CP_BODY_TYPE_DYNAMIC); + } + + m_mass = mass; + } + + void RigidBody2D::SetMassCenter(const Vector2f& center) + { + if (m_mass > 0.f) + cpBodySetCenterOfGravity(m_handle, cpv(center.x, center.y)); + } + + void RigidBody2D::SetPosition(const Vector2f& position) + { + cpBodySetPosition(m_handle, cpv(position.x, position.y)); + } + + void RigidBody2D::SetRotation(float rotation) + { + cpBodySetAngle(m_handle, rotation); + } + + void RigidBody2D::SetVelocity(const Vector2f& velocity) + { + cpBodySetVelocity(m_handle, cpv(velocity.x, velocity.y)); + } + + RigidBody2D& RigidBody2D::operator=(const RigidBody2D& object) + { + RigidBody2D physObj(object); + return operator=(std::move(physObj)); + } + + RigidBody2D& RigidBody2D::operator=(RigidBody2D&& object) + { + if (m_handle) + cpBodyFree(m_handle); + + m_handle = object.m_handle; + m_forceAccumulator = std::move(object.m_forceAccumulator); + m_geom = std::move(object.m_geom); + m_gravityFactor = object.m_gravityFactor; + m_mass = object.m_mass; + m_torqueAccumulator = std::move(object.m_torqueAccumulator); + m_world = object.m_world; + + object.m_handle = nullptr; + + return *this; + } +}