1 // Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details
2 // Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
3 
4 #ifndef _BODY_H
5 #define _BODY_H
6 
7 #include "DeleteEmitter.h"
8 #include "FrameId.h"
9 #include "lua/PropertiedObject.h"
10 #include "matrix3x3.h"
11 #include "vector3.h"
12 #include <string>
13 
14 class Space;
15 class Camera;
16 class Frame;
17 class SystemBody;
18 
19 namespace Graphics {
20 	class Renderer;
21 }
22 struct CollisionContact;
23 
24 // ObjectType is used as a form of RTTI for Body and its children.
25 // Think carefully before adding more entries; we'd like to switch
26 // to a composition-based system instead.
27 enum class ObjectType { // <enum name=PhysicsObjectType scope='ObjectType' public>
28 	// only creating enum strings for types that are exposed to Lua
29 	BODY,
30 	MODELBODY,
31 	DYNAMICBODY, // <enum skip>
32 	SHIP,
33 	PLAYER,
34 	SPACESTATION,
35 	TERRAINBODY, // <enum skip>
36 	PLANET,
37 	STAR,
38 	CARGOBODY,
39 	PROJECTILE, // <enum skip>
40 	MISSILE,
41 	HYPERSPACECLOUD // <enum skip>
42 };
43 
44 #define OBJDEF(__thisClass, __parentClass, __TYPE)                             \
45 	virtual ObjectType GetType() const override { return ObjectType::__TYPE; } \
46 	virtual bool IsType(ObjectType c) const override                           \
47 	{                                                                          \
48 		if (__thisClass::GetType() == (c))                                     \
49 			return true;                                                       \
50 		else                                                                   \
51 			return __parentClass::IsType(c);                                   \
52 	}
53 
54 class Body : public DeleteEmitter, public PropertiedObject {
55 public:
GetType()56 	virtual ObjectType GetType() const { return ObjectType::BODY; }
IsType(ObjectType c)57 	virtual bool IsType(ObjectType c) const { return GetType() == c; }
58 
59 	Body();
60 	Body(const Json &jsonObj, Space *space);
61 	virtual ~Body();
62 	void ToJson(Json &jsonObj, Space *space);
63 	static Body *FromJson(const Json &jsonObj, Space *space);
PostLoadFixup(Space * space)64 	virtual void PostLoadFixup(Space *space){};
65 
SetPosition(const vector3d & p)66 	virtual void SetPosition(const vector3d &p) { m_pos = p; }
GetPosition()67 	vector3d GetPosition() const { return m_pos; }
SetOrient(const matrix3x3d & r)68 	virtual void SetOrient(const matrix3x3d &r) { m_orient = r; }
GetOrient()69 	const matrix3x3d &GetOrient() const { return m_orient; }
SetVelocity(const vector3d & v)70 	virtual void SetVelocity(const vector3d &v) { assert(0); }
GetVelocity()71 	virtual vector3d GetVelocity() const { return vector3d(0.0); }
72 
SetPhysRadius(double r)73 	void SetPhysRadius(double r) { m_physRadius = r; }
GetPhysRadius()74 	double GetPhysRadius() const { return m_physRadius; }
SetClipRadius(double r)75 	void SetClipRadius(double r) { m_clipRadius = r; }
GetClipRadius()76 	double GetClipRadius() const { return m_clipRadius; }
GetMass()77 	virtual double GetMass() const
78 	{
79 		assert(0);
80 		return 0;
81 	}
82 
83 	// return true if to do collision response and apply damage
OnCollision(Body * o,Uint32 flags,double relVel)84 	virtual bool OnCollision(Body *o, Uint32 flags, double relVel) { return false; }
85 	// Attacker may be null
OnDamage(Body * attacker,float kgDamage,const CollisionContact & contactData)86 	virtual bool OnDamage(Body *attacker, float kgDamage, const CollisionContact &contactData) { return false; }
87 	// Override to clear any pointers you hold to the body
NotifyRemoved(const Body * const removedBody)88 	virtual void NotifyRemoved(const Body *const removedBody) {}
89 
90 	// before all bodies have had TimeStepUpdate (their moving step),
91 	// StaticUpdate() is called. Good for special collision testing (Projectiles)
92 	// as you can't test for collisions if different objects are on different 'steps'
StaticUpdate(const float timeStep)93 	virtual void StaticUpdate(const float timeStep) {}
TimeStepUpdate(const float timeStep)94 	virtual void TimeStepUpdate(const float timeStep) {}
95 	virtual void Render(Graphics::Renderer *r, const Camera *camera, const vector3d &viewCoords, const matrix4x4d &viewTransform) = 0;
96 
SetFrame(FrameId f)97 	virtual void SetFrame(FrameId f) { m_frame = f; }
GetFrame()98 	FrameId GetFrame() const { return m_frame; }
99 	void SwitchToFrame(FrameId newFrame);
100 	void UpdateFrame(); // check for frame switching
101 
102 	vector3d GetVelocityRelTo(const Body *) const;
103 	vector3d GetVelocityRelTo(FrameId) const;
104 	vector3d GetPositionRelTo(FrameId) const;
105 	vector3d GetPositionRelTo(const Body *) const;
106 	matrix3x3d GetOrientRelTo(FrameId) const;
107 
108 	// Should return pointer in Pi::currentSystem
GetSystemBody()109 	virtual const SystemBody *GetSystemBody() const { return nullptr; }
110 	// for putting on planet surface, oriented +y up
111 	void OrientOnSurface(double radius, double latitude, double longitude);
112 
113 	virtual void SetLabel(const std::string &label);
GetLabel()114 	const std::string &GetLabel() const { return m_label; }
115 
GetFlags()116 	unsigned int GetFlags() const { return m_flags; }
117 	// TODO(sturnclaw) use this sparingly, the flags interface is rather fragile and needs work
SetFlag(unsigned int flag,bool enable)118 	void SetFlag(unsigned int flag, bool enable)
119 	{
120 		if (enable)
121 			m_flags |= flag;
122 		else
123 			m_flags &= ~flag;
124 	}
125 
126 	// Only Space::KillBody() should call this method.
MarkDead()127 	void MarkDead() { m_dead = true; }
IsDead()128 	bool IsDead() const { return m_dead; }
129 
130 	// all Bodies are in space... except where they're not (Ships hidden in hyperspace clouds)
IsInSpace()131 	virtual bool IsInSpace() const { return true; }
132 
133 	// Interpolated between physics ticks.
GetInterpOrient()134 	const matrix3x3d &GetInterpOrient() const { return m_interpOrient; }
GetInterpPosition()135 	vector3d GetInterpPosition() const { return m_interpPos; }
136 	vector3d GetInterpPositionRelTo(FrameId relToId) const;
137 	vector3d GetInterpPositionRelTo(const Body *relTo) const;
138 	matrix3x3d GetInterpOrientRelTo(FrameId relToId) const;
139 
140 	// should set m_interpolatedTransform to the smoothly interpolated value
141 	// (interpolated by 0 <= alpha <=1) between the previous and current physics tick
UpdateInterpTransform(double alpha)142 	virtual void UpdateInterpTransform(double alpha)
143 	{
144 		m_interpOrient = GetOrient();
145 		m_interpPos = GetPosition();
146 	}
147 
148 	// TODO: abstract this functionality into a component of some fashion
149 	// Return the position in body-local coordinates where the target indicator should be displayed.
150 	// Usually equal to the center of the body == vector3d(0, 0, 0)
151 	virtual vector3d GetTargetIndicatorPosition() const;
152 
153 	enum {
154 		FLAG_CAN_MOVE_FRAME = (1 << 0),
155 		FLAG_LABEL_HIDDEN = (1 << 1),
156 		FLAG_DRAW_LAST = (1 << 2),	 // causes the body drawn after other bodies in the z-sort
157 		FLAG_DRAW_EXCLUDE = (1 << 3) // do not draw this body, intended for e.g. when camera is inside
158 	};
159 
160 protected:
161 	virtual void SaveToJson(Json &jsonObj, Space *space);
162 	unsigned int m_flags;
163 
164 	// Interpolated draw orientation-position
165 	vector3d m_interpPos;
166 	matrix3x3d m_interpOrient;
167 
168 private:
169 	vector3d m_pos;
170 	matrix3x3d m_orient;
171 	FrameId m_frame; // frame of reference
172 	std::string m_label;
173 	bool m_dead; // Checked in destructor to make sure body has been marked dead.
174 	double m_clipRadius;
175 	double m_physRadius;
176 };
177 
178 #endif /* _BODY_H */
179