1
0
forked from 0ad/0ad

Render the range visualization of auras, heal and attack component in a separate RangeOverlayRenderer component instead of abusing Selectable for that.

This also allows non-selectable entities like building previews to cast
range visualizations.

Patch By: Sandarac
Differential Revision: https://code.wildfiregames.com/D555
Refs #3915, #4349, ee5bb1fd61 / D238.
Comments By: Vladislav
This was SVN commit r20622.
This commit is contained in:
elexis 2017-12-10 02:41:08 +00:00
parent 13ad114dd6
commit 5fbb224dc0
10 changed files with 297 additions and 71 deletions

View File

@ -70,11 +70,11 @@ RangeVisualization.prototype.SetEnabled = function(enabled, enabledRangeTypes, f
RangeVisualization.prototype.RegenerateRangeVisualizations = function(forceUpdate) RangeVisualization.prototype.RegenerateRangeVisualizations = function(forceUpdate)
{ {
let cmpSelectable = Engine.QueryInterface(this.entity, IID_Selectable); let cmpRangeOverlayRenderer = Engine.QueryInterface(this.entity, IID_RangeOverlayRenderer);
if (!cmpSelectable) if (!cmpRangeOverlayRenderer)
return; return;
cmpSelectable.ResetRangeOverlays(); cmpRangeOverlayRenderer.ResetRangeOverlays();
if (!this.enabled && !forceUpdate) if (!this.enabled && !forceUpdate)
return; return;
@ -83,7 +83,7 @@ RangeVisualization.prototype.RegenerateRangeVisualizations = function(forceUpdat
for (let rangeOverlayType of this.rangeVisualizations.keys()) for (let rangeOverlayType of this.rangeVisualizations.keys())
if (this.enabledRangeTypes[rangeOverlayType]) if (this.enabledRangeTypes[rangeOverlayType])
for (let rangeOverlay of this.rangeVisualizations.get(rangeOverlayType)) for (let rangeOverlay of this.rangeVisualizations.get(rangeOverlayType))
cmpSelectable.AddRangeOverlay( cmpRangeOverlayRenderer.AddRangeOverlay(
rangeOverlay.radius, rangeOverlay.radius,
rangeOverlay.texture, rangeOverlay.texture,
rangeOverlay.textureMask, rangeOverlay.textureMask,

View File

@ -100,6 +100,7 @@
<LineEndCap>round</LineEndCap> <LineEndCap>round</LineEndCap>
<LinePassabilityClass>default</LinePassabilityClass> <LinePassabilityClass>default</LinePassabilityClass>
</RallyPointRenderer> </RallyPointRenderer>
<RangeOverlayRenderer/>
<RangeVisualization/> <RangeVisualization/>
<Repairable> <Repairable>
<RepairTimeRatio>2.0</RepairTimeRatio> <RepairTimeRatio>2.0</RepairTimeRatio>

View File

@ -66,6 +66,7 @@
<DisableBlockPathfinding>false</DisableBlockPathfinding> <DisableBlockPathfinding>false</DisableBlockPathfinding>
</Obstruction> </Obstruction>
<OverlayRenderer/> <OverlayRenderer/>
<RangeOverlayRenderer/>
<RangeVisualization/> <RangeVisualization/>
<ResourceGatherer> <ResourceGatherer>
<MaxDistance>2.0</MaxDistance> <MaxDistance>2.0</MaxDistance>

View File

@ -150,6 +150,9 @@ COMPONENT(RallyPointRenderer)
INTERFACE(RangeManager) INTERFACE(RangeManager)
COMPONENT(RangeManager) COMPONENT(RangeManager)
INTERFACE(RangeOverlayRenderer)
COMPONENT(RangeOverlayRenderer)
INTERFACE(Selectable) INTERFACE(Selectable)
COMPONENT(Selectable) COMPONENT(Selectable)

View File

@ -0,0 +1,216 @@
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "ICmpRangeOverlayRenderer.h"
#include "graphics/Overlay.h"
#include "graphics/TextureManager.h"
#include "renderer/Renderer.h"
#include "simulation2/MessageTypes.h"
#include "simulation2/components/ICmpPlayer.h"
#include "simulation2/components/ICmpPlayerManager.h"
#include "simulation2/components/ICmpPosition.h"
#include "simulation2/helpers/Render.h"
#include "simulation2/system/Component.h"
class CCmpRangeOverlayRenderer : public ICmpRangeOverlayRenderer
{
public:
static void ClassInit(CComponentManager& componentManager)
{
componentManager.SubscribeToMessageType(MT_OwnershipChanged);
}
DEFAULT_COMPONENT_ALLOCATOR(RangeOverlayRenderer)
CCmpRangeOverlayRenderer() : m_RangeOverlayData()
{
m_Color = CColor(0, 0, 0, 0);
}
~CCmpRangeOverlayRenderer()
{
for (const RangeOverlayData& rangeOverlay : m_RangeOverlayData)
delete rangeOverlay.second;
}
static std::string GetSchema()
{
return "<a:component type='system'/><empty/>";
}
virtual void Init(const CParamNode& UNUSED(paramNode))
{
m_EnabledInterpolate = false;
m_EnabledRenderSubmit = false;
m_Enabled = false;
UpdateMessageSubscriptions();
}
virtual void Deinit() { }
virtual void Serialize(ISerializer& UNUSED(serialize))
{
}
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& UNUSED(deserialize))
{
Init(paramNode);
}
void ResetRangeOverlays()
{
for (const RangeOverlayData& rangeOverlay : m_RangeOverlayData)
delete rangeOverlay.second;
m_RangeOverlayData.clear();
UpdateMessageSubscriptions();
m_Enabled = false;
}
virtual void AddRangeOverlay(float radius, const std::string& texture, const std::string& textureMask, float thickness)
{
if (!CRenderer::IsInitialised())
return;
SOverlayDescriptor rangeOverlayDescriptor;
SOverlayTexturedLine* rangeOverlay = nullptr;
rangeOverlayDescriptor.m_Radius = radius;
rangeOverlayDescriptor.m_LineTexture = CStrIntern(TEXTUREBASEPATH + texture);
rangeOverlayDescriptor.m_LineTextureMask = CStrIntern(TEXTUREBASEPATH + textureMask);
rangeOverlayDescriptor.m_LineThickness = thickness;
m_RangeOverlayData.push_back({ rangeOverlayDescriptor, rangeOverlay });
m_Enabled = true;
UpdateMessageSubscriptions();
}
void HandleMessage(const CMessage& msg, bool UNUSED(global))
{
switch (msg.GetType())
{
case MT_Interpolate:
{
const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg);
for (RangeOverlayData& rangeOverlay : m_RangeOverlayData)
{
delete rangeOverlay.second;
rangeOverlay.second = new SOverlayTexturedLine;
UpdateRangeOverlay(&rangeOverlay.first, *rangeOverlay.second, msgData.offset);
}
UpdateMessageSubscriptions();
break;
}
case MT_OwnershipChanged:
{
const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg);
if (msgData.to == INVALID_PLAYER)
break;
CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSystemEntity());
if (!cmpPlayerManager)
break;
CmpPtr<ICmpPlayer> cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(msgData.to));
if (!cmpPlayer)
break;
CColor color = cmpPlayer->GetColor();
m_Color = color;
break;
}
case MT_RenderSubmit:
{
const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg);
RenderSubmit(msgData.collector);
break;
}
}
}
void UpdateMessageSubscriptions()
{
bool needInterpolate = false;
bool needRenderSubmit = false;
if (m_Enabled)
{
needInterpolate = true;
needRenderSubmit = true;
}
if (needInterpolate != m_EnabledInterpolate)
{
GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_Interpolate, this, needInterpolate);
m_EnabledInterpolate = needInterpolate;
m_Enabled = needInterpolate;
}
if (needRenderSubmit != m_EnabledRenderSubmit)
{
GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_RenderSubmit, this, needRenderSubmit);
m_EnabledRenderSubmit = needRenderSubmit;
m_Enabled = needRenderSubmit;
}
}
void RenderSubmit(SceneCollector& collector)
{
if (!m_RangeOverlayData.size())
return;
for (const RangeOverlayData& rangeOverlay : m_RangeOverlayData)
if (rangeOverlay.second)
collector.Submit(rangeOverlay.second);
}
private:
void UpdateRangeOverlay(const SOverlayDescriptor* overlayDescriptor, SOverlayTexturedLine& overlay, float frameOffset)
{
if (!CRenderer::IsInitialised())
return;
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
if (!cmpPosition || !cmpPosition->IsInWorld())
return;
float rotY;
CVector2D origin;
cmpPosition->GetInterpolatedPosition2D(frameOffset, origin.X, origin.Y, rotY);
overlay.m_SimContext = &GetSimContext();
overlay.m_Color = m_Color;
overlay.CreateOverlayTexture(overlayDescriptor);
SimRender::ConstructTexturedLineCircle(overlay, origin, overlayDescriptor->m_Radius);
}
bool m_EnabledInterpolate;
bool m_EnabledRenderSubmit;
bool m_Enabled;
const char* TEXTUREBASEPATH = "art/textures/selection/";
typedef std::pair<SOverlayDescriptor, SOverlayTexturedLine*> RangeOverlayData;
std::vector<RangeOverlayData> m_RangeOverlayData;
CColor m_Color;
};
REGISTER_COMPONENT_TYPE(RangeOverlayRenderer)

