1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ 2 3 #ifndef COLLISION_HANDLER_H 4 #define COLLISION_HANDLER_H 5 6 #include "System/creg/creg_cond.h" 7 #include "System/float3.h" 8 9 struct CollisionVolume; 10 class CMatrix44f; 11 class CSolidObject; 12 class CUnit; 13 struct LocalModelPiece; 14 15 enum { 16 CQ_POINT_NO_INT = 0, 17 CQ_POINT_ON_RAY = 1, 18 CQ_POINT_IN_VOL = 2, 19 }; 20 21 struct CollisionQuery { 22 public: CollisionQueryCollisionQuery23 CollisionQuery( ): lmp(NULL) { Reset(NULL); } CollisionQueryCollisionQuery24 CollisionQuery(const CollisionQuery& cq): lmp(NULL) { Reset( &cq); } 25 26 void Reset(const CollisionQuery* cq = NULL) { 27 // (0, 0, 0) is volume-space center, so impossible 28 // to obtain as actual points except in the special 29 // cases (which all calling code should check for!) 30 // when continuous hit-detection is enabled 31 if (cq == NULL) { 32 b0 = CQ_POINT_NO_INT; t0 = 0.0f; p0 = ZeroVector; 33 b1 = CQ_POINT_NO_INT; t1 = 0.0f; p1 = ZeroVector; 34 } else { 35 b0 = cq->b0; t0 = cq->t0; p0 = cq->p0; 36 b1 = cq->b1; t1 = cq->t1; p1 = cq->p1; 37 38 lmp = cq->lmp; 39 } 40 } 41 InsideHitCollisionQuery42 bool InsideHit() const { return (b0 == CQ_POINT_IN_VOL); } IngressHitCollisionQuery43 bool IngressHit() const { return (b0 == CQ_POINT_ON_RAY); } EgressHitCollisionQuery44 bool EgressHit() const { return (b1 == CQ_POINT_ON_RAY); } 45 GetIngressPosCollisionQuery46 const float3& GetIngressPos() const { return p0; } GetEgressPosCollisionQuery47 const float3& GetEgressPos() const { return p1; } GetHitPosCollisionQuery48 const float3& GetHitPos() const { 49 if (IngressHit()) return (GetIngressPos()); 50 if (EgressHit()) return (GetEgressPos()); 51 return ZeroVector; 52 } 53 54 // if the hit-position equals ZeroVector (i.e. if we have an 55 // inside-hit special case), the projected distance could be 56 // positive or negative depending on <dir> but we want it to 57 // be 0 --> turn <pos> into a ZeroVector if InsideHit() GetHitPosDistCollisionQuery58 float GetHitPosDist(const float3& pos, const float3& dir) const { return (std::max(0.0f, ((GetHitPos() - pos * (1 - InsideHit())).dot(dir)))); } GetIngressPosDistCollisionQuery59 float GetIngressPosDist(const float3& pos, const float3& dir) const { return (std::max(0.0f, ((GetIngressPos() - pos).dot(dir)))); } GetEgressPosDistCollisionQuery60 float GetEgressPosDist(const float3& pos, const float3& dir) const { return (std::max(0.0f, ((GetEgressPos() - pos).dot(dir)))); } 61 GetHitPieceCollisionQuery62 LocalModelPiece* GetHitPiece() const { return lmp; } SetHitPieceCollisionQuery63 void SetHitPiece(LocalModelPiece* p) { lmp = p; } 64 65 private: 66 friend class CCollisionHandler; 67 68 int b0, b1; ///< true (non-zero) if ingress (b0) or egress (b1) point on ray segment 69 float t0, t1; ///< distance parameter for ingress and egress point 70 float3 p0, p1; ///< ray-volume ingress and egress points 71 72 LocalModelPiece* lmp; ///< impacted piece 73 }; 74 75 /** 76 * Responsible for detecting hits between projectiles 77 * and solid objects (units, features), each SO has a 78 * collision volume. 79 */ 80 class CCollisionHandler { 81 public: 82 static void PrintStats(); 83 84 static bool DetectHit(const CSolidObject* o, const float3 p0, const float3 p1, CollisionQuery* cq = NULL, bool forceTrace = false); 85 static bool DetectHit(const CollisionVolume* v, const CSolidObject* o, const float3 p0, const float3 p1, CollisionQuery* cq, bool forceTrace = false); 86 static bool MouseHit(const CUnit* u, const float3& p0, const float3& p1, const CollisionVolume* v, CollisionQuery* cq); 87 88 private: 89 // HITTEST_DISC helpers for DetectHit 90 static bool Collision(const CollisionVolume* v, const CSolidObject* u, const float3 p, CollisionQuery* cq); 91 // HITTEST_CONT helpers for DetectHit 92 static bool Intersect(const CollisionVolume* v, const CSolidObject* o, const float3 p0, const float3 p1, CollisionQuery* cq); 93 94 private: 95 /** 96 * Test if a point lies inside a volume. 97 * @param v volume 98 * @param m volumes transformation matrix 99 * @param p point in world-coordinates 100 */ 101 static bool Collision(const CollisionVolume* v, const CMatrix44f& m, const float3& p); 102 static bool CollisionFootPrint(const CSolidObject* o, const float3& p); 103 104 /** 105 * Test if a ray intersects a volume. 106 * @param v volume 107 * @param m volumes transformation matrix 108 * @param p0 start of ray (in world-coordinates) 109 * @param p1 end of ray (in world-coordinates) 110 */ 111 static bool Intersect(const CollisionVolume* v, const CMatrix44f& m, const float3& p0, const float3& p1, CollisionQuery* cq); 112 static bool IntersectPieceTree(const CUnit* u, const float3& p0, const float3& p1, CollisionQuery* cq); 113 114 static bool IntersectPiecesHelper(const CUnit* u, const float3& p0, const float3& p1, CollisionQuery* cqp); 115 116 public: 117 static bool IntersectEllipsoid(const CollisionVolume* v, const float3& pi0, const float3& pi1, CollisionQuery* cq); 118 static bool IntersectCylinder(const CollisionVolume* v, const float3& pi0, const float3& pi1, CollisionQuery* cq); 119 static bool IntersectBox(const CollisionVolume* v, const float3& pi0, const float3& pi1, CollisionQuery* cq); 120 121 private: 122 static unsigned int numDiscTests; // number of discrete hit-tests executed 123 static unsigned int numContTests; // number of continuous hit-tests executed (inc. unsynced) 124 }; 125 126 #endif // COLLISION_HANDLER_H 127