Line data Source code
1 : /* Copyright (C) 2022 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 : #include "precompiled.h"
19 :
20 : #include "ICmpRangeOverlayRenderer.h"
21 :
22 : #include "graphics/Overlay.h"
23 : #include "graphics/TextureManager.h"
24 : #include "renderer/Renderer.h"
25 : #include "simulation2/MessageTypes.h"
26 : #include "simulation2/components/ICmpOwnership.h"
27 : #include "simulation2/components/ICmpPlayer.h"
28 : #include "simulation2/components/ICmpPlayerManager.h"
29 : #include "simulation2/components/ICmpPosition.h"
30 : #include "simulation2/helpers/Render.h"
31 : #include "simulation2/system/Component.h"
32 :
33 : #include <memory>
34 :
35 : class CCmpRangeOverlayRenderer final : public ICmpRangeOverlayRenderer
36 : {
37 : public:
38 116 : static void ClassInit(CComponentManager& componentManager)
39 : {
40 116 : componentManager.SubscribeToMessageType(MT_Deserialized);
41 116 : componentManager.SubscribeToMessageType(MT_OwnershipChanged);
42 116 : componentManager.SubscribeToMessageType(MT_PlayerColorChanged);
43 116 : }
44 :
45 0 : DEFAULT_COMPONENT_ALLOCATOR(RangeOverlayRenderer)
46 :
47 0 : CCmpRangeOverlayRenderer() : m_RangeOverlayData()
48 : {
49 0 : m_Color = CColor(0.f, 0.f, 0.f, 1.f);
50 0 : }
51 :
52 0 : ~CCmpRangeOverlayRenderer() = default;
53 :
54 116 : static std::string GetSchema()
55 : {
56 116 : return "<a:component type='system'/><empty/>";
57 : }
58 :
59 0 : void Init(const CParamNode& UNUSED(paramNode)) override
60 : {
61 0 : m_Enabled = m_LastEnabledState = false;
62 0 : UpdateMessageSubscriptions();
63 0 : }
64 :
65 0 : void Deinit() override { }
66 :
67 0 : void Serialize(ISerializer& UNUSED(serialize)) override
68 : {
69 0 : }
70 :
71 0 : void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override
72 : {
73 0 : Init(paramNode);
74 0 : }
75 :
76 0 : void ResetRangeOverlays() override
77 : {
78 0 : m_RangeOverlayData.clear();
79 0 : UpdateMessageSubscriptions();
80 0 : m_Enabled = false;
81 0 : }
82 :
83 0 : void AddRangeOverlay(float radius, const std::string& texture, const std::string& textureMask, float thickness) override
84 : {
85 0 : if (!CRenderer::IsInitialised())
86 0 : return;
87 :
88 0 : SOverlayDescriptor rangeOverlayDescriptor;
89 0 : rangeOverlayDescriptor.m_Radius = radius;
90 0 : rangeOverlayDescriptor.m_LineTexture = CStrIntern(TEXTURE_BASE_PATH + texture);
91 0 : rangeOverlayDescriptor.m_LineTextureMask = CStrIntern(TEXTURE_BASE_PATH + textureMask);
92 0 : rangeOverlayDescriptor.m_LineThickness = thickness;
93 :
94 0 : m_RangeOverlayData.push_back({
95 : rangeOverlayDescriptor, std::unique_ptr<SOverlayTexturedLine>()
96 : });
97 0 : m_Enabled = true;
98 0 : UpdateMessageSubscriptions();
99 : }
100 :
101 0 : void HandleMessage(const CMessage& msg, bool UNUSED(global)) override
102 : {
103 0 : switch (msg.GetType())
104 : {
105 0 : case MT_Interpolate:
106 : {
107 0 : const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg);
108 :
109 0 : for (RangeOverlayData& rangeOverlay : m_RangeOverlayData)
110 0 : UpdateRangeOverlay(rangeOverlay, msgData.offset);
111 :
112 0 : UpdateMessageSubscriptions();
113 :
114 0 : break;
115 : }
116 0 : case MT_Deserialized:
117 : case MT_OwnershipChanged:
118 : case MT_PlayerColorChanged:
119 : {
120 0 : UpdateColor();
121 0 : break;
122 : }
123 0 : case MT_RenderSubmit:
124 : {
125 0 : const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg);
126 0 : RenderSubmit(msgData.collector, msgData.frustum, msgData.culling);
127 0 : break;
128 : }
129 : }
130 0 : }
131 :
132 : private:
133 0 : struct RangeOverlayData {
134 : SOverlayDescriptor descriptor;
135 : std::unique_ptr<SOverlayTexturedLine> line;
136 : };
137 :
138 0 : void UpdateColor() override
139 : {
140 0 : CmpPtr<ICmpOwnership> cmpOwnership(GetEntityHandle());
141 0 : if (!cmpOwnership)
142 0 : return;
143 :
144 0 : player_id_t owner = cmpOwnership->GetOwner();
145 0 : if (owner == INVALID_PLAYER)
146 0 : return;
147 :
148 0 : CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSystemEntity());
149 0 : if (!cmpPlayerManager)
150 0 : return;
151 :
152 0 : CmpPtr<ICmpPlayer> cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(owner));
153 0 : if (!cmpPlayer)
154 0 : return;
155 :
156 0 : CColor color = cmpPlayer->GetDisplayedColor();
157 0 : m_Color = color;
158 : }
159 :
160 0 : void UpdateMessageSubscriptions()
161 : {
162 0 : if (m_Enabled == m_LastEnabledState)
163 0 : return;
164 :
165 0 : CComponentManager& cmpManager = GetSimContext().GetComponentManager();
166 0 : cmpManager.DynamicSubscriptionNonsync(MT_Interpolate, this, m_Enabled);
167 0 : cmpManager.DynamicSubscriptionNonsync(MT_RenderSubmit, this, m_Enabled);
168 0 : m_LastEnabledState = m_Enabled;
169 : }
170 :
171 0 : void RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling)
172 : {
173 0 : if (!m_RangeOverlayData.size())
174 0 : return;
175 :
176 0 : for (const RangeOverlayData& rangeOverlay : m_RangeOverlayData)
177 : {
178 0 : if (!rangeOverlay.line)
179 0 : continue;
180 0 : if (culling && !rangeOverlay.line->IsVisibleInFrustum(frustum))
181 0 : continue;
182 0 : collector.Submit(rangeOverlay.line.get());
183 : }
184 : }
185 :
186 0 : void UpdateRangeOverlay(RangeOverlayData& rangeOverlay, const float frameOffset)
187 : {
188 0 : if (!CRenderer::IsInitialised())
189 0 : return;
190 :
191 0 : CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
192 0 : if (!cmpPosition || !cmpPosition->IsInWorld())
193 0 : return;
194 :
195 : float rotY;
196 0 : CVector2D origin;
197 0 : cmpPosition->GetInterpolatedPosition2D(frameOffset, origin.X, origin.Y, rotY);
198 :
199 0 : rangeOverlay.line = std::make_unique<SOverlayTexturedLine>();
200 0 : rangeOverlay.line->m_SimContext = &GetSimContext();
201 0 : rangeOverlay.line->m_Color = m_Color;
202 0 : rangeOverlay.line->CreateOverlayTexture(&rangeOverlay.descriptor);
203 :
204 0 : SimRender::ConstructTexturedLineCircle(*rangeOverlay.line.get(), origin, rangeOverlay.descriptor.m_Radius);
205 : }
206 :
207 : bool m_LastEnabledState;
208 : bool m_Enabled;
209 :
210 : const char* TEXTURE_BASE_PATH = "art/textures/selection/";
211 : std::vector<RangeOverlayData> m_RangeOverlayData;
212 : CColor m_Color;
213 : };
214 :
215 119 : REGISTER_COMPONENT_TYPE(RangeOverlayRenderer)
|