File: CollisionHandler.h

package info (click to toggle)
spring 98.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 41,928 kB
  • ctags: 60,665
  • sloc: cpp: 356,167; ansic: 39,434; python: 12,228; java: 12,203; awk: 5,856; sh: 1,719; xml: 997; perl: 405; php: 253; objc: 194; makefile: 72; sed: 2
file content (126 lines) | stat: -rw-r--r-- 4,990 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */

#ifndef COLLISION_HANDLER_H
#define COLLISION_HANDLER_H

#include "System/creg/creg_cond.h"
#include "System/float3.h"

struct CollisionVolume;
class CMatrix44f;
class CSolidObject;
class CUnit;
struct LocalModelPiece;

enum {
	CQ_POINT_NO_INT = 0,
	CQ_POINT_ON_RAY = 1,
	CQ_POINT_IN_VOL = 2,
};

struct CollisionQuery {
public:
	CollisionQuery(                        ): lmp(NULL) { Reset(NULL); }
	CollisionQuery(const CollisionQuery& cq): lmp(NULL) { Reset( &cq); }

	void Reset(const CollisionQuery* cq = NULL) {
		// (0, 0, 0) is volume-space center, so impossible
		// to obtain as actual points except in the special
		// cases (which all calling code should check for!)
		// when continuous hit-detection is enabled
		if (cq == NULL) {
			b0 = CQ_POINT_NO_INT; t0 = 0.0f; p0 = ZeroVector;
			b1 = CQ_POINT_NO_INT; t1 = 0.0f; p1 = ZeroVector;
		} else {
			b0 = cq->b0; t0 = cq->t0; p0 = cq->p0;
			b1 = cq->b1; t1 = cq->t1; p1 = cq->p1;

			lmp = cq->lmp;
		}
	}

	bool InsideHit() const { return (b0 == CQ_POINT_IN_VOL); }
	bool IngressHit() const { return (b0 == CQ_POINT_ON_RAY); }
	bool EgressHit() const { return (b1 == CQ_POINT_ON_RAY); }

	const float3& GetIngressPos() const { return p0; }
	const float3& GetEgressPos() const { return p1; }
	const float3& GetHitPos() const {
		if (IngressHit()) return (GetIngressPos());
		if (EgressHit()) return (GetEgressPos());
		return ZeroVector;
	}

	// if the hit-position equals ZeroVector (i.e. if we have an
	// inside-hit special case), the projected distance could be
	// positive or negative depending on <dir> but we want it to
	// be 0 --> turn <pos> into a ZeroVector if InsideHit()
	float GetHitPosDist(const float3& pos, const float3& dir) const { return (std::max(0.0f, ((GetHitPos() - pos * (1 - InsideHit())).dot(dir)))); }
	float GetIngressPosDist(const float3& pos, const float3& dir) const { return (std::max(0.0f, ((GetIngressPos() - pos).dot(dir)))); }
	float GetEgressPosDist(const float3& pos, const float3& dir) const { return (std::max(0.0f, ((GetEgressPos() - pos).dot(dir)))); }

	LocalModelPiece* GetHitPiece() const { return lmp; }
	void SetHitPiece(LocalModelPiece* p) { lmp = p; }

private:
	friend class CCollisionHandler;

	int    b0, b1;        ///< true (non-zero) if ingress (b0) or egress (b1) point on ray segment
	float  t0, t1;        ///< distance parameter for ingress and egress point
	float3 p0, p1;        ///< ray-volume ingress and egress points

	LocalModelPiece* lmp; ///< impacted piece
};

/**
 * Responsible for detecting hits between projectiles
 * and solid objects (units, features), each SO has a
 * collision volume.
 */
class CCollisionHandler {
	public:
		static void PrintStats();

		static bool DetectHit(const CSolidObject* o, const float3 p0, const float3 p1, CollisionQuery* cq = NULL, bool forceTrace = false);
		static bool DetectHit(const CollisionVolume* v, const CSolidObject* o, const float3 p0, const float3 p1, CollisionQuery* cq, bool forceTrace = false);
		static bool MouseHit(const CUnit* u, const float3& p0, const float3& p1, const CollisionVolume* v, CollisionQuery* cq);

	private:
		// HITTEST_DISC helpers for DetectHit
		static bool Collision(const CollisionVolume* v, const CSolidObject* u, const float3 p, CollisionQuery* cq);
		// HITTEST_CONT helpers for DetectHit
		static bool Intersect(const CollisionVolume* v, const CSolidObject* o, const float3 p0, const float3 p1, CollisionQuery* cq);

	private:
		/**
		 * Test if a point lies inside a volume.
		 * @param v volume
		 * @param m volumes transformation matrix
		 * @param p point in world-coordinates
		 */
		static bool Collision(const CollisionVolume* v, const CMatrix44f& m, const float3& p);
		static bool CollisionFootPrint(const CSolidObject* o, const float3& p);

		/**
		 * Test if a ray intersects a volume.
		 * @param v volume
		 * @param m volumes transformation matrix
		 * @param p0 start of ray (in world-coordinates)
		 * @param p1 end of ray (in world-coordinates)
		 */
		static bool Intersect(const CollisionVolume* v, const CMatrix44f& m, const float3& p0, const float3& p1, CollisionQuery* cq);
		static bool IntersectPieceTree(const CUnit* u, const float3& p0, const float3& p1, CollisionQuery* cq);

		static bool IntersectPiecesHelper(const CUnit* u, const float3& p0, const float3& p1, CollisionQuery* cqp);

	public:
		static bool IntersectEllipsoid(const CollisionVolume* v, const float3& pi0, const float3& pi1, CollisionQuery* cq);
		static bool IntersectCylinder(const CollisionVolume* v, const float3& pi0, const float3& pi1, CollisionQuery* cq);
		static bool IntersectBox(const CollisionVolume* v, const float3& pi0, const float3& pi1, CollisionQuery* cq);

	private:
		static unsigned int numDiscTests; // number of discrete hit-tests executed
		static unsigned int numContTests; // number of continuous hit-tests executed (inc. unsynced)
};

#endif // COLLISION_HANDLER_H