1 /* Copyright (C) 2017 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 #ifndef INCLUDED_CCMPPATHFINDER_COMMON
19 #define INCLUDED_CCMPPATHFINDER_COMMON
20 
21 /**
22  * @file
23  * Declares CCmpPathfinder. Its implementation is mainly done in CCmpPathfinder.cpp,
24  * but the short-range (vertex) pathfinding is done in CCmpPathfinder_Vertex.cpp.
25  * This file provides common code needed for both files.
26  *
27  * The long-range pathfinding is done by a LongPathfinder object.
28  */
29 
30 #include "simulation2/system/Component.h"
31 
32 #include "ICmpPathfinder.h"
33 
34 #include "graphics/Overlay.h"
35 #include "graphics/Terrain.h"
36 #include "maths/MathUtil.h"
37 #include "ps/CLogger.h"
38 #include "simulation2/components/ICmpObstructionManager.h"
39 #include "simulation2/helpers/LongPathfinder.h"
40 
41 class SceneCollector;
42 class AtlasOverlay;
43 
44 #ifdef NDEBUG
45 #define PATHFIND_DEBUG 0
46 #else
47 #define PATHFIND_DEBUG 1
48 #endif
49 
50 
51 struct AsyncLongPathRequest
52 {
53 	u32 ticket;
54 	entity_pos_t x0;
55 	entity_pos_t z0;
56 	PathGoal goal;
57 	pass_class_t passClass;
58 	entity_id_t notify;
59 };
60 
61 struct AsyncShortPathRequest
62 {
63 	u32 ticket;
64 	entity_pos_t x0;
65 	entity_pos_t z0;
66 	entity_pos_t clearance;
67 	entity_pos_t range;
68 	PathGoal goal;
69 	pass_class_t passClass;
70 	bool avoidMovingUnits;
71 	entity_id_t group;
72 	entity_id_t notify;
73 };
74 
75 // A vertex around the corners of an obstruction
76 // (paths will be sequences of these vertexes)
77 struct Vertex
78 {
79 	enum
80 	{
81 		UNEXPLORED,
82 		OPEN,
83 		CLOSED,
84 	};
85 
86 	CFixedVector2D p;
87 	fixed g, h;
88 	u16 pred;
89 	u8 status;
90 	u8 quadInward : 4; // the quadrant which is inside the shape (or NONE)
91 	u8 quadOutward : 4; // the quadrants of the next point on the path which this vertex must be in, given 'pred'
92 };
93 
94 // Obstruction edges (paths will not cross any of these).
95 // Defines the two points of the edge.
96 struct Edge
97 {
98 	CFixedVector2D p0, p1;
99 };
100 
101 // Axis-aligned obstruction squares (paths will not cross any of these).
102 // Defines the opposing corners of an axis-aligned square
103 // (from which four individual edges can be trivially computed), requiring p0 <= p1
104 struct Square
105 {
106 	CFixedVector2D p0, p1;
107 };
108 
109 // Axis-aligned obstruction edges.
110 // p0 defines one end; c1 is either the X or Y coordinate of the other end,
111 // depending on the context in which this is used.
112 struct EdgeAA
113 {
114 	CFixedVector2D p0;
115 	fixed c1;
116 };
117 
118 /**
119  * Implementation of ICmpPathfinder
120  */
121 class CCmpPathfinder : public ICmpPathfinder
122 {
123 public:
ClassInit(CComponentManager & componentManager)124 	static void ClassInit(CComponentManager& componentManager)
125 	{
126 		componentManager.SubscribeToMessageType(MT_Update);
127 		componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays
128 		componentManager.SubscribeToMessageType(MT_TerrainChanged);
129 		componentManager.SubscribeToMessageType(MT_WaterChanged);
130 		componentManager.SubscribeToMessageType(MT_ObstructionMapShapeChanged);
131 		componentManager.SubscribeToMessageType(MT_TurnStart);
132 	}
133 
134 	DEFAULT_COMPONENT_ALLOCATOR(Pathfinder)
135 
136 	// Template state:
137 
138 	std::map<std::string, pass_class_t> m_PassClassMasks;
139 	std::vector<PathfinderPassability> m_PassClasses;
140 
141 	// Dynamic state:
142 
143 	std::vector<AsyncLongPathRequest> m_AsyncLongPathRequests;
144 	std::vector<AsyncShortPathRequest> m_AsyncShortPathRequests;
145 	u32 m_NextAsyncTicket; // unique IDs for asynchronous path requests
146 	u16 m_SameTurnMovesCount; // current number of same turn moves we have processed this turn
147 
148 	// Lazily-constructed dynamic state (not serialized):
149 
150 	u16 m_MapSize; // tiles per side
151 	Grid<NavcellData>* m_Grid; // terrain/passability information
152 	Grid<NavcellData>* m_TerrainOnlyGrid; // same as m_Grid, but only with terrain, to avoid some recomputations
153 
154 	// Keep clever updates in memory to avoid memory fragmentation from the grid.
155 	// This should be used only in UpdateGrid(), there is no guarantee the data is properly initialized anywhere else.
156 	GridUpdateInformation m_DirtinessInformation;
157 	// The data from clever updates is stored for the AI manager
158 	GridUpdateInformation m_AIPathfinderDirtinessInformation;
159 	bool m_TerrainDirty;
160 
161 	// Interface to the long-range pathfinder.
162 	LongPathfinder m_LongPathfinder;
163 
164 	// For responsiveness we will process some moves in the same turn they were generated in
165 
166 	u16 m_MaxSameTurnMoves; // max number of moves that can be created and processed in the same turn
167 
168 	// memory optimizations: those vectors are created once, reused for all calculations;
169 	std::vector<Edge> edgesUnaligned;
170 	std::vector<EdgeAA> edgesLeft;
171 	std::vector<EdgeAA> edgesRight;
172 	std::vector<EdgeAA> edgesBottom;
173 	std::vector<EdgeAA> edgesTop;
174 
175 	// List of obstruction vertexes (plus start/end points); we'll try to find paths through
176 	// the graph defined by these vertexes
177 	std::vector<Vertex> vertexes;
178 	// List of collision edges - paths must never cross these.
179 	// (Edges are one-sided so intersections are fine in one direction, but not the other direction.)
180 	std::vector<Edge> edges;
181 	std::vector<Square> edgeSquares; // axis-aligned squares; equivalent to 4 edges
182 
183 	bool m_DebugOverlay;
184 	std::vector<SOverlayLine> m_DebugOverlayShortPathLines;
185 	AtlasOverlay* m_AtlasOverlay;
186 
GetSchema()187 	static std::string GetSchema()
188 	{
189 		return "<a:component type='system'/><empty/>";
190 	}
191 
192 	virtual void Init(const CParamNode& paramNode);
193 
194 	virtual void Deinit();
195 
196 	template<typename S>
197 	void SerializeCommon(S& serialize);
198 
199 	virtual void Serialize(ISerializer& serialize);
200 
201 	virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize);
202 
203 	virtual void HandleMessage(const CMessage& msg, bool global);
204 
205 	virtual pass_class_t GetPassabilityClass(const std::string& name) const;
206 
207 	virtual void GetPassabilityClasses(std::map<std::string, pass_class_t>& passClasses) const;
208 	virtual void GetPassabilityClasses(
209 		std::map<std::string, pass_class_t>& nonPathfindingPassClasses,
210 		std::map<std::string, pass_class_t>& pathfindingPassClasses) const;
211 
212 	const PathfinderPassability* GetPassabilityFromMask(pass_class_t passClass) const;
213 
GetClearance(pass_class_t passClass)214 	virtual entity_pos_t GetClearance(pass_class_t passClass) const
215 	{
216 		const PathfinderPassability* passability = GetPassabilityFromMask(passClass);
217 		if (!passability)
218 			return fixed::Zero();
219 
220 		return passability->m_Clearance;
221 	}
222 
GetMaximumClearance()223 	virtual entity_pos_t GetMaximumClearance() const
224 	{
225 		entity_pos_t max = fixed::Zero();
226 
227 		for (const PathfinderPassability& passability : m_PassClasses)
228 			if (passability.m_Clearance > max)
229 				max = passability.m_Clearance;
230 
231 		return max + Pathfinding::CLEARANCE_EXTENSION_RADIUS;
232 	}
233 
234 	virtual const Grid<NavcellData>& GetPassabilityGrid();
235 
GetAIPathfinderDirtinessInformation()236 	virtual const GridUpdateInformation& GetAIPathfinderDirtinessInformation() const
237 	{
238 		return m_AIPathfinderDirtinessInformation;
239 	}
240 
FlushAIPathfinderDirtinessInformation()241 	virtual void FlushAIPathfinderDirtinessInformation()
242 	{
243 		m_AIPathfinderDirtinessInformation.Clean();
244 	}
245 
246 	virtual Grid<u16> ComputeShoreGrid(bool expandOnWater = false);
247 
ComputePath(entity_pos_t x0,entity_pos_t z0,const PathGoal & goal,pass_class_t passClass,WaypointPath & ret)248 	virtual void ComputePath(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret)
249 	{
250 		m_LongPathfinder.ComputePath(x0, z0, goal, passClass, ret);
251 	}
252 
253 	virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, entity_id_t notify);
254 
255 	virtual void ComputeShortPath(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret);
256 
257 	virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t controller, entity_id_t notify);
258 
SetDebugPath(entity_pos_t x0,entity_pos_t z0,const PathGoal & goal,pass_class_t passClass)259 	virtual void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass)
260 	{
261 		m_LongPathfinder.SetDebugPath(x0, z0, goal, passClass);
262 	}
263 
SetDebugOverlay(bool enabled)264 	virtual void SetDebugOverlay(bool enabled)
265 	{
266 		m_DebugOverlay = enabled;
267 		m_LongPathfinder.SetDebugOverlay(enabled);
268 	}
269 
SetHierDebugOverlay(bool enabled)270 	virtual void SetHierDebugOverlay(bool enabled)
271 	{
272 		m_LongPathfinder.SetHierDebugOverlay(enabled, &GetSimContext());
273 	}
274 
GetDebugData(u32 & steps,double & time,Grid<u8> & grid)275 	virtual void GetDebugData(u32& steps, double& time, Grid<u8>& grid) const
276 	{
277 		m_LongPathfinder.GetDebugData(steps, time, grid);
278 	}
279 
280 	virtual void SetAtlasOverlay(bool enable, pass_class_t passClass = 0);
281 
282 	virtual bool CheckMovement(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass) const;
283 
284 	virtual ICmpObstruction::EFoundationCheck CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass, bool onlyCenterPoint) const;
285 
286 	virtual ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass) const;
287 
288 	virtual ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass, bool onlyCenterPoint) const;
289 
290 	virtual void FinishAsyncRequests();
291 
292 	void ProcessLongRequests(const std::vector<AsyncLongPathRequest>& longRequests);
293 
294 	void ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests);
295 
296 	virtual void ProcessSameTurnMoves();
297 
298 	/**
299 	 * Regenerates the grid based on the current obstruction list, if necessary
300 	 */
301 	virtual void UpdateGrid();
302 
303 	/**
304 	 * Updates the terrain-only grid without updating the dirtiness informations.
305 	 * Useful for fast passability updates in Atlas.
306 	 */
307 	void MinimalTerrainUpdate();
308 
309 	/**
310 	 * Regenerates the terrain-only grid.
311 	 * Atlas doesn't need to have passability cells expanded.
312 	 */
313 	void TerrainUpdateHelper(bool expandPassability = true);
314 
315 	void RenderSubmit(SceneCollector& collector);
316 };
317 
318 class AtlasOverlay : public TerrainTextureOverlay
319 {
320 public:
321 	const CCmpPathfinder* m_Pathfinder;
322 	pass_class_t m_PassClass;
323 
AtlasOverlay(const CCmpPathfinder * pathfinder,pass_class_t passClass)324 	AtlasOverlay(const CCmpPathfinder* pathfinder, pass_class_t passClass) :
325 		TerrainTextureOverlay(Pathfinding::NAVCELLS_PER_TILE), m_Pathfinder(pathfinder), m_PassClass(passClass)
326 	{
327 	}
328 
BuildTextureRGBA(u8 * data,size_t w,size_t h)329 	virtual void BuildTextureRGBA(u8* data, size_t w, size_t h)
330 	{
331 		// Render navcell passability, based on the terrain-only grid
332 		u8* p = data;
333 		for (size_t j = 0; j < h; ++j)
334 		{
335 			for (size_t i = 0; i < w; ++i)
336 			{
337 				SColor4ub color(0, 0, 0, 0);
338 				if (!IS_PASSABLE(m_Pathfinder->m_TerrainOnlyGrid->get((int)i, (int)j), m_PassClass))
339 					color = SColor4ub(255, 0, 0, 127);
340 
341 				*p++ = color.R;
342 				*p++ = color.G;
343 				*p++ = color.B;
344 				*p++ = color.A;
345 			}
346 		}
347 	}
348 };
349 
350 #endif // INCLUDED_CCMPPATHFINDER_COMMON
351