1 /* Copyright (C) 2022 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
18 #ifndef INCLUDED_CCMPRALLYPOINTRENDERER
19 #define INCLUDED_CCMPRALLYPOINTRENDERER
21 #include "ICmpRallyPointRenderer.h"
23 #include "graphics/Overlay.h"
24 #include "graphics/TextureManager.h"
25 #include "ps/CLogger.h"
26 #include "renderer/Renderer.h"
27 #include "simulation2/MessageTypes.h"
28 #include "simulation2/components/ICmpFootprint.h"
29 #include "simulation2/components/ICmpIdentity.h"
30 #include "simulation2/components/ICmpObstructionManager.h"
31 #include "simulation2/components/ICmpOwnership.h"
32 #include "simulation2/components/ICmpPathfinder.h"
33 #include "simulation2/components/ICmpPlayer.h"
34 #include "simulation2/components/ICmpPlayerManager.h"
35 #include "simulation2/components/ICmpPosition.h"
36 #include "simulation2/components/ICmpTerrain.h"
37 #include "simulation2/components/ICmpVisual.h"
38 #include "simulation2/components/ICmpWaterManager.h"
39 #include "simulation2/helpers/Render.h"
40 #include "simulation2/helpers/Geometry.h"
41 #include "simulation2/system/Component.h"
43 struct SVisibilitySegment
47 size_t m_EndIndex
; // Inclusive
49 SVisibilitySegment(bool visible
, size_t startIndex
, size_t endIndex
)
50 : m_Visible(visible
), m_StartIndex(startIndex
), m_EndIndex(endIndex
)
53 bool operator==(const SVisibilitySegment
& other
) const
55 return m_Visible
== other
.m_Visible
&& m_StartIndex
== other
.m_StartIndex
&& m_EndIndex
== other
.m_EndIndex
;
58 bool operator!=(const SVisibilitySegment
& other
) const
60 return !(*this == other
);
63 bool IsSinglePoint() const
65 return m_StartIndex
== m_EndIndex
;
69 class CCmpRallyPointRenderer final
: public ICmpRallyPointRenderer
72 static std::string
GetSchema();
73 static void ClassInit(CComponentManager
& componentManager
);
75 void Init(const CParamNode
& paramNode
) override
;
76 void Deinit() override
;
78 void Serialize(ISerializer
& UNUSED(serialize
)) override
;
79 void Deserialize(const CParamNode
& paramNode
, IDeserializer
& UNUSED(deserialize
)) override
;
81 void HandleMessage(const CMessage
& msg
, bool UNUSED(global
)) override
;
84 * Must be called whenever m_Displayed or the size of m_RallyPoints change,
85 * to determine whether we need to respond to render messages.
87 virtual void UpdateMessageSubscriptions();
89 void AddPosition_wrapper(const CFixedVector2D
& pos
) override
;
91 void SetPosition(const CFixedVector2D
& pos
) override
;
93 void UpdatePosition(u32 rallyPointId
, const CFixedVector2D
& pos
) override
;
95 void SetDisplayed(bool displayed
) override
;
97 void Reset() override
;
99 void UpdateColor() override
;
102 * Returns true if at least one display rally point is set; i.e., if we have a point to render our marker/line at.
104 bool IsSet() const override
;
106 DEFAULT_COMPONENT_ALLOCATOR(RallyPointRenderer
)
110 * Display position of the rally points. Note that this are merely the display positions; they not necessarily the same as the
111 * actual positions used in the simulation at any given time. In particular, we need this separate copy to support
112 * instantaneously rendering the rally point markers/lines when the user sets one in-game (instead of waiting until the
113 * network-synchronization code sets it on the RallyPoint component, which might take up to half a second).
115 std::vector
<CFixedVector2D
> m_RallyPoints
;
117 * Full path to the rally points as returned by the pathfinder, with some post-processing applied to reduce zig/zagging.
119 std::vector
<std::vector
<CVector2D
> > m_Path
;
121 * Visibility segments of the rally point paths; splits the path into SoD/non-SoD segments.
123 std::vector
<std::vector
<SVisibilitySegment
> > m_VisibilitySegments
;
125 * Should we render the rally points and the path lines? (set from JS when e.g. the unit is selected/deselected)
129 * Smooth the path before rendering?
133 * Entity IDs of the rally point markers.
135 std::vector
<entity_id_t
> m_MarkerEntityIds
;
137 size_t m_LastMarkerCount
;
139 * Last seen owner of this entity (used to keep track of ownership changes).
141 player_id_t m_LastOwner
;
143 * Template name of the rally point markers.
145 std::wstring m_MarkerTemplate
;
148 * Marker connector line settings (loaded from XML)
150 float m_LineThickness
;
152 CColor m_LineDashColor
;
153 SOverlayTexturedLine::LineCapType m_LineStartCapType
;
154 SOverlayTexturedLine::LineCapType m_LineEndCapType
;
155 std::wstring m_LineTexturePath
;
156 std::wstring m_LineTextureMaskPath
;
158 * Pathfinder passability class to use for computing the (long-range) marker line path.
160 std::string m_LinePassabilityClass
;
162 CTexturePtr m_Texture
;
163 CTexturePtr m_TextureMask
;
166 * Textured overlay lines to be used for rendering the marker line. There can be multiple because we may need to render
167 * dashes for segments that are inside the SoD.
169 std::vector
<std::vector
<SOverlayTexturedLine
> > m_TexturedOverlayLines
;
172 * Draw little overlay circles to indicate where the exact path points are.
174 bool m_EnableDebugNodeOverlay
;
175 std::vector
<std::vector
<SOverlayLine
> > m_DebugNodeOverlays
;
179 * Helper function for AddPosition_wrapper and SetPosition.
181 void AddPosition(CFixedVector2D pos
, bool recompute
);
184 * Helper function to set the line color to its owner's color.
186 void UpdateLineColor();
189 * Repositions the rally point markers; moves them outside of the world (ie. hides them), or positions them at the currently
190 * set rally points. Also updates the actor's variation according to the entity's current owning player's civilization.
192 * Should be called whenever either the position of a rally point changes (including whether it is set or not), or the display
193 * flag changes, or the ownership of the entity changes.
195 void UpdateMarkers();
198 * Recomputes all the full paths from this entity to the rally point and from the rally point to the next, and does all the necessary
199 * post-processing to make them prettier.
201 * Should be called whenever all rally points' position changes.
203 void RecomputeAllRallyPointPaths();
206 * Recomputes the full path for m_Path[ @p index], and does all the necessary post-processing to make it prettier.
208 * Should be called whenever either the starting position or the rally point's position changes.
210 void RecomputeRallyPointPath_wrapper(size_t index
);
213 * Recomputes the full path from this entity/the previous rally point to the next rally point, and does all the necessary
214 * post-processing to make it prettier. This doesn't check if we have a valid position or if a rally point is set.
216 * You shouldn't need to call this method directly.
218 void RecomputeRallyPointPath(size_t index
, CmpPtr
<ICmpPosition
>& cmpPosition
, CmpPtr
<ICmpFootprint
>& cmpFootprint
, CmpPtr
<ICmpPathfinder
> cmpPathfinder
);
221 * Checks for changes to the SoD to the previously saved state, and reconstructs the visibility segments and overlay lines to
222 * match if necessary. Does nothing if the rally point lines are not currently set to be displayed, or if no rally point is set.
224 void UpdateOverlayLines();
227 * Sets up all overlay lines for rendering according to the current full path and visibility segments. Splits the line into solid
228 * and dashed pieces (for the SoD). Should be called whenever the SoD has changed. If no full path is currently set, this method
231 void ConstructAllOverlayLines();
234 * Sets up the overlay lines for rendering according to the full path and visibility segments at @p index. Splits the line into
235 * solid and dashed pieces (for the SoD). Should be called whenever the SoD of the path at @p index has changed.
237 void ConstructOverlayLines(size_t index
);
240 * Get the point on the footprint edge that's as close from "start" as possible.
242 void GetClosestsEdgePointFrom(CFixedVector2D
& result
, CFixedVector2D
& start
, CmpPtr
<ICmpPosition
> cmpPosition
, CmpPtr
<ICmpFootprint
> cmpFootprint
) const;
245 * Returns a list of indices of waypoints in the current path (m_Path[index]) where the LOS visibility changes, ordered from
246 * building/previous rally point to rally point. Used to construct the overlay line segments and track changes to the SoD.
248 void GetVisibilitySegments(std::vector
<SVisibilitySegment
>& out
, size_t index
) const;
251 * Simplifies the path by removing waypoints that lie between two points that are visible from one another. This is primarily
252 * intended to reduce some unnecessary curviness of the path; the pathfinder returns a mathematically (near-)optimal path, which
253 * will happily curve and bend to reduce costs. Visually, it doesn't make sense for a rally point path to curve and bend when it
254 * could just as well have gone in a straight line; that's why we have this, to make it look more natural.
256 * @p coords array of path coordinates to simplify
257 * @p maxSegmentLinks if non-zero, indicates the maximum amount of consecutive node-to-node links that can be joined into a
258 * single link. If this value is set to e.g. 1, then no reductions will be performed. A value of 3 means that
259 * at most 3 consecutive node links will be joined into a single link.
260 * @p floating whether to consider nodes who are under the water level as floating on top of the water
262 void ReduceSegmentsByVisibility(std::vector
<CVector2D
>& coords
, unsigned maxSegmentLinks
= 0, bool floating
= true) const;
265 * Helper function to GetVisibilitySegments, factored out for testing. Merges single-point segments with its neighbouring
266 * segments. You should not have to call this method directly.
268 static void MergeVisibilitySegments(std::vector
<SVisibilitySegment
>& segments
);
270 void RenderSubmit(SceneCollector
& collector
, const CFrustum
& frustum
, bool culling
);
273 REGISTER_COMPONENT_TYPE(RallyPointRenderer
)
275 #endif // INCLUDED_CCMPRALLYPOINTRENDERER