View File

@ -65,7 +65,7 @@ public:
CCmpSelectable() CCmpSelectable()
: m_DebugBoundingBoxOverlay(NULL), m_DebugSelectionBoxOverlay(NULL), : m_DebugBoundingBoxOverlay(NULL), m_DebugSelectionBoxOverlay(NULL),
m_BuildingOverlay(NULL), m_UnitOverlay(NULL), m_RangeOverlayData(), m_BuildingOverlay(NULL), m_UnitOverlay(NULL),
m_FadeBaselineAlpha(0.f), m_FadeDeltaAlpha(0.f), m_FadeProgress(0.f), m_FadeBaselineAlpha(0.f), m_FadeDeltaAlpha(0.f), m_FadeProgress(0.f),
m_Selected(false), m_Cached(false), m_Visible(false) m_Selected(false), m_Cached(false), m_Visible(false)
{ {
@ -78,8 +78,6 @@ public:
delete m_DebugSelectionBoxOverlay; delete m_DebugSelectionBoxOverlay;
delete m_BuildingOverlay; delete m_BuildingOverlay;
delete m_UnitOverlay; delete m_UnitOverlay;
for (RangeOverlayData& rangeOverlay : m_RangeOverlayData)
delete rangeOverlay.second;
} }
static std::string GetSchema() static std::string GetSchema()
@ -194,22 +192,6 @@ public:
SetSelectionHighlightAlpha(color.a); SetSelectionHighlightAlpha(color.a);
} }
virtual void AddRangeOverlay(float radius, const std::string& texture, const std::string& textureMask, float thickness)
{
if (!CRenderer::IsInitialised())
return;
SOverlayDescriptor rangeOverlayDescriptor;
SOverlayTexturedLine* rangeOverlay = nullptr;
rangeOverlayDescriptor.m_Radius = radius;
rangeOverlayDescriptor.m_LineTexture = CStrIntern(TEXTUREBASEPATH + texture);
rangeOverlayDescriptor.m_LineTextureMask = CStrIntern(TEXTUREBASEPATH + textureMask);
rangeOverlayDescriptor.m_LineThickness = thickness;
m_RangeOverlayData.push_back({rangeOverlayDescriptor, rangeOverlay});
}
virtual void SetSelectionHighlightAlpha(float alpha) virtual void SetSelectionHighlightAlpha(float alpha)
{ {
alpha = std::max(m_AlphaMin, alpha); alpha = std::max(m_AlphaMin, alpha);
@ -238,7 +220,7 @@ public:
/** /**
* Draw a textured line overlay. The selection overlays for structures are based solely on footprint shape. * Draw a textured line overlay. The selection overlays for structures are based solely on footprint shape.
*/ */
void UpdateTexturedLineOverlay(const SOverlayDescriptor* overlayDescriptor, SOverlayTexturedLine& overlay, float frameOffset, bool buildingOverlay); void UpdateTexturedLineOverlay(const SOverlayDescriptor* overlayDescriptor, SOverlayTexturedLine& overlay, float frameOffset);
/** /**
* Called from the interpolation handler; responsible for ensuring the dynamic overlay (provided we're * Called from the interpolation handler; responsible for ensuring the dynamic overlay (provided we're
@ -259,11 +241,6 @@ public:
*/ */
void UpdateMessageSubscriptions(); void UpdateMessageSubscriptions();
/**
* Delete all range overlays.
*/
void ResetRangeOverlays();
/** /**
* Set the color of the current owner. * Set the color of the current owner.
*/ */
@ -274,10 +251,6 @@ private:
SOverlayTexturedLine* m_BuildingOverlay; SOverlayTexturedLine* m_BuildingOverlay;
SOverlayQuad* m_UnitOverlay; SOverlayQuad* m_UnitOverlay;
// Holds the data for all range overlays
typedef std::pair<SOverlayDescriptor, SOverlayTexturedLine*> RangeOverlayData;
std::vector<RangeOverlayData> m_RangeOverlayData;
SOverlayLine* m_DebugBoundingBoxOverlay; SOverlayLine* m_DebugBoundingBoxOverlay;
SOverlayLine* m_DebugSelectionBoxOverlay; SOverlayLine* m_DebugSelectionBoxOverlay;
@ -345,17 +318,8 @@ void CCmpSelectable::HandleMessage(const CMessage& msg, bool UNUSED(global))
// update dynamic overlay only when visible // update dynamic overlay only when visible
if (m_Color.a > 0) if (m_Color.a > 0)
{
UpdateDynamicOverlay(msgData.offset); UpdateDynamicOverlay(msgData.offset);
for (RangeOverlayData& rangeOverlay : m_RangeOverlayData)
{
delete rangeOverlay.second;
rangeOverlay.second = new SOverlayTexturedLine;
UpdateTexturedLineOverlay(&rangeOverlay.first, *rangeOverlay.second, msgData.offset, false);
}
}
UpdateMessageSubscriptions(); UpdateMessageSubscriptions();
break; break;
@ -439,15 +403,6 @@ void CCmpSelectable::UpdatePlayerColor()
SetSelectionHighlight(color, m_Selected); SetSelectionHighlight(color, m_Selected);
} }
void CCmpSelectable::ResetRangeOverlays()
{
for (RangeOverlayData& rangeOverlay : m_RangeOverlayData)
delete rangeOverlay.second;
m_RangeOverlayData.clear();
UpdateMessageSubscriptions();
}
void CCmpSelectable::UpdateMessageSubscriptions() void CCmpSelectable::UpdateMessageSubscriptions()
{ {
bool needInterpolate = false; bool needInterpolate = false;
@ -477,7 +432,7 @@ void CCmpSelectable::InvalidateStaticOverlay()
SAFE_DELETE(m_BuildingOverlay); SAFE_DELETE(m_BuildingOverlay);
} }
void CCmpSelectable::UpdateTexturedLineOverlay(const SOverlayDescriptor* overlayDescriptor, SOverlayTexturedLine& overlay, float frameOffset, bool buildingOverlay) void CCmpSelectable::UpdateTexturedLineOverlay(const SOverlayDescriptor* overlayDescriptor, SOverlayTexturedLine& overlay, float frameOffset)
{ {
if (!CRenderer::IsInitialised()) if (!CRenderer::IsInitialised())
return; return;
@ -499,10 +454,10 @@ void CCmpSelectable::UpdateTexturedLineOverlay(const SOverlayDescriptor* overlay
overlay.m_Color = m_Color; overlay.m_Color = m_Color;
overlay.CreateOverlayTexture(overlayDescriptor); overlay.CreateOverlayTexture(overlayDescriptor);
if (buildingOverlay && fpShape == ICmpFootprint::SQUARE) if (fpShape == ICmpFootprint::SQUARE)
SimRender::ConstructTexturedLineBox(overlay, origin, cmpPosition->GetRotation(), fpSize0_fixed.ToFloat(), fpSize1_fixed.ToFloat()); SimRender::ConstructTexturedLineBox(overlay, origin, cmpPosition->GetRotation(), fpSize0_fixed.ToFloat(), fpSize1_fixed.ToFloat());
else else
SimRender::ConstructTexturedLineCircle(overlay, origin, buildingOverlay ? fpSize0_fixed.ToFloat() : overlayDescriptor->m_Radius); SimRender::ConstructTexturedLineCircle(overlay, origin, fpSize0_fixed.ToFloat());
} }
void CCmpSelectable::UpdateDynamicOverlay(float frameOffset) void CCmpSelectable::UpdateDynamicOverlay(float frameOffset)
@ -615,7 +570,7 @@ void CCmpSelectable::RenderSubmit(SceneCollector& collector)
// (see InvalidateStaticOverlay). Since they are expected to change rarely (if ever) during // (see InvalidateStaticOverlay). Since they are expected to change rarely (if ever) during
// normal gameplay, this saves us doing all the work below on each frame. // normal gameplay, this saves us doing all the work below on each frame.
m_BuildingOverlay = new SOverlayTexturedLine; m_BuildingOverlay = new SOverlayTexturedLine;
UpdateTexturedLineOverlay(&m_OverlayDescriptor, *m_BuildingOverlay, 0, true); UpdateTexturedLineOverlay(&m_OverlayDescriptor, *m_BuildingOverlay, 0);
} }
m_BuildingOverlay->m_Color = m_Color; // done separately so alpha changes don't require a full update call m_BuildingOverlay->m_Color = m_Color; // done separately so alpha changes don't require a full update call
collector.Submit(m_BuildingOverlay); collector.Submit(m_BuildingOverlay);
@ -630,10 +585,6 @@ void CCmpSelectable::RenderSubmit(SceneCollector& collector)
default: default:
break; break;
} }
for (const RangeOverlayData& rangeOverlay : m_RangeOverlayData)
if (rangeOverlay.second)
collector.Submit(rangeOverlay.second);
} }
// Render bounding box debug overlays if we have a positive target alpha value. This ensures // Render bounding box debug overlays if we have a positive target alpha value. This ensures

