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 "simulation2/system/Component.h"
21 : #include "ICmpOverlayRenderer.h"
22 :
23 : #include "ICmpPosition.h"
24 :
25 : #include "simulation2/MessageTypes.h"
26 :
27 : #include "graphics/Overlay.h"
28 : #include "graphics/TextureManager.h"
29 : #include "renderer/Renderer.h"
30 : #include "ps/CLogger.h"
31 : #include "ps/Profile.h"
32 :
33 0 : class CCmpOverlayRenderer final : public ICmpOverlayRenderer
34 : {
35 : public:
36 116 : static void ClassInit(CComponentManager& UNUSED(componentManager))
37 : {
38 116 : }
39 :
40 0 : DEFAULT_COMPONENT_ALLOCATOR(OverlayRenderer)
41 :
42 : // Currently-enabled set of sprites
43 : std::vector<SOverlaySprite> m_Sprites;
44 :
45 : // For each entry in m_Sprites, store the offset of the sprite from the unit's position
46 : // (so we can recompute the sprite position after the unit moves)
47 : std::vector<CVector3D> m_SpriteOffsets;
48 :
49 : // Whether the sprites should be drawn (only valid between Interpolate and RenderSubmit)
50 : bool m_Enabled;
51 :
52 116 : static std::string GetSchema()
53 : {
54 116 : return "<empty/>";
55 : }
56 :
57 0 : void Init(const CParamNode& UNUSED(paramNode)) override
58 : {
59 0 : }
60 :
61 0 : void Deinit() override
62 : {
63 0 : }
64 :
65 0 : void Serialize(ISerializer& UNUSED(serialize)) override
66 : {
67 : // TODO: should we do anything here?
68 : // or should we expect other components to reinitialise us
69 : // after deserialization?
70 0 : }
71 :
72 0 : void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize)) override
73 : {
74 0 : Init(paramNode);
75 0 : }
76 :
77 0 : void HandleMessage(const CMessage& msg, bool UNUSED(global)) override
78 : {
79 0 : switch (msg.GetType())
80 : {
81 0 : case MT_Interpolate:
82 : {
83 0 : PROFILE("OverlayRenderer::Interpolate");
84 0 : const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg);
85 0 : Interpolate(msgData.deltaSimTime, msgData.offset);
86 0 : break;
87 : }
88 0 : case MT_RenderSubmit:
89 : {
90 0 : PROFILE("OverlayRenderer::RenderSubmit");
91 0 : const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg);
92 0 : RenderSubmit(msgData.collector);
93 0 : break;
94 : }
95 : }
96 0 : }
97 :
98 : /*
99 : * Must be called whenever the size of m_Sprites changes,
100 : * to determine whether we need to respond to rendering messages.
101 : */
102 0 : void UpdateMessageSubscriptions()
103 : {
104 0 : bool needRender = !m_Sprites.empty();
105 :
106 0 : GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_Interpolate, this, needRender);
107 0 : GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_RenderSubmit, this, needRender);
108 0 : }
109 :
110 0 : void Reset() override
111 : {
112 0 : m_Sprites.clear();
113 0 : m_SpriteOffsets.clear();
114 :
115 0 : UpdateMessageSubscriptions();
116 0 : }
117 :
118 0 : void AddSprite(const VfsPath& textureName, const CFixedVector2D& corner0, const CFixedVector2D& corner1, const CFixedVector3D& position, const std::string& color) override
119 : {
120 0 : CColor colorObj(1.0f, 1.0f, 1.0f, 1.0f);
121 0 : if (!colorObj.ParseString(color, 1))
122 0 : LOGERROR("OverlayRenderer: Error parsing '%s'", color);
123 :
124 0 : CTextureProperties textureProps(textureName);
125 :
126 0 : SOverlaySprite sprite;
127 0 : sprite.m_Texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
128 0 : sprite.m_X0 = corner0.X.ToFloat();
129 0 : sprite.m_Y0 = corner0.Y.ToFloat();
130 0 : sprite.m_X1 = corner1.X.ToFloat();
131 0 : sprite.m_Y1 = corner1.Y.ToFloat();
132 0 : sprite.m_Color = colorObj;
133 :
134 0 : m_Sprites.push_back(sprite);
135 0 : m_SpriteOffsets.push_back(CVector3D(position));
136 :
137 0 : UpdateMessageSubscriptions();
138 0 : }
139 :
140 0 : void Interpolate(float UNUSED(frameTime), float frameOffset)
141 : {
142 : // Skip all the following computations if we have no sprites
143 0 : if (m_Sprites.empty())
144 : {
145 0 : m_Enabled = false;
146 0 : return;
147 : }
148 :
149 : // Disable rendering of the unit if it has no position
150 0 : CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
151 0 : if (!cmpPosition || !cmpPosition->IsInWorld())
152 : {
153 0 : m_Enabled = false;
154 0 : return;
155 : }
156 :
157 : // Find the precise position of the unit
158 0 : CMatrix3D transform(cmpPosition->GetInterpolatedTransform(frameOffset));
159 0 : CVector3D position(transform.GetTranslation());
160 :
161 : // Move all the sprites to the desired offset relative to the unit
162 0 : for (size_t i = 0; i < m_Sprites.size(); ++i)
163 0 : m_Sprites[i].m_Position = position + m_SpriteOffsets[i];
164 :
165 0 : m_Enabled = true;
166 : }
167 :
168 0 : void RenderSubmit(SceneCollector& collector)
169 : {
170 0 : if (!m_Enabled || !ICmpOverlayRenderer::m_OverrideVisible)
171 0 : return;
172 :
173 0 : for (size_t i = 0; i < m_Sprites.size(); ++i)
174 0 : collector.Submit(&m_Sprites[i]);
175 : }
176 : };
177 :
178 119 : REGISTER_COMPONENT_TYPE(OverlayRenderer)
|