1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * Base class for renderable objects
20  */
21 
22 #ifndef INCLUDED_RENDERABLEOBJECT
23 #define INCLUDED_RENDERABLEOBJECT
24 
25 
26 #include "maths/BoundingBoxAligned.h"
27 #include "maths/Matrix3D.h"
28 
29 
30 // dirty flags - used as notification to the renderer that some bit of data
31 // need updating
32 #define RENDERDATA_UPDATE_VERTICES		(1<<1)
33 #define RENDERDATA_UPDATE_INDICES		(1<<2)
34 #define RENDERDATA_UPDATE_COLOR			(1<<4)
35 
36 
37 ///////////////////////////////////////////////////////////////////////////////
38 // CRenderData: base class of all the renderer's renderdata classes - the
39 // derived class stores necessary information for rendering an object of a
40 // particular type
41 class CRenderData
42 {
43 public:
CRenderData()44 	CRenderData() : m_UpdateFlags(0) {}
~CRenderData()45 	virtual ~CRenderData() {}
46 
47 	int m_UpdateFlags;
48 };
49 
50 ///////////////////////////////////////////////////////////////////////////////
51 // CRenderableObject: base class of all renderable objects - patches, models,
52 // sprites, etc; stores position and bound information, and a pointer to
53 // some renderdata necessary for the renderer to actually render it
54 class CRenderableObject
55 {
56 	NONCOPYABLE(CRenderableObject);
57 
58 public:
59 	// constructor
CRenderableObject()60 	CRenderableObject() : m_RenderData(0), m_BoundsValid(false)
61 	{
62 		m_Transform.SetIdentity();
63 	}
64 	// destructor
~CRenderableObject()65 	virtual ~CRenderableObject() { delete m_RenderData; }
66 
67 	// set object transform
SetTransform(const CMatrix3D & transform)68 	virtual void SetTransform(const CMatrix3D& transform)
69 	{
70 		if (m_Transform == transform)
71 			return;
72 		// store transform, calculate inverse
73 		m_Transform=transform;
74 		m_Transform.GetInverse(m_InvTransform);
75 		// normal recalculation likely required on transform change; flag it
76 		SetDirty(RENDERDATA_UPDATE_VERTICES);
77 		// need to rebuild world space bounds
78 		InvalidateBounds();
79 	}
80 	// get object to world space transform
GetTransform()81 	const CMatrix3D& GetTransform() const { return m_Transform; }
82 	// get world to object space transform
GetInvTransform()83 	const CMatrix3D& GetInvTransform() const { return m_InvTransform; }
84 
85 	// mark some part of the renderdata as dirty, and requiring
86 	// an update on next render
SetDirty(u32 dirtyflags)87 	void SetDirty(u32 dirtyflags)
88 	{
89 		if (m_RenderData)
90 			m_RenderData->m_UpdateFlags |= dirtyflags;
91 	}
92 
93 	/**
94 	 * (Re)calculates and stores any bounds or bound-dependent data for this object. At this abstraction level, this is only the world-space
95 	 * bounds stored in @ref m_WorldBounds; subclasses may use this method to (re)compute additional bounds if necessary, or any data that
96 	 * depends on the bounds. Whenever bound-dependent data is requested through a public interface, @ref RecalculateBoundsIfNecessary should
97 	 * be called first to ensure bound correctness, which will in turn call this method if it turns out that they're outdated.
98 	 *
99 	 * @see m_BoundsValid
100 	 * @see RecalculateBoundsIfNecessary
101 	 */
102 	virtual void CalcBounds() = 0;
103 
104 	/// Returns the world-space axis-aligned bounds of this object.
GetWorldBounds()105 	const CBoundingBoxAligned& GetWorldBounds()
106 	{
107 		RecalculateBoundsIfNecessary();
108 		return m_WorldBounds;
109 	}
110 
111 	/**
112 	 * Marks the bounds as invalid. This will trigger @ref RecalculateBoundsIfNecessary to recompute any bound-related data the next time
113 	 * any bound-related data is requested through a public interface -- at least, if you've made sure to call it before returning the
114 	 * stored data.
115 	 */
InvalidateBounds()116 	virtual void InvalidateBounds() { m_BoundsValid = false; }
117 
118 	// Set the object renderdata and free previous renderdata, if any.
SetRenderData(CRenderData * renderdata)119 	void SetRenderData(CRenderData* renderdata)
120 	{
121 		delete m_RenderData;
122 		m_RenderData = renderdata;
123 	}
124 
125 	/// Return object renderdata - can be null if renderer hasn't yet created the renderdata
GetRenderData()126 	CRenderData* GetRenderData() { return m_RenderData; }
127 
128 protected:
129 	/// Factored out so subclasses don't need to repeat this if they want to add additional getters for bounds-related methods
130 	/// (since they'll have to make sure to recalc the bounds if necessary before they return it).
RecalculateBoundsIfNecessary()131 	void RecalculateBoundsIfNecessary()
132 	{
133 		if (!m_BoundsValid) {
134 			CalcBounds();
135 			m_BoundsValid = true;
136 		}
137 	}
138 
139 protected:
140 	/// World-space bounds of this object
141 	CBoundingBoxAligned m_WorldBounds;
142 	// local->world space transform
143 	CMatrix3D m_Transform;
144 	// world->local space transform
145 	CMatrix3D m_InvTransform;
146 	// object renderdata
147 	CRenderData* m_RenderData;
148 
149 	/**
150 	 * Remembers whether any bounds need to be recalculated. Subclasses that add any data that depends on the bounds should
151 	 * take care to consider the validity of the bounds and recalculate their data when necessary -- overriding @ref CalcBounds
152 	 * to do so would be a good idea, since it's already set up to be called by @ref RecalculateBoundsIfNecessary whenever the
153 	 * bounds are marked as invalid. The latter should then be called before returning any bounds or bounds-derived data through
154 	 * a public interface (see the implementation of @ref GetWorldBounds for an example).
155 	 *
156 	 * @see CalcBounds
157 	 * @see InvalidateBounds
158 	 * @see RecalculateBoundsIfNecessary
159 	 */
160 	bool m_BoundsValid;
161 };
162 
163 #endif
164