View File

@ -0,0 +1,26 @@
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "ICmpRangeOverlayRenderer.h"
#include "simulation2/system/InterfaceScripted.h"
BEGIN_INTERFACE_WRAPPER(RangeOverlayRenderer)
DEFINE_INTERFACE_METHOD_4("AddRangeOverlay", void, ICmpRangeOverlayRenderer, AddRangeOverlay, float, std::string, std::string, float)
DEFINE_INTERFACE_METHOD_0("ResetRangeOverlays", void, ICmpRangeOverlayRenderer, ResetRangeOverlays)
END_INTERFACE_WRAPPER(RangeOverlayRenderer)

View File

@ -0,0 +1,40 @@
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_ICMPRANGEOVERLAYRENDERER
#define INCLUDED_ICMPRANGEOVERLAYRENDERER
#include "ps/CStrIntern.h"
#include "simulation2/system/Interface.h"
class ICmpRangeOverlayRenderer : public IComponent
{
public:
/**
* Add a range overlay to this entity, for example for an aura or attack.
*/
virtual void AddRangeOverlay(float radius, const std::string& texture, const std::string& textureMask, float thickness) = 0;
/**
* Delete all range overlays.
*/
virtual void ResetRangeOverlays() = 0;
DECLARE_INTERFACE_TYPE(RangeOverlayRenderer)
};
#endif // INCLUDED_ICMPRANGEOVERLAYRENDERER

