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

View File

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

View File

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

View File

@ -150,6 +150,9 @@ COMPONENT(RallyPointRenderer)
INTERFACE(RangeManager)
COMPONENT(RangeManager)
INTERFACE(RangeOverlayRenderer)
COMPONENT(RangeOverlayRenderer)
INTERFACE(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()
: 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_Selected(false), m_Cached(false), m_Visible(false)
{
@ -78,8 +78,6 @@ public:
delete m_DebugSelectionBoxOverlay;
delete m_BuildingOverlay;
delete m_UnitOverlay;
for (RangeOverlayData& rangeOverlay : m_RangeOverlayData)
delete rangeOverlay.second;
}
static std::string GetSchema()
@ -194,22 +192,6 @@ public:
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)
{
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.
*/
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
@ -259,11 +241,6 @@ public:
*/
void UpdateMessageSubscriptions();
/**
* Delete all range overlays.
*/
void ResetRangeOverlays();
/**
* Set the color of the current owner.
*/
@ -274,10 +251,6 @@ private:
SOverlayTexturedLine* m_BuildingOverlay;
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_DebugSelectionBoxOverlay;
@ -345,17 +318,8 @@ void CCmpSelectable::HandleMessage(const CMessage& msg, bool UNUSED(global))
// update dynamic overlay only when visible
if (m_Color.a > 0)
{
UpdateDynamicOverlay(msgData.offset);
for (RangeOverlayData& rangeOverlay : m_RangeOverlayData)
{
delete rangeOverlay.second;
rangeOverlay.second = new SOverlayTexturedLine;
UpdateTexturedLineOverlay(&rangeOverlay.first, *rangeOverlay.second, msgData.offset, false);
}
}
UpdateMessageSubscriptions();
break;
@ -439,15 +403,6 @@ void CCmpSelectable::UpdatePlayerColor()
SetSelectionHighlight(color, m_Selected);
}
void CCmpSelectable::ResetRangeOverlays()
{
for (RangeOverlayData& rangeOverlay : m_RangeOverlayData)
delete rangeOverlay.second;
m_RangeOverlayData.clear();
UpdateMessageSubscriptions();
}
void CCmpSelectable::UpdateMessageSubscriptions()
{
bool needInterpolate = false;
@ -477,7 +432,7 @@ void CCmpSelectable::InvalidateStaticOverlay()
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())
return;
@ -499,10 +454,10 @@ void CCmpSelectable::UpdateTexturedLineOverlay(const SOverlayDescriptor* overlay
overlay.m_Color = m_Color;
overlay.CreateOverlayTexture(overlayDescriptor);
if (buildingOverlay && fpShape == ICmpFootprint::SQUARE)
if (fpShape == ICmpFootprint::SQUARE)
SimRender::ConstructTexturedLineBox(overlay, origin, cmpPosition->GetRotation(), fpSize0_fixed.ToFloat(), fpSize1_fixed.ToFloat());
else
SimRender::ConstructTexturedLineCircle(overlay, origin, buildingOverlay ? fpSize0_fixed.ToFloat() : overlayDescriptor->m_Radius);
SimRender::ConstructTexturedLineCircle(overlay, origin, fpSize0_fixed.ToFloat());
}
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
// normal gameplay, this saves us doing all the work below on each frame.
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
collector.Submit(m_BuildingOverlay);
@ -630,10 +585,6 @@ void CCmpSelectable::RenderSubmit(SceneCollector& collector)
default:
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

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)
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)
bool ICmpSelectable::ms_EnableDebugOverlays = false;

View File

@ -38,16 +38,6 @@ public:
*/
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.
* @param visible Whether the selectable should be visible.