Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/simulation2/components/CCmpSelectable.cpp
Show First 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | static void ClassInit(CComponentManager& componentManager) | ||||
componentManager.SubscribeToMessageType(MT_TerrainChanged); | componentManager.SubscribeToMessageType(MT_TerrainChanged); | ||||
componentManager.SubscribeToMessageType(MT_WaterChanged); | componentManager.SubscribeToMessageType(MT_WaterChanged); | ||||
} | } | ||||
DEFAULT_COMPONENT_ALLOCATOR(Selectable) | DEFAULT_COMPONENT_ALLOCATOR(Selectable) | ||||
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) | ||||
{ | { | ||||
m_Color = CColor(0, 0, 0, m_FadeBaselineAlpha); | m_Color = CColor(0, 0, 0, m_FadeBaselineAlpha); | ||||
} | } | ||||
~CCmpSelectable() | ~CCmpSelectable() | ||||
{ | { | ||||
delete m_DebugBoundingBoxOverlay; | delete m_DebugBoundingBoxOverlay; | ||||
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() | ||||
{ | { | ||||
return | return | ||||
"<a:help>Allows this entity to be selected by the player.</a:help>" | "<a:help>Allows this entity to be selected by the player.</a:help>" | ||||
"<a:example/>" | "<a:example/>" | ||||
"<optional>" | "<optional>" | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | if (m_AlwaysVisible && !selected) | ||||
m_Color.r += (max - m_Color.r) * RGB_DESATURATION; | m_Color.r += (max - m_Color.r) * RGB_DESATURATION; | ||||
m_Color.g += (max - m_Color.g) * RGB_DESATURATION; | m_Color.g += (max - m_Color.g) * RGB_DESATURATION; | ||||
m_Color.b += (max - m_Color.b) * RGB_DESATURATION; | m_Color.b += (max - m_Color.b) * RGB_DESATURATION; | ||||
} | } | ||||
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); | ||||
// set up fading from the current value (as the baseline) to the target value | // set up fading from the current value (as the baseline) to the target value | ||||
m_FadeBaselineAlpha = m_Color.a; | m_FadeBaselineAlpha = m_Color.a; | ||||
m_FadeDeltaAlpha = alpha - m_FadeBaselineAlpha; | m_FadeDeltaAlpha = alpha - m_FadeBaselineAlpha; | ||||
m_FadeProgress = 0.f; | m_FadeProgress = 0.f; | ||||
Show All 12 Lines | virtual bool IsEditorOnly() const | ||||
return m_EditorOnly; | return m_EditorOnly; | ||||
} | } | ||||
void RenderSubmit(SceneCollector& collector); | void RenderSubmit(SceneCollector& collector); | ||||
/** | /** | ||||
* 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 | ||||
* using one) is up-to-date and ready to be submitted to the next rendering run. | * using one) is up-to-date and ready to be submitted to the next rendering run. | ||||
*/ | */ | ||||
void UpdateDynamicOverlay(float frameOffset); | void UpdateDynamicOverlay(float frameOffset); | ||||
/// Explicitly invalidates the static overlay. | /// Explicitly invalidates the static overlay. | ||||
void InvalidateStaticOverlay(); | void InvalidateStaticOverlay(); | ||||
/** | /** | ||||
* Subscribe/unsubscribe to MT_Interpolate, MT_RenderSubmit, depending on | * Subscribe/unsubscribe to MT_Interpolate, MT_RenderSubmit, depending on | ||||
* whether we will do any actual work when receiving them. (This is to avoid | * whether we will do any actual work when receiving them. (This is to avoid | ||||
* the performance cost of receiving messages in the typical case when the | * the performance cost of receiving messages in the typical case when the | ||||
* entity is not selected.) | * entity is not selected.) | ||||
* | * | ||||
* Must be called after changing m_Visible, m_FadeDeltaAlpha, m_Color.a | * Must be called after changing m_Visible, m_FadeDeltaAlpha, m_Color.a | ||||
*/ | */ | ||||
void UpdateMessageSubscriptions(); | void UpdateMessageSubscriptions(); | ||||
/** | /** | ||||
* Delete all range overlays. | |||||
*/ | |||||
void ResetRangeOverlays(); | |||||
/** | |||||
* Set the color of the current owner. | * Set the color of the current owner. | ||||
*/ | */ | ||||
void UpdatePlayerColor(); | void UpdatePlayerColor(); | ||||
private: | private: | ||||
SOverlayDescriptor m_OverlayDescriptor; | SOverlayDescriptor m_OverlayDescriptor; | ||||
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; | ||||
bool m_EnabledInterpolate; | bool m_EnabledInterpolate; | ||||
bool m_EnabledRenderSubmit; | bool m_EnabledRenderSubmit; | ||||
// Whether the selectable will be rendered. | // Whether the selectable will be rendered. | ||||
bool m_Visible; | bool m_Visible; | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | if (m_FadeDeltaAlpha != 0.f) | ||||
else | else | ||||
{ | { | ||||
m_Color.a = Ease::QuartOut(m_FadeProgress, m_FadeBaselineAlpha, m_FadeDeltaAlpha, FADE_DURATION); | m_Color.a = Ease::QuartOut(m_FadeProgress, m_FadeBaselineAlpha, m_FadeDeltaAlpha, FADE_DURATION); | ||||
} | } | ||||
} | } | ||||
// 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; | ||||
} | } | ||||
case MT_OwnershipChanged: | case MT_OwnershipChanged: | ||||
{ | { | ||||
const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); | const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | void CCmpSelectable::UpdatePlayerColor() | ||||
// Update the highlight color, while keeping the current alpha target value intact | // Update the highlight color, while keeping the current alpha target value intact | ||||
// (i.e. baseline + delta), so that any ongoing fades simply continue with the new color. | // (i.e. baseline + delta), so that any ongoing fades simply continue with the new color. | ||||
color.a = m_FadeBaselineAlpha + m_FadeDeltaAlpha; | color.a = m_FadeBaselineAlpha + m_FadeDeltaAlpha; | ||||
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; | ||||
bool needRenderSubmit = false; | bool needRenderSubmit = false; | ||||
if (m_FadeDeltaAlpha != 0.f || m_Color.a > 0) | if (m_FadeDeltaAlpha != 0.f || m_Color.a > 0) | ||||
needInterpolate = true; | needInterpolate = true; | ||||
Show All 13 Lines | void CCmpSelectable::UpdateMessageSubscriptions() | ||||
} | } | ||||
} | } | ||||
void CCmpSelectable::InvalidateStaticOverlay() | 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; | ||||
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | ||||
CmpPtr<ICmpFootprint> cmpFootprint(GetEntityHandle()); | CmpPtr<ICmpFootprint> cmpFootprint(GetEntityHandle()); | ||||
if (!cmpFootprint || !cmpPosition || !cmpPosition->IsInWorld()) | if (!cmpFootprint || !cmpPosition || !cmpPosition->IsInWorld()) | ||||
return; | return; | ||||
ICmpFootprint::EShape fpShape; | ICmpFootprint::EShape fpShape; | ||||
entity_pos_t fpSize0_fixed, fpSize1_fixed, fpHeight_fixed; | entity_pos_t fpSize0_fixed, fpSize1_fixed, fpHeight_fixed; | ||||
cmpFootprint->GetShape(fpShape, fpSize0_fixed, fpSize1_fixed, fpHeight_fixed); | cmpFootprint->GetShape(fpShape, fpSize0_fixed, fpSize1_fixed, fpHeight_fixed); | ||||
float rotY; | float rotY; | ||||
CVector2D origin; | CVector2D origin; | ||||
cmpPosition->GetInterpolatedPosition2D(frameOffset, origin.X, origin.Y, rotY); | cmpPosition->GetInterpolatedPosition2D(frameOffset, origin.X, origin.Y, rotY); | ||||
overlay.m_SimContext = &GetSimContext(); | overlay.m_SimContext = &GetSimContext(); | ||||
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) | ||||
{ | { | ||||
// Dynamic overlay lines are allocated once and never deleted. Since they are expected to change frequently, | // Dynamic overlay lines are allocated once and never deleted. Since they are expected to change frequently, | ||||
// they are assumed dirty on every call to this function, and we should therefore use this function more | // they are assumed dirty on every call to this function, and we should therefore use this function more | ||||
// thoughtfully than calling it right before every frame render. | // thoughtfully than calling it right before every frame render. | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | switch (m_OverlayDescriptor.m_Type) | ||||
case STATIC_OUTLINE: | case STATIC_OUTLINE: | ||||
{ | { | ||||
if (!m_BuildingOverlay) | if (!m_BuildingOverlay) | ||||
{ | { | ||||
// Static overlays are allocated once and not updated until they are explicitly deleted again | // Static overlays are allocated once and not updated until they are explicitly deleted again | ||||
// (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); | ||||
} | } | ||||
break; | break; | ||||
case DYNAMIC_QUAD: | case DYNAMIC_QUAD: | ||||
{ | { | ||||
if (m_UnitOverlay) | if (m_UnitOverlay) | ||||
collector.Submit(m_UnitOverlay); | collector.Submit(m_UnitOverlay); | ||||
} | } | ||||
break; | break; | ||||
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 | ||||
// that the debug overlays respond immediately to deselection without delay from fading out. | // that the debug overlays respond immediately to deselection without delay from fading out. | ||||
if (m_FadeBaselineAlpha + m_FadeDeltaAlpha > 0) | if (m_FadeBaselineAlpha + m_FadeDeltaAlpha > 0) | ||||
{ | { | ||||
if (ICmpSelectable::ms_EnableDebugOverlays) | if (ICmpSelectable::ms_EnableDebugOverlays) | ||||
{ | { | ||||
Show All 29 Lines |
Wildfire Games · Phabricator