// Copyright (C) 2017 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_PHYSWORLD2D_HPP #define NAZARA_PHYSWORLD2D_HPP #include #include #include #include #include #include #include #include #include struct cpCollisionHandler; struct cpSpace; namespace Nz { class Arbiter2D; class NAZARA_PHYSICS2D_API PhysWorld2D { friend RigidBody2D; using ContactEndCallback = std::function; using ContactPreSolveCallback = std::function; using ContactPostSolveCallback = std::function; using ContactStartCallback = std::function; using DebugDrawCircleCallback = std::function; using DebugDrawDotCallback = std::function; using DebugDrawPolygonCallback = std::function; using DebugDrawSegmentCallback = std::function; using DebugDrawTickSegmentCallback = std::function; using DebugDrawGetColorCallback = std::function; public: struct Callback; struct DebugDrawOptions; struct NearestQueryResult; struct RaycastHit; PhysWorld2D(); PhysWorld2D(const PhysWorld2D&) = delete; PhysWorld2D(PhysWorld2D&&) = delete; ///TODO ~PhysWorld2D(); void DebugDraw(const DebugDrawOptions& options, bool drawShapes = true, bool drawConstraints = true, bool drawCollisions = true); float GetDamping() const; Vector2f GetGravity() const; cpSpace* GetHandle() const; std::size_t GetIterationCount() const; std::size_t GetMaxStepCount() const; float GetStepSize() const; bool NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RigidBody2D** nearestBody = nullptr); bool NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result); bool RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* hitInfos); bool RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo = nullptr); void RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* bodies); void RegisterCallbacks(unsigned int collisionId, const Callback& callbacks); void RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, const Callback& callbacks); void SetDamping(float dampingValue); void SetGravity(const Vector2f& gravity); void SetIterationCount(std::size_t iterationCount); void SetMaxStepCount(std::size_t maxStepCount); void SetStepSize(float stepSize); void Step(float timestep); void UseSpatialHash(float cellSize, std::size_t entityCount); PhysWorld2D& operator=(const PhysWorld2D&) = delete; PhysWorld2D& operator=(PhysWorld2D&&) = delete; ///TODO struct Callback { ContactEndCallback endCallback = nullptr; ContactPreSolveCallback preSolveCallback = nullptr; ContactPostSolveCallback postSolveCallback = nullptr; ContactStartCallback startCallback = nullptr; void* userdata; }; struct DebugDrawOptions { Color constraintColor; Color collisionPointColor; Color shapeOutlineColor; DebugDrawCircleCallback circleCallback; DebugDrawGetColorCallback colorCallback; DebugDrawDotCallback dotCallback; DebugDrawPolygonCallback polygonCallback; DebugDrawSegmentCallback segmentCallback; DebugDrawTickSegmentCallback thickSegmentCallback; void* userdata; }; struct NearestQueryResult { Nz::RigidBody2D* nearestBody; Nz::Vector2f closestPoint; Nz::Vector2f fraction; float distance; }; struct RaycastHit { Nz::RigidBody2D* nearestBody; Nz::Vector2f hitPos; Nz::Vector2f hitNormal; float fraction; }; NazaraSignal(OnPhysWorld2DPreStep, const PhysWorld2D* /*physWorld*/, float /*invStepCount*/); NazaraSignal(OnPhysWorld2DPostStep, const PhysWorld2D* /*physWorld*/, float /*invStepCount*/); private: void InitCallbacks(cpCollisionHandler* handler, const Callback& callbacks); using PostStep = std::function; void OnRigidBodyMoved(RigidBody2D* oldPointer, RigidBody2D* newPointer); void OnRigidBodyRelease(RigidBody2D* rigidBody); void RegisterPostStep(RigidBody2D* rigidBody, PostStep&& func); struct PostStepContainer { NazaraSlot(RigidBody2D, OnRigidBody2DMove, onMovedSlot); NazaraSlot(RigidBody2D, OnRigidBody2DRelease, onReleaseSlot); std::vector funcs; }; static_assert(std::is_nothrow_move_constructible::value, "PostStepContainer should be noexcept MoveConstructible"); std::size_t m_maxStepCount; std::unordered_map> m_callbacks; std::unordered_map m_rigidPostSteps; cpSpace* m_handle; float m_stepSize; float m_timestepAccumulator; }; } #endif // NAZARA_PHYSWORLD2D_HPP