mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
Improve envelope evaluation and validation
Call `EnvelopeEval` functions directly instead of passing them and their arguments to `CRenderTools::RenderTilemap` and `CRenderTools::RenderTileRectangle`. Only evaluate color envelopes for tiles layers once instead of separately for the opaque and transparent passes. Only evaluate relevant number of envelope channels instead of always evaluating all channels. Avoid unnecessary calculations by only evaluating position envelopes for quads which are not fully transparent. Fully ignore layer color and envelope color for entities layers, as these cannot be specified in the editor and should not be changeable. Remove duplicate and insufficient checks for invalid envelope index before calling `EnvelopeEval`. Instead, set the correct default for all channels before calling `EnvelopeEval` and only change the result on success. Now, white color will consistently be assumed for invalid color envelopes, zero positions and rotations for invalid position envelopes, and full volume for invalid sound envelopes. Validate number of envelope channels to prevent crashes. When loading maps containing envelopes with invalid number of channels (not equal to 1, 3 or 4), the number of channels of these envelopes is reset to 4 and an error message is displayed, so the mapper can examine all channels' data and transfer it to another envelope if necessary. Closes #7985.
This commit is contained in:
parent
040d7673c6
commit
ab3c6c4353
|
@ -56,18 +56,19 @@ void CMapLayers::EnvelopeUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapLayers::EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Channels, void *pUser)
|
void CMapLayers::EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Result, size_t Channels, void *pUser)
|
||||||
{
|
{
|
||||||
CMapLayers *pThis = (CMapLayers *)pUser;
|
CMapLayers *pThis = (CMapLayers *)pUser;
|
||||||
Channels = ColorRGBA();
|
|
||||||
|
|
||||||
int EnvStart, EnvNum;
|
int EnvStart, EnvNum;
|
||||||
pThis->m_pLayers->Map()->GetType(MAPITEMTYPE_ENVELOPE, &EnvStart, &EnvNum);
|
pThis->m_pLayers->Map()->GetType(MAPITEMTYPE_ENVELOPE, &EnvStart, &EnvNum);
|
||||||
|
|
||||||
if(Env < 0 || Env >= EnvNum)
|
if(Env < 0 || Env >= EnvNum)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const CMapItemEnvelope *pItem = (CMapItemEnvelope *)pThis->m_pLayers->Map()->GetItem(EnvStart + Env);
|
const CMapItemEnvelope *pItem = (CMapItemEnvelope *)pThis->m_pLayers->Map()->GetItem(EnvStart + Env);
|
||||||
|
if(pItem->m_Channels <= 0)
|
||||||
|
return;
|
||||||
|
Channels = minimum<size_t>(Channels, pItem->m_Channels, CEnvPoint::MAX_CHANNELS);
|
||||||
|
|
||||||
CMapBasedEnvelopePointAccess EnvelopePoints(pThis->m_pLayers->Map());
|
CMapBasedEnvelopePointAccess EnvelopePoints(pThis->m_pLayers->Map());
|
||||||
EnvelopePoints.SetPointsRange(pItem->m_StartPoint, pItem->m_NumPoints);
|
EnvelopePoints.SetPointsRange(pItem->m_StartPoint, pItem->m_NumPoints);
|
||||||
|
@ -114,7 +115,7 @@ void CMapLayers::EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Channels
|
||||||
MinTick * TickToNanoSeconds;
|
MinTick * TickToNanoSeconds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CRenderTools::RenderEvalEnvelope(&EnvelopePoints, 4, s_Time + (int64_t)TimeOffsetMillis * std::chrono::nanoseconds(1ms), Channels);
|
CRenderTools::RenderEvalEnvelope(&EnvelopePoints, s_Time + (int64_t)TimeOffsetMillis * std::chrono::nanoseconds(1ms), Result, Channels);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -139,7 +140,7 @@ void CMapLayers::EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Channels
|
||||||
s_Time += CurTime - s_LastLocalTime;
|
s_Time += CurTime - s_LastLocalTime;
|
||||||
s_LastLocalTime = CurTime;
|
s_LastLocalTime = CurTime;
|
||||||
}
|
}
|
||||||
CRenderTools::RenderEvalEnvelope(&EnvelopePoints, 4, s_Time + std::chrono::nanoseconds(std::chrono::milliseconds(TimeOffsetMillis)), Channels);
|
CRenderTools::RenderEvalEnvelope(&EnvelopePoints, s_Time + std::chrono::nanoseconds(std::chrono::milliseconds(TimeOffsetMillis)), Result, Channels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -901,7 +902,7 @@ void CMapLayers::OnMapLoad()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapLayers::RenderTileLayer(int LayerIndex, ColorRGBA &Color, CMapItemLayerTilemap *pTileLayer, CMapItemGroup *pGroup)
|
void CMapLayers::RenderTileLayer(int LayerIndex, const ColorRGBA &Color, CMapItemLayerTilemap *pTileLayer, CMapItemGroup *pGroup)
|
||||||
{
|
{
|
||||||
STileLayerVisuals &Visuals = *m_vpTileLayerVisuals[LayerIndex];
|
STileLayerVisuals &Visuals = *m_vpTileLayerVisuals[LayerIndex];
|
||||||
if(Visuals.m_BufferContainerIndex == -1)
|
if(Visuals.m_BufferContainerIndex == -1)
|
||||||
|
@ -910,12 +911,6 @@ void CMapLayers::RenderTileLayer(int LayerIndex, ColorRGBA &Color, CMapItemLayer
|
||||||
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
||||||
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
||||||
|
|
||||||
ColorRGBA Channels(1.f, 1.f, 1.f, 1.f);
|
|
||||||
if(pTileLayer->m_ColorEnv >= 0)
|
|
||||||
{
|
|
||||||
EnvelopeEval(pTileLayer->m_ColorEnvOffset, pTileLayer->m_ColorEnv, Channels, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
int BorderX0, BorderY0, BorderX1, BorderY1;
|
int BorderX0, BorderY0, BorderX1, BorderY1;
|
||||||
bool DrawBorder = false;
|
bool DrawBorder = false;
|
||||||
|
|
||||||
|
@ -985,11 +980,6 @@ void CMapLayers::RenderTileLayer(int LayerIndex, ColorRGBA &Color, CMapItemLayer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Color.x *= Channels.r;
|
|
||||||
Color.y *= Channels.g;
|
|
||||||
Color.z *= Channels.b;
|
|
||||||
Color.w *= Channels.a;
|
|
||||||
|
|
||||||
int DrawCount = s_vpIndexOffsets.size();
|
int DrawCount = s_vpIndexOffsets.size();
|
||||||
if(DrawCount != 0)
|
if(DrawCount != 0)
|
||||||
{
|
{
|
||||||
|
@ -1277,27 +1267,11 @@ void CMapLayers::RenderQuadLayer(int LayerIndex, CMapItemLayerQuads *pQuadLayer,
|
||||||
{
|
{
|
||||||
CQuad *pQuad = &pQuads[i];
|
CQuad *pQuad = &pQuads[i];
|
||||||
|
|
||||||
ColorRGBA Color(1.f, 1.f, 1.f, 1.f);
|
ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
if(pQuad->m_ColorEnv >= 0)
|
EnvelopeEval(pQuad->m_ColorEnvOffset, pQuad->m_ColorEnv, Color, 4, this);
|
||||||
{
|
|
||||||
EnvelopeEval(pQuad->m_ColorEnvOffset, pQuad->m_ColorEnv, Color, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
float OffsetX = 0;
|
const bool IsFullyTransparent = Color.a <= 0.0f;
|
||||||
float OffsetY = 0;
|
const bool NeedsFlush = QuadsRenderCount == gs_GraphicsMaxQuadsRenderCount || IsFullyTransparent;
|
||||||
float Rot = 0;
|
|
||||||
|
|
||||||
if(pQuad->m_PosEnv >= 0)
|
|
||||||
{
|
|
||||||
ColorRGBA Channels;
|
|
||||||
EnvelopeEval(pQuad->m_PosEnvOffset, pQuad->m_PosEnv, Channels, this);
|
|
||||||
OffsetX = Channels.r;
|
|
||||||
OffsetY = Channels.g;
|
|
||||||
Rot = Channels.b / 180.0f * pi;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool IsFullyTransparent = Color.a <= 0;
|
|
||||||
bool NeedsFlush = QuadsRenderCount == gs_GraphicsMaxQuadsRenderCount || IsFullyTransparent;
|
|
||||||
|
|
||||||
if(NeedsFlush)
|
if(NeedsFlush)
|
||||||
{
|
{
|
||||||
|
@ -1314,11 +1288,14 @@ void CMapLayers::RenderQuadLayer(int LayerIndex, CMapItemLayerQuads *pQuadLayer,
|
||||||
|
|
||||||
if(!IsFullyTransparent)
|
if(!IsFullyTransparent)
|
||||||
{
|
{
|
||||||
|
ColorRGBA Position = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
EnvelopeEval(pQuad->m_PosEnvOffset, pQuad->m_PosEnv, Position, 3, this);
|
||||||
|
|
||||||
SQuadRenderInfo &QInfo = s_vQuadRenderInfo[QuadsRenderCount++];
|
SQuadRenderInfo &QInfo = s_vQuadRenderInfo[QuadsRenderCount++];
|
||||||
QInfo.m_Color = Color;
|
QInfo.m_Color = Color;
|
||||||
QInfo.m_Offsets.x = OffsetX;
|
QInfo.m_Offsets.x = Position.r;
|
||||||
QInfo.m_Offsets.y = OffsetY;
|
QInfo.m_Offsets.y = Position.g;
|
||||||
QInfo.m_Rotation = Rot;
|
QInfo.m_Rotation = Position.b / 180.0f * pi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Graphics()->RenderQuadLayer(Visuals.m_BufferContainerIndex, s_vQuadRenderInfo.data(), QuadsRenderCount, CurQuadOffset);
|
Graphics()->RenderQuadLayer(Visuals.m_BufferContainerIndex, s_vQuadRenderInfo.data(), QuadsRenderCount, CurQuadOffset);
|
||||||
|
@ -1638,17 +1615,23 @@ void CMapLayers::OnRender()
|
||||||
|
|
||||||
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTile))
|
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTile))
|
||||||
{
|
{
|
||||||
ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f);
|
ColorRGBA Color = IsGameLayer ? ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f) : ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f);
|
||||||
if(IsGameLayer && EntityOverlayVal)
|
if(IsGameLayer && EntityOverlayVal)
|
||||||
Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f);
|
Color.a *= EntityOverlayVal / 100.0f;
|
||||||
else if(!IsGameLayer && EntityOverlayVal && !(m_Type == TYPE_BACKGROUND_FORCE))
|
else if(!IsGameLayer && EntityOverlayVal && m_Type != TYPE_BACKGROUND_FORCE)
|
||||||
Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * (100 - EntityOverlayVal) / 100.0f);
|
Color.a *= (100 - EntityOverlayVal) / 100.0f;
|
||||||
|
|
||||||
|
if(!IsGameLayer)
|
||||||
|
{
|
||||||
|
ColorRGBA ColorEnv = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
EnvelopeEval(pTMap->m_ColorEnvOffset, pTMap->m_ColorEnv, ColorEnv, 4, this);
|
||||||
|
Color = Color.Multiply(ColorEnv);
|
||||||
|
}
|
||||||
|
|
||||||
if(!Graphics()->IsTileBufferingEnabled())
|
if(!Graphics()->IsTileBufferingEnabled())
|
||||||
{
|
{
|
||||||
Graphics()->BlendNone();
|
Graphics()->BlendNone();
|
||||||
RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_OPAQUE,
|
RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_OPAQUE);
|
||||||
EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset);
|
|
||||||
|
|
||||||
Graphics()->BlendNormal();
|
Graphics()->BlendNormal();
|
||||||
|
|
||||||
// draw kill tiles outside the entity clipping rectangle
|
// draw kill tiles outside the entity clipping rectangle
|
||||||
|
@ -1657,15 +1640,12 @@ void CMapLayers::OnRender()
|
||||||
// slow blinking to hint that it's not a part of the map
|
// slow blinking to hint that it's not a part of the map
|
||||||
double Seconds = time_get() / (double)time_freq();
|
double Seconds = time_get() / (double)time_freq();
|
||||||
ColorRGBA ColorHint = ColorRGBA(1.0f, 1.0f, 1.0f, 0.3 + 0.7 * (1 + std::sin(2 * (double)pi * Seconds / 3)) / 2);
|
ColorRGBA ColorHint = ColorRGBA(1.0f, 1.0f, 1.0f, 0.3 + 0.7 * (1 + std::sin(2 * (double)pi * Seconds / 3)) / 2);
|
||||||
|
|
||||||
RenderTools()->RenderTileRectangle(-201, -201, pTMap->m_Width + 402, pTMap->m_Height + 402,
|
RenderTools()->RenderTileRectangle(-201, -201, pTMap->m_Width + 402, pTMap->m_Height + 402,
|
||||||
0, TILE_DEATH, // display air inside, death outside
|
0, TILE_DEATH, // display air inside, death outside
|
||||||
32.0f, Color.v4() * ColorHint.v4(), TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT,
|
32.0f, Color.Multiply(ColorHint), TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT);
|
||||||
EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT,
|
RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT);
|
||||||
EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1676,9 +1656,7 @@ void CMapLayers::OnRender()
|
||||||
// slow blinking to hint that it's not a part of the map
|
// slow blinking to hint that it's not a part of the map
|
||||||
double Seconds = time_get() / (double)time_freq();
|
double Seconds = time_get() / (double)time_freq();
|
||||||
ColorRGBA ColorHint = ColorRGBA(1.0f, 1.0f, 1.0f, 0.3 + 0.7 * (1.0 + std::sin(2 * (double)pi * Seconds / 3)) / 2);
|
ColorRGBA ColorHint = ColorRGBA(1.0f, 1.0f, 1.0f, 0.3 + 0.7 * (1.0 + std::sin(2 * (double)pi * Seconds / 3)) / 2);
|
||||||
|
RenderKillTileBorder(TileLayerCounter - 1, Color.Multiply(ColorHint), pTMap, pGroup);
|
||||||
ColorRGBA ColorKill(Color.x * ColorHint.x, Color.y * ColorHint.y, Color.z * ColorHint.z, Color.w * ColorHint.w);
|
|
||||||
RenderKillTileBorder(TileLayerCounter - 1, ColorKill, pTMap, pGroup);
|
|
||||||
}
|
}
|
||||||
RenderTileLayer(TileLayerCounter - 1, Color, pTMap, pGroup);
|
RenderTileLayer(TileLayerCounter - 1, Color, pTMap, pGroup);
|
||||||
}
|
}
|
||||||
|
@ -1732,15 +1710,13 @@ void CMapLayers::OnRender()
|
||||||
|
|
||||||
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTile))
|
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTile))
|
||||||
{
|
{
|
||||||
ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f);
|
const ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, EntityOverlayVal / 100.0f);
|
||||||
if(!Graphics()->IsTileBufferingEnabled())
|
if(!Graphics()->IsTileBufferingEnabled())
|
||||||
{
|
{
|
||||||
Graphics()->BlendNone();
|
Graphics()->BlendNone();
|
||||||
RenderTools()->RenderTilemap(pFrontTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_OPAQUE,
|
RenderTools()->RenderTilemap(pFrontTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_OPAQUE);
|
||||||
EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset);
|
|
||||||
Graphics()->BlendNormal();
|
Graphics()->BlendNormal();
|
||||||
RenderTools()->RenderTilemap(pFrontTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT,
|
RenderTools()->RenderTilemap(pFrontTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT);
|
||||||
EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1759,7 +1735,7 @@ void CMapLayers::OnRender()
|
||||||
|
|
||||||
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CSwitchTile))
|
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CSwitchTile))
|
||||||
{
|
{
|
||||||
ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f);
|
const ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, EntityOverlayVal / 100.0f);
|
||||||
if(!Graphics()->IsTileBufferingEnabled())
|
if(!Graphics()->IsTileBufferingEnabled())
|
||||||
{
|
{
|
||||||
Graphics()->BlendNone();
|
Graphics()->BlendNone();
|
||||||
|
@ -1792,7 +1768,7 @@ void CMapLayers::OnRender()
|
||||||
|
|
||||||
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTeleTile))
|
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTeleTile))
|
||||||
{
|
{
|
||||||
ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f);
|
const ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, EntityOverlayVal / 100.0f);
|
||||||
if(!Graphics()->IsTileBufferingEnabled())
|
if(!Graphics()->IsTileBufferingEnabled())
|
||||||
{
|
{
|
||||||
Graphics()->BlendNone();
|
Graphics()->BlendNone();
|
||||||
|
@ -1823,7 +1799,7 @@ void CMapLayers::OnRender()
|
||||||
|
|
||||||
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CSpeedupTile))
|
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CSpeedupTile))
|
||||||
{
|
{
|
||||||
ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f);
|
const ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, EntityOverlayVal / 100.0f);
|
||||||
if(!Graphics()->IsTileBufferingEnabled())
|
if(!Graphics()->IsTileBufferingEnabled())
|
||||||
{
|
{
|
||||||
Graphics()->BlendNone();
|
Graphics()->BlendNone();
|
||||||
|
@ -1862,7 +1838,7 @@ void CMapLayers::OnRender()
|
||||||
|
|
||||||
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTuneTile))
|
if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTuneTile))
|
||||||
{
|
{
|
||||||
ColorRGBA Color = ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f * EntityOverlayVal / 100.0f);
|
const ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, EntityOverlayVal / 100.0f);
|
||||||
if(!Graphics()->IsTileBufferingEnabled())
|
if(!Graphics()->IsTileBufferingEnabled())
|
||||||
{
|
{
|
||||||
Graphics()->BlendNone();
|
Graphics()->BlendNone();
|
||||||
|
|
|
@ -152,14 +152,14 @@ public:
|
||||||
virtual void OnRender() override;
|
virtual void OnRender() override;
|
||||||
virtual void OnMapLoad() override;
|
virtual void OnMapLoad() override;
|
||||||
|
|
||||||
void RenderTileLayer(int LayerIndex, ColorRGBA &Color, CMapItemLayerTilemap *pTileLayer, CMapItemGroup *pGroup);
|
void RenderTileLayer(int LayerIndex, const ColorRGBA &Color, CMapItemLayerTilemap *pTileLayer, CMapItemGroup *pGroup);
|
||||||
void RenderTileBorder(int LayerIndex, const ColorRGBA &Color, CMapItemLayerTilemap *pTileLayer, CMapItemGroup *pGroup, int BorderX0, int BorderY0, int BorderX1, int BorderY1);
|
void RenderTileBorder(int LayerIndex, const ColorRGBA &Color, CMapItemLayerTilemap *pTileLayer, CMapItemGroup *pGroup, int BorderX0, int BorderY0, int BorderX1, int BorderY1);
|
||||||
void RenderKillTileBorder(int LayerIndex, const ColorRGBA &Color, CMapItemLayerTilemap *pTileLayer, CMapItemGroup *pGroup);
|
void RenderKillTileBorder(int LayerIndex, const ColorRGBA &Color, CMapItemLayerTilemap *pTileLayer, CMapItemGroup *pGroup);
|
||||||
void RenderQuadLayer(int LayerIndex, CMapItemLayerQuads *pQuadLayer, CMapItemGroup *pGroup, bool ForceRender = false);
|
void RenderQuadLayer(int LayerIndex, CMapItemLayerQuads *pQuadLayer, CMapItemGroup *pGroup, bool ForceRender = false);
|
||||||
|
|
||||||
void EnvelopeUpdate();
|
void EnvelopeUpdate();
|
||||||
|
|
||||||
static void EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Channels, void *pUser);
|
static void EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Result, size_t Channels, void *pUser);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -209,18 +209,11 @@ void CMapSounds::OnRender()
|
||||||
if(!Voice.m_Voice.IsValid())
|
if(!Voice.m_Voice.IsValid())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float OffsetX = 0, OffsetY = 0;
|
ColorRGBA Position = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
CMapLayers::EnvelopeEval(Voice.m_pSource->m_PosEnvOffset, Voice.m_pSource->m_PosEnv, Position, 2, &m_pClient->m_MapLayersBackground);
|
||||||
|
|
||||||
if(Voice.m_pSource->m_PosEnv >= 0)
|
float x = fx2f(Voice.m_pSource->m_Position.x) + Position.r;
|
||||||
{
|
float y = fx2f(Voice.m_pSource->m_Position.y) + Position.g;
|
||||||
ColorRGBA Channels;
|
|
||||||
CMapLayers::EnvelopeEval(Voice.m_pSource->m_PosEnvOffset, Voice.m_pSource->m_PosEnv, Channels, &m_pClient->m_MapLayersBackground);
|
|
||||||
OffsetX = Channels.r;
|
|
||||||
OffsetY = Channels.g;
|
|
||||||
}
|
|
||||||
|
|
||||||
float x = fx2f(Voice.m_pSource->m_Position.x) + OffsetX;
|
|
||||||
float y = fx2f(Voice.m_pSource->m_Position.y) + OffsetY;
|
|
||||||
|
|
||||||
x += Center.x * (1.0f - pGroup->m_ParallaxX / 100.0f);
|
x += Center.x * (1.0f - pGroup->m_ParallaxX / 100.0f);
|
||||||
y += Center.y * (1.0f - pGroup->m_ParallaxY / 100.0f);
|
y += Center.y * (1.0f - pGroup->m_ParallaxY / 100.0f);
|
||||||
|
@ -230,13 +223,11 @@ void CMapSounds::OnRender()
|
||||||
|
|
||||||
Sound()->SetVoiceLocation(Voice.m_Voice, x, y);
|
Sound()->SetVoiceLocation(Voice.m_Voice, x, y);
|
||||||
|
|
||||||
if(Voice.m_pSource->m_SoundEnv >= 0)
|
ColorRGBA Volume = ColorRGBA(1.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
CMapLayers::EnvelopeEval(Voice.m_pSource->m_SoundEnvOffset, Voice.m_pSource->m_SoundEnv, Volume, 1, &m_pClient->m_MapLayersBackground);
|
||||||
|
if(Volume.r < 1.0f)
|
||||||
{
|
{
|
||||||
ColorRGBA Channels;
|
Sound()->SetVoiceVolume(Voice.m_Voice, Volume.r);
|
||||||
CMapLayers::EnvelopeEval(Voice.m_pSource->m_SoundEnvOffset, Voice.m_pSource->m_SoundEnv, Channels, &m_pClient->m_MapLayersBackground);
|
|
||||||
float Volume = clamp(Channels.r, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
Sound()->SetVoiceVolume(Voice.m_Voice, Volume);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,7 @@ public:
|
||||||
const CEnvPointBezier *GetBezier(int Index) const override;
|
const CEnvPointBezier *GetBezier(int Index) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*ENVELOPE_EVAL)(int TimeOffsetMillis, int Env, ColorRGBA &Channels, void *pUser);
|
typedef void (*ENVELOPE_EVAL)(int TimeOffsetMillis, int Env, ColorRGBA &Result, size_t Channels, void *pUser);
|
||||||
|
|
||||||
class CRenderTools
|
class CRenderTools
|
||||||
{
|
{
|
||||||
|
@ -162,14 +162,14 @@ public:
|
||||||
void RenderTee(const CAnimState *pAnim, const CTeeRenderInfo *pInfo, int Emote, vec2 Dir, vec2 Pos, float Alpha = 1.0f) const;
|
void RenderTee(const CAnimState *pAnim, const CTeeRenderInfo *pInfo, int Emote, vec2 Dir, vec2 Pos, float Alpha = 1.0f) const;
|
||||||
|
|
||||||
// map render methods (render_map.cpp)
|
// map render methods (render_map.cpp)
|
||||||
static void RenderEvalEnvelope(const IEnvelopePointAccess *pPoints, int Channels, std::chrono::nanoseconds TimeNanos, ColorRGBA &Result);
|
static void RenderEvalEnvelope(const IEnvelopePointAccess *pPoints, std::chrono::nanoseconds TimeNanos, ColorRGBA &Result, size_t Channels);
|
||||||
void RenderQuads(CQuad *pQuads, int NumQuads, int Flags, ENVELOPE_EVAL pfnEval, void *pUser) const;
|
void RenderQuads(CQuad *pQuads, int NumQuads, int Flags, ENVELOPE_EVAL pfnEval, void *pUser) const;
|
||||||
void ForceRenderQuads(CQuad *pQuads, int NumQuads, int Flags, ENVELOPE_EVAL pfnEval, void *pUser, float Alpha = 1.0f) const;
|
void ForceRenderQuads(CQuad *pQuads, int NumQuads, int Flags, ENVELOPE_EVAL pfnEval, void *pUser, float Alpha = 1.0f) const;
|
||||||
void RenderTilemap(CTile *pTiles, int w, int h, float Scale, ColorRGBA Color, int RenderFlags, ENVELOPE_EVAL pfnEval, void *pUser, int ColorEnv, int ColorEnvOffset) const;
|
void RenderTilemap(CTile *pTiles, int w, int h, float Scale, ColorRGBA Color, int RenderFlags) const;
|
||||||
|
|
||||||
// render a rectangle made of IndexIn tiles, over a background made of IndexOut tiles
|
// render a rectangle made of IndexIn tiles, over a background made of IndexOut tiles
|
||||||
// the rectangle include all tiles in [RectX, RectX+RectW-1] x [RectY, RectY+RectH-1]
|
// the rectangle include all tiles in [RectX, RectX+RectW-1] x [RectY, RectY+RectH-1]
|
||||||
void RenderTileRectangle(int RectX, int RectY, int RectW, int RectH, unsigned char IndexIn, unsigned char IndexOut, float Scale, ColorRGBA Color, int RenderFlags, ENVELOPE_EVAL pfnEval, void *pUser, int ColorEnv, int ColorEnvOffset) const;
|
void RenderTileRectangle(int RectX, int RectY, int RectW, int RectH, unsigned char IndexIn, unsigned char IndexOut, float Scale, ColorRGBA Color, int RenderFlags) const;
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
void CalcScreenParams(float Aspect, float Zoom, float *pWidth, float *pHeight);
|
void CalcScreenParams(float Aspect, float Zoom, float *pWidth, float *pHeight);
|
||||||
|
|
|
@ -237,22 +237,21 @@ static float SolveBezier(float x, float p0, float p1, float p2, float p3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRenderTools::RenderEvalEnvelope(const IEnvelopePointAccess *pPoints, int Channels, std::chrono::nanoseconds TimeNanos, ColorRGBA &Result)
|
void CRenderTools::RenderEvalEnvelope(const IEnvelopePointAccess *pPoints, std::chrono::nanoseconds TimeNanos, ColorRGBA &Result, size_t Channels)
|
||||||
{
|
{
|
||||||
const int NumPoints = pPoints->NumPoints();
|
const int NumPoints = pPoints->NumPoints();
|
||||||
if(NumPoints == 0)
|
if(NumPoints == 0)
|
||||||
{
|
{
|
||||||
Result = ColorRGBA();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(NumPoints == 1)
|
if(NumPoints == 1)
|
||||||
{
|
{
|
||||||
const CEnvPoint *pFirstPoint = pPoints->GetPoint(0);
|
const CEnvPoint *pFirstPoint = pPoints->GetPoint(0);
|
||||||
Result.r = fx2f(pFirstPoint->m_aValues[0]);
|
for(size_t c = 0; c < Channels; c++)
|
||||||
Result.g = fx2f(pFirstPoint->m_aValues[1]);
|
{
|
||||||
Result.b = fx2f(pFirstPoint->m_aValues[2]);
|
Result[c] = fx2f(pFirstPoint->m_aValues[c]);
|
||||||
Result.a = fx2f(pFirstPoint->m_aValues[3]);
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +297,7 @@ void CRenderTools::RenderEvalEnvelope(const IEnvelopePointAccess *pPoints, int C
|
||||||
const CEnvPointBezier *pNextPointBezier = pPoints->GetBezier(i + 1);
|
const CEnvPointBezier *pNextPointBezier = pPoints->GetBezier(i + 1);
|
||||||
if(pCurrentPointBezier == nullptr || pNextPointBezier == nullptr)
|
if(pCurrentPointBezier == nullptr || pNextPointBezier == nullptr)
|
||||||
break; // fallback to linear
|
break; // fallback to linear
|
||||||
for(int c = 0; c < Channels; c++)
|
for(size_t c = 0; c < Channels; c++)
|
||||||
{
|
{
|
||||||
// monotonic 2d cubic bezier curve
|
// monotonic 2d cubic bezier curve
|
||||||
const vec2 p0 = vec2(pCurrentPoint->m_Time / 1000.0f, fx2f(pCurrentPoint->m_aValues[c]));
|
const vec2 p0 = vec2(pCurrentPoint->m_Time / 1000.0f, fx2f(pCurrentPoint->m_aValues[c]));
|
||||||
|
@ -326,7 +325,7 @@ void CRenderTools::RenderEvalEnvelope(const IEnvelopePointAccess *pPoints, int C
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int c = 0; c < Channels; c++)
|
for(size_t c = 0; c < Channels; c++)
|
||||||
{
|
{
|
||||||
const float v0 = fx2f(pCurrentPoint->m_aValues[c]);
|
const float v0 = fx2f(pCurrentPoint->m_aValues[c]);
|
||||||
const float v1 = fx2f(pNextPoint->m_aValues[c]);
|
const float v1 = fx2f(pNextPoint->m_aValues[c]);
|
||||||
|
@ -337,13 +336,13 @@ void CRenderTools::RenderEvalEnvelope(const IEnvelopePointAccess *pPoints, int C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result.r = fx2f(pLastPoint->m_aValues[0]);
|
for(size_t c = 0; c < Channels; c++)
|
||||||
Result.g = fx2f(pLastPoint->m_aValues[1]);
|
{
|
||||||
Result.b = fx2f(pLastPoint->m_aValues[2]);
|
Result[c] = fx2f(pLastPoint->m_aValues[c]);
|
||||||
Result.a = fx2f(pLastPoint->m_aValues[3]);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Rotate(CPoint *pCenter, CPoint *pPoint, float Rotation)
|
static void Rotate(const CPoint *pCenter, CPoint *pPoint, float Rotation)
|
||||||
{
|
{
|
||||||
int x = pPoint->x - pCenter->x;
|
int x = pPoint->x - pCenter->x;
|
||||||
int y = pPoint->y - pCenter->y;
|
int y = pPoint->y - pCenter->y;
|
||||||
|
@ -367,13 +366,10 @@ void CRenderTools::ForceRenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags
|
||||||
{
|
{
|
||||||
CQuad *pQuad = &pQuads[i];
|
CQuad *pQuad = &pQuads[i];
|
||||||
|
|
||||||
ColorRGBA Color(1.f, 1.f, 1.f, 1.f);
|
ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
if(pQuad->m_ColorEnv >= 0)
|
pfnEval(pQuad->m_ColorEnvOffset, pQuad->m_ColorEnv, Color, 4, pUser);
|
||||||
{
|
|
||||||
pfnEval(pQuad->m_ColorEnvOffset, pQuad->m_ColorEnv, Color, pUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Color.a <= 0)
|
if(Color.a <= 0.0f)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool Opaque = false;
|
bool Opaque = false;
|
||||||
|
@ -392,19 +388,10 @@ void CRenderTools::ForceRenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags
|
||||||
fx2f(pQuad->m_aTexcoords[2].x), fx2f(pQuad->m_aTexcoords[2].y),
|
fx2f(pQuad->m_aTexcoords[2].x), fx2f(pQuad->m_aTexcoords[2].y),
|
||||||
fx2f(pQuad->m_aTexcoords[3].x), fx2f(pQuad->m_aTexcoords[3].y));
|
fx2f(pQuad->m_aTexcoords[3].x), fx2f(pQuad->m_aTexcoords[3].y));
|
||||||
|
|
||||||
float OffsetX = 0;
|
ColorRGBA Position = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
float OffsetY = 0;
|
pfnEval(pQuad->m_PosEnvOffset, pQuad->m_PosEnv, Position, 3, pUser);
|
||||||
float Rot = 0;
|
const vec2 Offset = vec2(Position.r, Position.g);
|
||||||
|
const float Rotation = Position.b / 180.0f * pi;
|
||||||
// TODO: fix this
|
|
||||||
if(pQuad->m_PosEnv >= 0)
|
|
||||||
{
|
|
||||||
ColorRGBA Channels;
|
|
||||||
pfnEval(pQuad->m_PosEnvOffset, pQuad->m_PosEnv, Channels, pUser);
|
|
||||||
OffsetX = Channels.r;
|
|
||||||
OffsetY = Channels.g;
|
|
||||||
Rot = Channels.b / 360.0f * pi * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
IGraphics::CColorVertex Array[4] = {
|
IGraphics::CColorVertex Array[4] = {
|
||||||
IGraphics::CColorVertex(0, pQuad->m_aColors[0].r * Conv * Color.r, pQuad->m_aColors[0].g * Conv * Color.g, pQuad->m_aColors[0].b * Conv * Color.b, pQuad->m_aColors[0].a * Conv * Color.a * Alpha),
|
IGraphics::CColorVertex(0, pQuad->m_aColors[0].r * Conv * Color.r, pQuad->m_aColors[0].g * Conv * Color.g, pQuad->m_aColors[0].b * Conv * Color.b, pQuad->m_aColors[0].a * Conv * Color.a * Alpha),
|
||||||
|
@ -415,26 +402,22 @@ void CRenderTools::ForceRenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags
|
||||||
|
|
||||||
CPoint *pPoints = pQuad->m_aPoints;
|
CPoint *pPoints = pQuad->m_aPoints;
|
||||||
|
|
||||||
if(Rot != 0)
|
CPoint aRotated[4];
|
||||||
|
if(Rotation != 0.0f)
|
||||||
{
|
{
|
||||||
static CPoint aRotated[4];
|
for(size_t p = 0; p < std::size(aRotated); ++p)
|
||||||
aRotated[0] = pQuad->m_aPoints[0];
|
{
|
||||||
aRotated[1] = pQuad->m_aPoints[1];
|
aRotated[p] = pQuad->m_aPoints[p];
|
||||||
aRotated[2] = pQuad->m_aPoints[2];
|
Rotate(&pQuad->m_aPoints[4], &aRotated[p], Rotation);
|
||||||
aRotated[3] = pQuad->m_aPoints[3];
|
}
|
||||||
pPoints = aRotated;
|
pPoints = aRotated;
|
||||||
|
|
||||||
Rotate(&pQuad->m_aPoints[4], &aRotated[0], Rot);
|
|
||||||
Rotate(&pQuad->m_aPoints[4], &aRotated[1], Rot);
|
|
||||||
Rotate(&pQuad->m_aPoints[4], &aRotated[2], Rot);
|
|
||||||
Rotate(&pQuad->m_aPoints[4], &aRotated[3], Rot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IGraphics::CFreeformItem Freeform(
|
IGraphics::CFreeformItem Freeform(
|
||||||
fx2f(pPoints[0].x) + OffsetX, fx2f(pPoints[0].y) + OffsetY,
|
fx2f(pPoints[0].x) + Offset.x, fx2f(pPoints[0].y) + Offset.y,
|
||||||
fx2f(pPoints[1].x) + OffsetX, fx2f(pPoints[1].y) + OffsetY,
|
fx2f(pPoints[1].x) + Offset.x, fx2f(pPoints[1].y) + Offset.y,
|
||||||
fx2f(pPoints[2].x) + OffsetX, fx2f(pPoints[2].y) + OffsetY,
|
fx2f(pPoints[2].x) + Offset.x, fx2f(pPoints[2].y) + Offset.y,
|
||||||
fx2f(pPoints[3].x) + OffsetX, fx2f(pPoints[3].y) + OffsetY);
|
fx2f(pPoints[3].x) + Offset.x, fx2f(pPoints[3].y) + Offset.y);
|
||||||
Graphics()->QuadsDrawFreeform(&Freeform, 1);
|
Graphics()->QuadsDrawFreeform(&Freeform, 1);
|
||||||
}
|
}
|
||||||
Graphics()->TrianglesEnd();
|
Graphics()->TrianglesEnd();
|
||||||
|
@ -442,8 +425,7 @@ void CRenderTools::ForceRenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags
|
||||||
|
|
||||||
void CRenderTools::RenderTileRectangle(int RectX, int RectY, int RectW, int RectH,
|
void CRenderTools::RenderTileRectangle(int RectX, int RectY, int RectW, int RectH,
|
||||||
unsigned char IndexIn, unsigned char IndexOut,
|
unsigned char IndexIn, unsigned char IndexOut,
|
||||||
float Scale, ColorRGBA Color, int RenderFlags,
|
float Scale, ColorRGBA Color, int RenderFlags) const
|
||||||
ENVELOPE_EVAL pfnEval, void *pUser, int ColorEnv, int ColorEnvOffset) const
|
|
||||||
{
|
{
|
||||||
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
||||||
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
||||||
|
@ -453,17 +435,11 @@ void CRenderTools::RenderTileRectangle(int RectX, int RectY, int RectW, int Rect
|
||||||
float FinalTileSize = Scale / (ScreenX1 - ScreenX0) * Graphics()->ScreenWidth();
|
float FinalTileSize = Scale / (ScreenX1 - ScreenX0) * Graphics()->ScreenWidth();
|
||||||
float FinalTilesetScale = FinalTileSize / TilePixelSize;
|
float FinalTilesetScale = FinalTileSize / TilePixelSize;
|
||||||
|
|
||||||
ColorRGBA Channels(1.f, 1.f, 1.f, 1.f);
|
|
||||||
if(ColorEnv >= 0)
|
|
||||||
{
|
|
||||||
pfnEval(ColorEnvOffset, ColorEnv, Channels, pUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Graphics()->HasTextureArraysSupport())
|
if(Graphics()->HasTextureArraysSupport())
|
||||||
Graphics()->QuadsTex3DBegin();
|
Graphics()->QuadsTex3DBegin();
|
||||||
else
|
else
|
||||||
Graphics()->QuadsBegin();
|
Graphics()->QuadsBegin();
|
||||||
Graphics()->SetColor(Color.r * Channels.r, Color.g * Channels.g, Color.b * Channels.b, Color.a * Channels.a);
|
Graphics()->SetColor(Color);
|
||||||
|
|
||||||
int StartY = (int)(ScreenY0 / Scale) - 1;
|
int StartY = (int)(ScreenY0 / Scale) - 1;
|
||||||
int StartX = (int)(ScreenX0 / Scale) - 1;
|
int StartX = (int)(ScreenX0 / Scale) - 1;
|
||||||
|
@ -540,8 +516,7 @@ void CRenderTools::RenderTileRectangle(int RectX, int RectY, int RectW, int Rect
|
||||||
Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);
|
Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, ColorRGBA Color, int RenderFlags,
|
void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, ColorRGBA Color, int RenderFlags) const
|
||||||
ENVELOPE_EVAL pfnEval, void *pUser, int ColorEnv, int ColorEnvOffset) const
|
|
||||||
{
|
{
|
||||||
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
||||||
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
||||||
|
@ -551,17 +526,12 @@ void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, Color
|
||||||
float FinalTileSize = Scale / (ScreenX1 - ScreenX0) * Graphics()->ScreenWidth();
|
float FinalTileSize = Scale / (ScreenX1 - ScreenX0) * Graphics()->ScreenWidth();
|
||||||
float FinalTilesetScale = FinalTileSize / TilePixelSize;
|
float FinalTilesetScale = FinalTileSize / TilePixelSize;
|
||||||
|
|
||||||
ColorRGBA Channels(1.f, 1.f, 1.f, 1.f);
|
|
||||||
if(ColorEnv >= 0)
|
|
||||||
{
|
|
||||||
pfnEval(ColorEnvOffset, ColorEnv, Channels, pUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Graphics()->HasTextureArraysSupport())
|
if(Graphics()->HasTextureArraysSupport())
|
||||||
Graphics()->QuadsTex3DBegin();
|
Graphics()->QuadsTex3DBegin();
|
||||||
else
|
else
|
||||||
Graphics()->QuadsBegin();
|
Graphics()->QuadsBegin();
|
||||||
Graphics()->SetColor(Color.r * Channels.r, Color.g * Channels.g, Color.b * Channels.b, Color.a * Channels.a);
|
Graphics()->SetColor(Color);
|
||||||
|
const bool ColorOpaque = Color.a > 254.0f / 255.0f;
|
||||||
|
|
||||||
int StartY = (int)(ScreenY0 / Scale) - 1;
|
int StartY = (int)(ScreenY0 / Scale) - 1;
|
||||||
int StartX = (int)(ScreenX0 / Scale) - 1;
|
int StartX = (int)(ScreenX0 / Scale) - 1;
|
||||||
|
@ -611,7 +581,7 @@ void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, Color
|
||||||
unsigned char Flags = pTiles[c].m_Flags;
|
unsigned char Flags = pTiles[c].m_Flags;
|
||||||
|
|
||||||
bool Render = false;
|
bool Render = false;
|
||||||
if(Flags & TILEFLAG_OPAQUE && Color.a * Channels.a > 254.0f / 255.0f)
|
if(ColorOpaque && Flags & TILEFLAG_OPAQUE)
|
||||||
{
|
{
|
||||||
if(RenderFlags & LAYERRENDERFLAG_OPAQUE)
|
if(RenderFlags & LAYERRENDERFLAG_OPAQUE)
|
||||||
Render = true;
|
Render = true;
|
||||||
|
|
|
@ -94,20 +94,17 @@ enum
|
||||||
BUTTON_CONTEXT = 1,
|
BUTTON_CONTEXT = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
void CEditor::EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Channels, void *pUser)
|
void CEditor::EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Result, size_t Channels, void *pUser)
|
||||||
{
|
{
|
||||||
CEditor *pThis = (CEditor *)pUser;
|
CEditor *pThis = (CEditor *)pUser;
|
||||||
if(Env < 0 || Env >= (int)pThis->m_Map.m_vpEnvelopes.size())
|
if(Env < 0 || Env >= (int)pThis->m_Map.m_vpEnvelopes.size())
|
||||||
{
|
|
||||||
Channels = ColorRGBA();
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<CEnvelope> pEnv = pThis->m_Map.m_vpEnvelopes[Env];
|
std::shared_ptr<CEnvelope> pEnv = pThis->m_Map.m_vpEnvelopes[Env];
|
||||||
float t = pThis->m_AnimateTime;
|
float Time = pThis->m_AnimateTime;
|
||||||
t *= pThis->m_AnimateSpeed;
|
Time *= pThis->m_AnimateSpeed;
|
||||||
t += (TimeOffsetMillis / 1000.0f);
|
Time += (TimeOffsetMillis / 1000.0f);
|
||||||
pEnv->Eval(t, Channels);
|
pEnv->Eval(Time, Result, Channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************
|
/********************************************************
|
||||||
|
@ -2791,15 +2788,16 @@ void CEditor::DoQuadEnvelopes(const std::vector<CQuad> &vQuads, IGraphics::CText
|
||||||
const CPoint *pPivotPoint = &vQuads[j].m_aPoints[4];
|
const CPoint *pPivotPoint = &vQuads[j].m_aPoints[4];
|
||||||
for(size_t i = 0; i < apEnvelope[j]->m_vPoints.size() - 1; i++)
|
for(size_t i = 0; i < apEnvelope[j]->m_vPoints.size() - 1; i++)
|
||||||
{
|
{
|
||||||
ColorRGBA Result;
|
ColorRGBA Result = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
apEnvelope[j]->Eval(apEnvelope[j]->m_vPoints[i].m_Time / 1000.0f + 0.000001f, Result);
|
apEnvelope[j]->Eval(apEnvelope[j]->m_vPoints[i].m_Time / 1000.0f + 0.000001f, Result, 2);
|
||||||
vec2 Pos0 = vec2(fx2f(pPivotPoint->x) + Result.r, fx2f(pPivotPoint->y) + Result.g);
|
vec2 Pos0 = vec2(fx2f(pPivotPoint->x) + Result.r, fx2f(pPivotPoint->y) + Result.g);
|
||||||
|
|
||||||
const int Steps = 15;
|
const int Steps = 15;
|
||||||
for(int n = 1; n <= Steps; n++)
|
for(int n = 1; n <= Steps; n++)
|
||||||
{
|
{
|
||||||
const float Time = mix(apEnvelope[j]->m_vPoints[i].m_Time, apEnvelope[j]->m_vPoints[i + 1].m_Time, (float)n / Steps);
|
const float Time = mix(apEnvelope[j]->m_vPoints[i].m_Time, apEnvelope[j]->m_vPoints[i + 1].m_Time, (float)n / Steps);
|
||||||
apEnvelope[j]->Eval(Time / 1000.0f - 0.000001f, Result);
|
Result = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
apEnvelope[j]->Eval(Time / 1000.0f - 0.000001f, Result, 2);
|
||||||
|
|
||||||
vec2 Pos1 = vec2(fx2f(pPivotPoint->x) + Result.r, fx2f(pPivotPoint->y) + Result.g);
|
vec2 Pos1 = vec2(fx2f(pPivotPoint->x) + Result.r, fx2f(pPivotPoint->y) + Result.g);
|
||||||
|
|
||||||
|
@ -6445,11 +6443,9 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
{
|
{
|
||||||
// add point
|
// add point
|
||||||
float Time = ScreenToEnvelopeX(View, UI()->MouseX());
|
float Time = ScreenToEnvelopeX(View, UI()->MouseX());
|
||||||
ColorRGBA Channels;
|
ColorRGBA Channels = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
if(in_range(Time, 0.0f, pEnvelope->EndTime()))
|
if(in_range(Time, 0.0f, pEnvelope->EndTime()))
|
||||||
pEnvelope->Eval(Time, Channels);
|
pEnvelope->Eval(Time, Channels, 4);
|
||||||
else
|
|
||||||
Channels = {0, 0, 0, 0};
|
|
||||||
|
|
||||||
int FixedTime = std::round(Time * 1000.0f);
|
int FixedTime = std::round(Time * 1000.0f);
|
||||||
bool TimeFound = false;
|
bool TimeFound = false;
|
||||||
|
@ -6642,12 +6638,13 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||||
float StepTime = (EndTime - StartTime) / static_cast<float>(Steps);
|
float StepTime = (EndTime - StartTime) / static_cast<float>(Steps);
|
||||||
float StepSize = (EndX - StartX) / static_cast<float>(Steps);
|
float StepSize = (EndX - StartX) / static_cast<float>(Steps);
|
||||||
|
|
||||||
ColorRGBA Channels;
|
ColorRGBA Channels = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
pEnvelope->Eval(StartTime + StepTime, Channels);
|
pEnvelope->Eval(StartTime + StepTime, Channels, c + 1);
|
||||||
float PrevY = EnvelopeToScreenY(View, Channels[c]);
|
float PrevY = EnvelopeToScreenY(View, Channels[c]);
|
||||||
for(int i = 2; i < Steps; i++)
|
for(int i = 2; i < Steps; i++)
|
||||||
{
|
{
|
||||||
pEnvelope->Eval(StartTime + i * StepTime, Channels);
|
Channels = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
pEnvelope->Eval(StartTime + i * StepTime, Channels, c + 1);
|
||||||
float CurrentY = EnvelopeToScreenY(View, Channels[c]);
|
float CurrentY = EnvelopeToScreenY(View, Channels[c]);
|
||||||
|
|
||||||
IGraphics::CLineItem LineItem(
|
IGraphics::CLineItem LineItem(
|
||||||
|
|
|
@ -809,7 +809,7 @@ public:
|
||||||
|
|
||||||
int m_ShiftBy;
|
int m_ShiftBy;
|
||||||
|
|
||||||
static void EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Channels, void *pUser);
|
static void EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Result, size_t Channels, void *pUser);
|
||||||
|
|
||||||
CLineInputBuffered<256> m_SettingsCommandInput;
|
CLineInputBuffered<256> m_SettingsCommandInput;
|
||||||
CMapSettingsBackend m_MapSettingsBackend;
|
CMapSettingsBackend m_MapSettingsBackend;
|
||||||
|
|
|
@ -98,10 +98,10 @@ std::pair<float, float> CEnvelope::GetValueRange(int ChannelMask)
|
||||||
return {Bottom, Top};
|
return {Bottom, Top};
|
||||||
}
|
}
|
||||||
|
|
||||||
int CEnvelope::Eval(float Time, ColorRGBA &Color)
|
void CEnvelope::Eval(float Time, ColorRGBA &Result, size_t Channels)
|
||||||
{
|
{
|
||||||
CRenderTools::RenderEvalEnvelope(&m_PointsAccess, GetChannels(), std::chrono::nanoseconds((int64_t)((double)Time * (double)std::chrono::nanoseconds(1s).count())), Color);
|
Channels = minimum<size_t>(Channels, GetChannels(), CEnvPoint::MAX_CHANNELS);
|
||||||
return GetChannels();
|
CRenderTools::RenderEvalEnvelope(&m_PointsAccess, std::chrono::nanoseconds((int64_t)((double)Time * (double)std::chrono::nanoseconds(1s).count())), Result, Channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEnvelope::AddPoint(int Time, int v0, int v1, int v2, int v3)
|
void CEnvelope::AddPoint(int Time, int v0, int v1, int v2, int v3)
|
||||||
|
|
|
@ -21,7 +21,7 @@ public:
|
||||||
explicit CEnvelope(int NumChannels);
|
explicit CEnvelope(int NumChannels);
|
||||||
|
|
||||||
std::pair<float, float> GetValueRange(int ChannelMask);
|
std::pair<float, float> GetValueRange(int ChannelMask);
|
||||||
int Eval(float Time, ColorRGBA &Color);
|
void Eval(float Time, ColorRGBA &Result, size_t Channels);
|
||||||
void AddPoint(int Time, int v0, int v1 = 0, int v2 = 0, int v3 = 0);
|
void AddPoint(int Time, int v0, int v1 = 0, int v2 = 0, int v3 = 0);
|
||||||
float EndTime() const;
|
float EndTime() const;
|
||||||
int GetChannels() const;
|
int GetChannels() const;
|
||||||
|
|
|
@ -34,41 +34,31 @@ void CLayerSounds::Render(bool Tileset)
|
||||||
Graphics()->SetColor(0.6f, 0.8f, 1.0f, 0.4f);
|
Graphics()->SetColor(0.6f, 0.8f, 1.0f, 0.4f);
|
||||||
for(const auto &Source : m_vSources)
|
for(const auto &Source : m_vSources)
|
||||||
{
|
{
|
||||||
float OffsetX = 0;
|
ColorRGBA Offset = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
float OffsetY = 0;
|
CEditor::EnvelopeEval(Source.m_PosEnvOffset, Source.m_PosEnv, Offset, 2, m_pEditor);
|
||||||
|
const vec2 Position = vec2(fx2f(Source.m_Position.x) + Offset.r, fx2f(Source.m_Position.y) + Offset.g);
|
||||||
if(Source.m_PosEnv >= 0)
|
const float Falloff = Source.m_Falloff / 255.0f;
|
||||||
{
|
|
||||||
ColorRGBA Channels;
|
|
||||||
CEditor::EnvelopeEval(Source.m_PosEnvOffset, Source.m_PosEnv, Channels, m_pEditor);
|
|
||||||
OffsetX = Channels.r;
|
|
||||||
OffsetY = Channels.g;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(Source.m_Shape.m_Type)
|
switch(Source.m_Shape.m_Type)
|
||||||
{
|
{
|
||||||
case CSoundShape::SHAPE_CIRCLE:
|
case CSoundShape::SHAPE_CIRCLE:
|
||||||
{
|
{
|
||||||
m_pEditor->Graphics()->DrawCircle(fx2f(Source.m_Position.x) + OffsetX, fx2f(Source.m_Position.y) + OffsetY,
|
m_pEditor->Graphics()->DrawCircle(Position.x, Position.y, Source.m_Shape.m_Circle.m_Radius, 32);
|
||||||
Source.m_Shape.m_Circle.m_Radius, 32);
|
|
||||||
|
|
||||||
float Falloff = ((float)Source.m_Falloff / 255.0f);
|
|
||||||
if(Falloff > 0.0f)
|
if(Falloff > 0.0f)
|
||||||
m_pEditor->Graphics()->DrawCircle(fx2f(Source.m_Position.x) + OffsetX, fx2f(Source.m_Position.y) + OffsetY,
|
{
|
||||||
Source.m_Shape.m_Circle.m_Radius * Falloff, 32);
|
m_pEditor->Graphics()->DrawCircle(Position.x, Position.y, Source.m_Shape.m_Circle.m_Radius * Falloff, 32);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CSoundShape::SHAPE_RECTANGLE:
|
case CSoundShape::SHAPE_RECTANGLE:
|
||||||
{
|
{
|
||||||
float Width = fx2f(Source.m_Shape.m_Rectangle.m_Width);
|
const float Width = fx2f(Source.m_Shape.m_Rectangle.m_Width);
|
||||||
float Height = fx2f(Source.m_Shape.m_Rectangle.m_Height);
|
const float Height = fx2f(Source.m_Shape.m_Rectangle.m_Height);
|
||||||
m_pEditor->Graphics()->DrawRectExt(fx2f(Source.m_Position.x) + OffsetX - Width / 2, fx2f(Source.m_Position.y) + OffsetY - Height / 2,
|
m_pEditor->Graphics()->DrawRectExt(Position.x - Width / 2, Position.y - Height / 2, Width, Height, 0.0f, IGraphics::CORNER_NONE);
|
||||||
Width, Height, 0.0f, IGraphics::CORNER_NONE);
|
|
||||||
|
|
||||||
float Falloff = ((float)Source.m_Falloff / 255.0f);
|
|
||||||
if(Falloff > 0.0f)
|
if(Falloff > 0.0f)
|
||||||
m_pEditor->Graphics()->DrawRectExt(fx2f(Source.m_Position.x) + OffsetX - Falloff * Width / 2, fx2f(Source.m_Position.y) + OffsetY - Falloff * Height / 2,
|
{
|
||||||
Width * Falloff, Height * Falloff, 0.0f, IGraphics::CORNER_NONE);
|
m_pEditor->Graphics()->DrawRectExt(Position.x - Falloff * Width / 2, Position.y - Falloff * Height / 2, Width * Falloff, Height * Falloff, 0.0f, IGraphics::CORNER_NONE);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,18 +74,10 @@ void CLayerSounds::Render(bool Tileset)
|
||||||
m_pEditor->RenderTools()->SelectSprite(SPRITE_AUDIO_SOURCE);
|
m_pEditor->RenderTools()->SelectSprite(SPRITE_AUDIO_SOURCE);
|
||||||
for(const auto &Source : m_vSources)
|
for(const auto &Source : m_vSources)
|
||||||
{
|
{
|
||||||
float OffsetX = 0;
|
ColorRGBA Offset = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
float OffsetY = 0;
|
CEditor::EnvelopeEval(Source.m_PosEnvOffset, Source.m_PosEnv, Offset, 2, m_pEditor);
|
||||||
|
const vec2 Position = vec2(fx2f(Source.m_Position.x) + Offset.r, fx2f(Source.m_Position.y) + Offset.g);
|
||||||
if(Source.m_PosEnv >= 0)
|
m_pEditor->RenderTools()->DrawSprite(Position.x, Position.y, m_pEditor->MapView()->ScaleLength(s_SourceVisualSize));
|
||||||
{
|
|
||||||
ColorRGBA Channels;
|
|
||||||
CEditor::EnvelopeEval(Source.m_PosEnvOffset, Source.m_PosEnv, Channels, m_pEditor);
|
|
||||||
OffsetX = Channels.r;
|
|
||||||
OffsetY = Channels.g;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pEditor->RenderTools()->DrawSprite(fx2f(Source.m_Position.x) + OffsetX, fx2f(Source.m_Position.y) + OffsetY, m_pEditor->MapView()->ScaleLength(s_SourceVisualSize));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Graphics()->QuadsEnd();
|
Graphics()->QuadsEnd();
|
||||||
|
|
|
@ -146,13 +146,14 @@ void CLayerTiles::Render(bool Tileset)
|
||||||
Texture = m_pEditor->GetTuneTexture();
|
Texture = m_pEditor->GetTuneTexture();
|
||||||
Graphics()->TextureSet(Texture);
|
Graphics()->TextureSet(Texture);
|
||||||
|
|
||||||
ColorRGBA Color = ColorRGBA(m_Color.r / 255.0f, m_Color.g / 255.0f, m_Color.b / 255.0f, m_Color.a / 255.0f);
|
ColorRGBA ColorEnv = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
CEditor::EnvelopeEval(m_ColorEnvOffset, m_ColorEnv, ColorEnv, 4, m_pEditor);
|
||||||
|
const ColorRGBA Color = ColorRGBA(m_Color.r / 255.0f, m_Color.g / 255.0f, m_Color.b / 255.0f, m_Color.a / 255.0f).Multiply(ColorEnv);
|
||||||
|
|
||||||
Graphics()->BlendNone();
|
Graphics()->BlendNone();
|
||||||
m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_OPAQUE,
|
m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_OPAQUE);
|
||||||
CEditor::EnvelopeEval, m_pEditor, m_ColorEnv, m_ColorEnvOffset);
|
|
||||||
Graphics()->BlendNormal();
|
Graphics()->BlendNormal();
|
||||||
m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_TRANSPARENT,
|
m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_TRANSPARENT);
|
||||||
CEditor::EnvelopeEval, m_pEditor, m_ColorEnv, m_ColorEnvOffset);
|
|
||||||
|
|
||||||
// Render DDRace Layers
|
// Render DDRace Layers
|
||||||
if(!Tileset)
|
if(!Tileset)
|
||||||
|
|
|
@ -916,7 +916,20 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
|
||||||
for(int e = 0; e < EnvNum; e++)
|
for(int e = 0; e < EnvNum; e++)
|
||||||
{
|
{
|
||||||
CMapItemEnvelope *pItem = (CMapItemEnvelope *)DataFile.GetItem(EnvStart + e);
|
CMapItemEnvelope *pItem = (CMapItemEnvelope *)DataFile.GetItem(EnvStart + e);
|
||||||
std::shared_ptr<CEnvelope> pEnv = std::make_shared<CEnvelope>(pItem->m_Channels);
|
int Channels = pItem->m_Channels;
|
||||||
|
if(Channels <= 0 || Channels == 2 || Channels > CEnvPoint::MAX_CHANNELS)
|
||||||
|
{
|
||||||
|
// Fall back to showing all channels if the number of channels is unsupported
|
||||||
|
Channels = CEnvPoint::MAX_CHANNELS;
|
||||||
|
}
|
||||||
|
if(Channels != pItem->m_Channels)
|
||||||
|
{
|
||||||
|
char aBuf[128];
|
||||||
|
str_format(aBuf, sizeof(aBuf), "Error: Envelope %d had an invalid number of channels, %d, which was changed to %d.", e, pItem->m_Channels, Channels);
|
||||||
|
ErrorHandler(aBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<CEnvelope> pEnv = std::make_shared<CEnvelope>(Channels);
|
||||||
pEnv->m_vPoints.resize(pItem->m_NumPoints);
|
pEnv->m_vPoints.resize(pItem->m_NumPoints);
|
||||||
for(int p = 0; p < pItem->m_NumPoints; p++)
|
for(int p = 0; p < pItem->m_NumPoints; p++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1610,8 +1610,8 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEnvPointCurveType(void *pContext, CU
|
||||||
if(SelectedIndex != FirstSelectedIndex && SelectedIndex != LastSelectedIndex)
|
if(SelectedIndex != FirstSelectedIndex && SelectedIndex != LastSelectedIndex)
|
||||||
{
|
{
|
||||||
CEnvPoint &CurrentPoint = pEnvelope->m_vPoints[SelectedIndex];
|
CEnvPoint &CurrentPoint = pEnvelope->m_vPoints[SelectedIndex];
|
||||||
ColorRGBA Channels;
|
ColorRGBA Channels = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
HelperEnvelope.Eval(CurrentPoint.m_Time / 1000.0f, Channels);
|
HelperEnvelope.Eval(CurrentPoint.m_Time / 1000.0f, Channels, 1);
|
||||||
int PrevValue = CurrentPoint.m_aValues[c];
|
int PrevValue = CurrentPoint.m_aValues[c];
|
||||||
CurrentPoint.m_aValues[c] = f2fx(Channels.r);
|
CurrentPoint.m_aValues[c] = f2fx(Channels.r);
|
||||||
vpActions.push_back(std::make_shared<CEditorActionEnvelopeEditPoint>(pEditor, pEditor->m_SelectedEnvelope, SelectedIndex, SelectedChannel, CEditorActionEnvelopeEditPoint::EEditType::VALUE, PrevValue, CurrentPoint.m_aValues[c]));
|
vpActions.push_back(std::make_shared<CEditorActionEnvelopeEditPoint>(pEditor, pEditor->m_SelectedEnvelope, SelectedIndex, SelectedChannel, CEditorActionEnvelopeEditPoint::EEditType::VALUE, PrevValue, CurrentPoint.m_aValues[c]));
|
||||||
|
|
Loading…
Reference in a new issue