View File

@ -25,8 +25,6 @@
BEGIN_INTERFACE_WRAPPER(Selectable) BEGIN_INTERFACE_WRAPPER(Selectable)
DEFINE_INTERFACE_METHOD_2("SetSelectionHighlight", void, ICmpSelectable, SetSelectionHighlight, CColor, bool) DEFINE_INTERFACE_METHOD_2("SetSelectionHighlight", void, ICmpSelectable, SetSelectionHighlight, CColor, bool)
DEFINE_INTERFACE_METHOD_4("AddRangeOverlay", void, ICmpSelectable, AddRangeOverlay, float, std::string, std::string, float)
DEFINE_INTERFACE_METHOD_0("ResetRangeOverlays", void, ICmpSelectable, ResetRangeOverlays)
END_INTERFACE_WRAPPER(Selectable) END_INTERFACE_WRAPPER(Selectable)
bool ICmpSelectable::ms_EnableDebugOverlays = false; bool ICmpSelectable::ms_EnableDebugOverlays = false;

View File

@ -38,16 +38,6 @@ public:
*/ */
virtual void SetSelectionHighlight(const CColor& color, bool selected) = 0; virtual void SetSelectionHighlight(const CColor& color, bool selected) = 0;
/**
* Add a range overlay to this entity, for example for an aura or attack.
*/
virtual void AddRangeOverlay(float radius, const std::string& texture, const std::string& textureMask, float thickness) = 0;
/**
* Delete all range overlays.
*/
virtual void ResetRangeOverlays() = 0;
/** /**
* Enables or disables rendering of an entity's selectable. * Enables or disables rendering of an entity's selectable.
* @param visible Whether the selectable should be visible. * @param visible Whether the selectable should be visible.