mirror of
https://github.com/ddnet/ddnet.git
synced 2024-09-20 09:34:19 +00:00
Merge pull request #6885 from Marmare314/envelope_zoom
Zoomable envelope editor
This commit is contained in:
commit
de3b2b170c
|
@ -1082,7 +1082,7 @@ void CEditor::DoToolbarLayers(CUIRect ToolBar)
|
|||
static int s_ZoomOutButton = 0;
|
||||
if(DoButton_FontIcon(&s_ZoomOutButton, "-", 0, &Button, 0, "[NumPad-] Zoom out", IGraphics::CORNER_L))
|
||||
{
|
||||
ChangeZoom(50.0f);
|
||||
m_ZoomMapView.ChangeZoom(50.0f);
|
||||
}
|
||||
|
||||
TB_Top.VSplitLeft(25.0f, &Button, &TB_Top);
|
||||
|
@ -1091,14 +1091,14 @@ void CEditor::DoToolbarLayers(CUIRect ToolBar)
|
|||
{
|
||||
m_EditorOffsetX = 0;
|
||||
m_EditorOffsetY = 0;
|
||||
SetZoom(100.0f);
|
||||
m_ZoomMapView.SetZoom(100.0f);
|
||||
}
|
||||
|
||||
TB_Top.VSplitLeft(20.0f, &Button, &TB_Top);
|
||||
static int s_ZoomInButton = 0;
|
||||
if(DoButton_FontIcon(&s_ZoomInButton, "+", 0, &Button, 0, "[NumPad+] Zoom in", IGraphics::CORNER_R))
|
||||
{
|
||||
ChangeZoom(-50.0f);
|
||||
m_ZoomMapView.ChangeZoom(-50.0f);
|
||||
}
|
||||
|
||||
TB_Top.VSplitLeft(5.0f, nullptr, &TB_Top);
|
||||
|
@ -2518,7 +2518,7 @@ void CEditor::DoMapEditor(CUIRect View)
|
|||
}
|
||||
|
||||
CLayerTiles *pT = static_cast<CLayerTiles *>(GetSelectedLayerType(0, LAYERTYPE_TILES));
|
||||
if(m_ShowTileInfo != SHOW_TILE_OFF && pT && pT->m_Visible && m_Zoom <= 300.0f)
|
||||
if(m_ShowTileInfo != SHOW_TILE_OFF && pT && pT->m_Visible && m_ZoomMapView.GetZoom() <= 300.0f)
|
||||
{
|
||||
GetSelectedGroup()->MapScreen();
|
||||
pT->ShowInfo();
|
||||
|
@ -5601,6 +5601,128 @@ void CEditor::RemoveUnusedEnvelopes()
|
|||
}
|
||||
}
|
||||
|
||||
void CEditor::ZoomAdaptOffsetX(float ZoomFactor, const CUIRect &View)
|
||||
{
|
||||
if(g_Config.m_EdZoomTarget)
|
||||
{
|
||||
float PosX = (UI()->MouseX() - View.x) / View.w;
|
||||
m_OffsetEnvelopeX += (m_OffsetEnvelopeX - PosX) * (1.0f - ZoomFactor);
|
||||
}
|
||||
else
|
||||
m_OffsetEnvelopeX += (m_OffsetEnvelopeX - 0.5f) * (1.0f - ZoomFactor);
|
||||
}
|
||||
|
||||
void CEditor::UpdateZoomEnvelopeX(const CUIRect &View)
|
||||
{
|
||||
float OldZoom = m_ZoomEnvelopeX.GetZoom();
|
||||
if(m_ZoomEnvelopeX.UpdateZoom())
|
||||
ZoomAdaptOffsetX(m_ZoomEnvelopeX.GetZoom() / OldZoom, View);
|
||||
}
|
||||
|
||||
void CEditor::ZoomAdaptOffsetY(float ZoomFactor, const CUIRect &View)
|
||||
{
|
||||
if(g_Config.m_EdZoomTarget)
|
||||
{
|
||||
float PosY = 1.0f - (UI()->MouseY() - View.y) / View.h;
|
||||
m_OffsetEnvelopeY += (m_OffsetEnvelopeY - PosY) * (1.0f - ZoomFactor);
|
||||
}
|
||||
else
|
||||
m_OffsetEnvelopeY += (m_OffsetEnvelopeY - 0.5f) * (1.0f - ZoomFactor);
|
||||
}
|
||||
|
||||
void CEditor::UpdateZoomEnvelopeY(const CUIRect &View)
|
||||
{
|
||||
float OldZoom = m_ZoomEnvelopeY.GetZoom();
|
||||
if(m_ZoomEnvelopeY.UpdateZoom())
|
||||
ZoomAdaptOffsetY(m_ZoomEnvelopeY.GetZoom() / OldZoom, View);
|
||||
}
|
||||
|
||||
void CEditor::ResetZoomEnvelope(CEnvelope *pEnvelope, int ActiveChannels)
|
||||
{
|
||||
pEnvelope->FindTopBottom(ActiveChannels);
|
||||
float Top = pEnvelope->m_Top;
|
||||
float Bottom = pEnvelope->m_Bottom;
|
||||
float EndTime = pEnvelope->EndTime();
|
||||
float ValueRange = absolute(Top - Bottom);
|
||||
|
||||
if(ValueRange < 0.1f)
|
||||
{
|
||||
// Set view to some sane default if range is too small
|
||||
m_OffsetEnvelopeY = 0.5f - Top / 0.1f;
|
||||
m_ZoomEnvelopeY.SetZoomInstant(0.1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ZoomEnvelopeY.SetZoomInstant(1.25f * ValueRange);
|
||||
if(Top >= 0 && Bottom >= 0)
|
||||
m_OffsetEnvelopeY = 0.1f - Bottom / m_ZoomEnvelopeY.GetZoom();
|
||||
else if(Top <= 0 && Bottom <= 0)
|
||||
m_OffsetEnvelopeY = 0.1f - Bottom / m_ZoomEnvelopeY.GetZoom();
|
||||
else
|
||||
m_OffsetEnvelopeY = 0.1f + 0.8f * absolute(Bottom) / ValueRange;
|
||||
}
|
||||
|
||||
if(EndTime < 0.1f)
|
||||
{
|
||||
m_OffsetEnvelopeX = 0.5f - EndTime / 0.1f;
|
||||
m_ZoomEnvelopeX.SetZoomInstant(0.1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ZoomEnvelopeX.SetZoomInstant(1.25f * EndTime);
|
||||
m_OffsetEnvelopeX = 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
float fxt2f(int t)
|
||||
{
|
||||
return t / 1000.0f;
|
||||
}
|
||||
|
||||
int f2fxt(float t)
|
||||
{
|
||||
return static_cast<int>(t * 1000.0f);
|
||||
}
|
||||
|
||||
float CEditor::ScreenToEnvelopeX(const CUIRect &View, float x) const
|
||||
{
|
||||
return (x - View.x - View.w * m_OffsetEnvelopeX) / View.w * m_ZoomEnvelopeX.GetZoom();
|
||||
}
|
||||
|
||||
float CEditor::EnvelopeToScreenX(const CUIRect &View, float x) const
|
||||
{
|
||||
return View.x + View.w * m_OffsetEnvelopeX + x / m_ZoomEnvelopeX.GetZoom() * View.w;
|
||||
}
|
||||
|
||||
float CEditor::ScreenToEnvelopeY(const CUIRect &View, float y) const
|
||||
{
|
||||
return (View.h - y + View.y) / View.h * m_ZoomEnvelopeY.GetZoom() - m_OffsetEnvelopeY * m_ZoomEnvelopeY.GetZoom();
|
||||
}
|
||||
|
||||
float CEditor::EnvelopeToScreenY(const CUIRect &View, float y) const
|
||||
{
|
||||
return View.y + View.h - y / m_ZoomEnvelopeY.GetZoom() * View.h - m_OffsetEnvelopeY * View.h;
|
||||
}
|
||||
|
||||
float CEditor::ScreenToEnvelopeDX(const CUIRect &View, float dx)
|
||||
{
|
||||
return dx / Graphics()->ScreenWidth() * UI()->Screen()->w / View.w * m_ZoomEnvelopeX.GetZoom();
|
||||
}
|
||||
|
||||
float CEditor::ScreenToEnvelopeDY(const CUIRect &View, float dy)
|
||||
{
|
||||
return dy / Graphics()->ScreenHeight() * UI()->Screen()->h / View.h * m_ZoomEnvelopeY.GetZoom();
|
||||
}
|
||||
|
||||
void CEditor::RemoveTimeOffsetEnvelope(CEnvelope *pEnvelope)
|
||||
{
|
||||
int TimeOffset = pEnvelope->m_vPoints[0].m_Time;
|
||||
for(auto &Point : pEnvelope->m_vPoints)
|
||||
Point.m_Time -= TimeOffset;
|
||||
|
||||
m_OffsetEnvelopeX += fxt2f(TimeOffset) / m_ZoomEnvelopeX.GetZoom();
|
||||
};
|
||||
|
||||
void CEditor::RenderEnvelopeEditor(CUIRect View)
|
||||
{
|
||||
RenderExtraEditorDragBar(View, &m_EnvelopeEditorSplit);
|
||||
|
@ -5614,6 +5736,17 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
if(m_SelectedEnvelope >= 0 && m_SelectedEnvelope < (int)m_Map.m_vpEnvelopes.size())
|
||||
pEnvelope = m_Map.m_vpEnvelopes[m_SelectedEnvelope];
|
||||
|
||||
enum
|
||||
{
|
||||
OP_NONE,
|
||||
OP_DRAG_POINT,
|
||||
OP_DRAG_POINT_X,
|
||||
OP_DRAG_POINT_Y
|
||||
};
|
||||
static int s_Operation = OP_NONE;
|
||||
static float s_AccurateDragValueX = 0.0f;
|
||||
static float s_AccurateDragValueY = 0.0f;
|
||||
|
||||
CUIRect ToolBar, CurveBar, ColorBar;
|
||||
View.HSplitTop(15.0f, &ToolBar, &View);
|
||||
View.HSplitTop(15.0f, &CurveBar, &View);
|
||||
|
@ -5623,6 +5756,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
bool CurrentEnvelopeSwitched = false;
|
||||
|
||||
// do the toolbar
|
||||
static int s_ActiveChannels = 0xf;
|
||||
{
|
||||
CUIRect Button;
|
||||
CEnvelope *pNewEnv = nullptr;
|
||||
|
@ -5688,6 +5822,15 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
pEnvelope = m_Map.m_vpEnvelopes[m_SelectedEnvelope];
|
||||
}
|
||||
|
||||
if(pEnvelope)
|
||||
{
|
||||
ToolBar.VSplitRight(5.0f, &ToolBar, nullptr);
|
||||
ToolBar.VSplitRight(20.0f, &ToolBar, &Button);
|
||||
static int s_ResetZoomButton = 0;
|
||||
if(DoButton_FontIcon(&s_ResetZoomButton, FONT_ICON_MAGNIFYING_GLASS, 0, &Button, 0, "Reset zoom to default value", IGraphics::CORNER_ALL, 9.0f))
|
||||
ResetZoomEnvelope(pEnvelope, s_ActiveChannels);
|
||||
}
|
||||
|
||||
// Margin on the right side
|
||||
ToolBar.VSplitRight(7.0f, &ToolBar, nullptr);
|
||||
}
|
||||
|
@ -5771,15 +5914,19 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
ShowColorBar = true;
|
||||
View.HSplitTop(20.0f, &ColorBar, &View);
|
||||
ColorBar.Margin(2.0f, &ColorBar);
|
||||
RenderBackground(ColorBar, m_CheckerTexture, 16.0f, 1.0f);
|
||||
}
|
||||
|
||||
RenderBackground(View, m_CheckerTexture, 32.0f, 0.1f);
|
||||
|
||||
if(pEnvelope)
|
||||
{
|
||||
if(m_ResetZoomEnvelope)
|
||||
{
|
||||
m_ResetZoomEnvelope = false;
|
||||
ResetZoomEnvelope(pEnvelope, s_ActiveChannels);
|
||||
}
|
||||
|
||||
static int s_EnvelopeEditorID = 0;
|
||||
static int s_ActiveChannels = 0xf;
|
||||
|
||||
ColorRGBA aColors[] = {ColorRGBA(1, 0.2f, 0.2f), ColorRGBA(0.2f, 1, 0.2f), ColorRGBA(0.2f, 0.2f, 1), ColorRGBA(1, 1, 0.2f)};
|
||||
|
||||
|
@ -5833,22 +5980,6 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
ToolBar.VSplitLeft(40.0f, &Button, &ToolBar);
|
||||
UI()->DoLabel(&Button, "Sync.", 10.0f, TEXTALIGN_ML);
|
||||
|
||||
float EndTime = pEnvelope->EndTime();
|
||||
if(EndTime < 1)
|
||||
EndTime = 1;
|
||||
|
||||
pEnvelope->FindTopBottom(s_ActiveChannels);
|
||||
float Top = pEnvelope->m_Top;
|
||||
float Bottom = pEnvelope->m_Bottom;
|
||||
|
||||
if(Top < 1)
|
||||
Top = 1;
|
||||
if(Bottom >= 0)
|
||||
Bottom = 0;
|
||||
|
||||
float TimeScale = EndTime / View.w;
|
||||
float ValueScale = (Top - Bottom) / View.h;
|
||||
|
||||
if(UI()->MouseInside(&View))
|
||||
UI()->SetHotItem(&s_EnvelopeEditorID);
|
||||
|
||||
|
@ -5858,19 +5989,47 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
if(UI()->MouseButtonClicked(1))
|
||||
{
|
||||
// add point
|
||||
int Time = (int)(((UI()->MouseX() - View.x) * TimeScale) * 1000.0f);
|
||||
float Time = ScreenToEnvelopeX(View, UI()->MouseX());
|
||||
ColorRGBA Channels;
|
||||
pEnvelope->Eval(Time / 1000.0f, Channels);
|
||||
pEnvelope->AddPoint(Time,
|
||||
if(in_range(Time, 0.0f, pEnvelope->EndTime()))
|
||||
pEnvelope->Eval(Time, Channels);
|
||||
else
|
||||
Channels = {0, 0, 0, 0};
|
||||
pEnvelope->AddPoint(f2fxt(Time),
|
||||
f2fx(Channels.r), f2fx(Channels.g),
|
||||
f2fx(Channels.b), f2fx(Channels.a));
|
||||
|
||||
if(Time < 0)
|
||||
RemoveTimeOffsetEnvelope(pEnvelope);
|
||||
m_Map.OnModify();
|
||||
}
|
||||
else if(UI()->MouseButton(2) || (UI()->MouseButton(0) && Input()->ModifierIsPressed()))
|
||||
{
|
||||
m_OffsetEnvelopeX += UI()->MouseDeltaX() / Graphics()->ScreenWidth() * UI()->Screen()->w / View.w;
|
||||
m_OffsetEnvelopeY -= UI()->MouseDeltaY() / Graphics()->ScreenHeight() * UI()->Screen()->h / View.h;
|
||||
}
|
||||
if(Input()->ShiftIsPressed())
|
||||
{
|
||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN))
|
||||
m_ZoomEnvelopeY.ChangeZoom(0.1f * m_ZoomEnvelopeY.GetZoom());
|
||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP))
|
||||
m_ZoomEnvelopeY.ChangeZoom(-0.1f * m_ZoomEnvelopeY.GetZoom());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN))
|
||||
m_ZoomEnvelopeX.ChangeZoom(0.1f * m_ZoomEnvelopeX.GetZoom());
|
||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP))
|
||||
m_ZoomEnvelopeX.ChangeZoom(-0.1f * m_ZoomEnvelopeX.GetZoom());
|
||||
}
|
||||
|
||||
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
||||
m_pTooltip = "Press right mouse button to create a new point";
|
||||
m_pTooltip = "Press right mouse button to create a new point. Use shift to change the zoom axis.";
|
||||
}
|
||||
|
||||
UpdateZoomEnvelopeX(View);
|
||||
UpdateZoomEnvelopeY(View);
|
||||
|
||||
// keep track of selected point to handle value/time text input
|
||||
static const void *s_pSelectedPoint = nullptr;
|
||||
|
||||
|
@ -5886,36 +6045,36 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
|
||||
for(int i = 0; i < (int)pEnvelope->m_vPoints.size(); i++)
|
||||
{
|
||||
const float PosX = pEnvelope->m_vPoints[i].m_Time / 1000.0f / EndTime;
|
||||
const float PosY = (fx2f(pEnvelope->m_vPoints[i].m_aValues[c]) - Bottom) / (Top - Bottom);
|
||||
float PosX = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i].m_Time));
|
||||
float PosY = EnvelopeToScreenY(View, fx2f(pEnvelope->m_vPoints[i].m_aValues[c]));
|
||||
|
||||
// Out-Tangent
|
||||
if(pEnvelope->m_vPoints[i].m_Curvetype == CURVETYPE_BEZIER)
|
||||
{
|
||||
const float OutTangentX = PosX + pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] / 1000.0f / EndTime;
|
||||
const float OutTangentY = PosY + fx2f(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c]) / (Top - Bottom);
|
||||
float TangentX = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i].m_Time + pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c]));
|
||||
float TangentY = EnvelopeToScreenY(View, fx2f(pEnvelope->m_vPoints[i].m_aValues[c] + pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c]));
|
||||
|
||||
if(s_pSelectedPoint == &pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] || (m_SelectedQuadEnvelope == m_SelectedEnvelope && m_SelectedEnvelopePoint == i))
|
||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
||||
else
|
||||
Graphics()->SetColor(aColors[c].r, aColors[c].g, aColors[c].b, 0.4f);
|
||||
|
||||
IGraphics::CLineItem LineItem(View.x + PosX * View.w, View.y + View.h - PosY * View.h, View.x + OutTangentX * View.w, View.y + View.h - OutTangentY * View.h);
|
||||
IGraphics::CLineItem LineItem(TangentX, TangentY, PosX, PosY);
|
||||
Graphics()->LinesDraw(&LineItem, 1);
|
||||
}
|
||||
|
||||
// In-Tangent
|
||||
if(i > 0 && pEnvelope->m_vPoints[i - 1].m_Curvetype == CURVETYPE_BEZIER)
|
||||
{
|
||||
const float InTangentX = PosX + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] / 1000.0f / EndTime;
|
||||
const float InTangentY = PosY + fx2f(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c]) / (Top - Bottom);
|
||||
float TangentX = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i].m_Time + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c]));
|
||||
float TangentY = EnvelopeToScreenY(View, fx2f(pEnvelope->m_vPoints[i].m_aValues[c] + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c]));
|
||||
|
||||
if(s_pSelectedPoint == &pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] || (m_SelectedQuadEnvelope == m_SelectedEnvelope && m_SelectedEnvelopePoint == i))
|
||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
||||
else
|
||||
Graphics()->SetColor(aColors[c].r, aColors[c].g, aColors[c].b, 0.4f);
|
||||
|
||||
IGraphics::CLineItem LineItem(View.x + PosX * View.w, View.y + View.h - PosY * View.h, View.x + InTangentX * View.w, View.y + View.h - InTangentY * View.h);
|
||||
IGraphics::CLineItem LineItem(TangentX, TangentY, PosX, PosY);
|
||||
Graphics()->LinesDraw(&LineItem, 1);
|
||||
}
|
||||
}
|
||||
|
@ -5926,6 +6085,13 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
|
||||
// render lines
|
||||
{
|
||||
float EndTimeTotal = maximum(0.000001f, pEnvelope->EndTime());
|
||||
float EndX = clamp(EnvelopeToScreenX(View, EndTimeTotal), View.x, View.x + View.w);
|
||||
float StartX = clamp(View.x + View.w * m_OffsetEnvelopeX, View.x, View.x + View.w);
|
||||
|
||||
float EndTime = ScreenToEnvelopeX(View, EndX);
|
||||
float StartTime = ScreenToEnvelopeX(View, StartX);
|
||||
|
||||
UI()->ClipEnable(&View);
|
||||
Graphics()->TextureClear();
|
||||
Graphics()->LinesBegin();
|
||||
|
@ -5936,23 +6102,26 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
else
|
||||
Graphics()->SetColor(aColors[c].r * 0.5f, aColors[c].g * 0.5f, aColors[c].b * 0.5f, 1);
|
||||
|
||||
float PrevX = 0;
|
||||
int Steps = static_cast<int>(((EndX - StartX) / UI()->Screen()->w) * Graphics()->ScreenWidth());
|
||||
float StepTime = (EndTime - StartTime) / static_cast<float>(Steps);
|
||||
float StepSize = (EndX - StartX) / static_cast<float>(Steps);
|
||||
|
||||
ColorRGBA Channels;
|
||||
pEnvelope->Eval(0.000001f, Channels);
|
||||
float PrevValue = Channels[c];
|
||||
|
||||
int Steps = (int)((View.w / UI()->Screen()->w) * Graphics()->ScreenWidth());
|
||||
for(int i = 1; i <= Steps; i++)
|
||||
pEnvelope->Eval(StartTime + StepTime, Channels);
|
||||
float PrevY = EnvelopeToScreenY(View, Channels[c]);
|
||||
for(int i = 2; i < Steps; i++)
|
||||
{
|
||||
float a = i / (float)Steps;
|
||||
pEnvelope->Eval(a * EndTime, Channels);
|
||||
float v = Channels[c];
|
||||
v = (v - Bottom) / (Top - Bottom);
|
||||
pEnvelope->Eval(StartTime + i * StepTime, Channels);
|
||||
float CurrentY = EnvelopeToScreenY(View, Channels[c]);
|
||||
|
||||
IGraphics::CLineItem LineItem(View.x + PrevX * View.w, View.y + View.h - PrevValue * View.h, View.x + a * View.w, View.y + View.h - v * View.h);
|
||||
IGraphics::CLineItem LineItem(
|
||||
StartX + (i - 1) * StepSize,
|
||||
PrevY,
|
||||
StartX + i * StepSize,
|
||||
CurrentY);
|
||||
Graphics()->LinesDraw(&LineItem, 1);
|
||||
PrevX = a;
|
||||
PrevValue = v;
|
||||
|
||||
PrevY = CurrentY;
|
||||
}
|
||||
}
|
||||
Graphics()->LinesEnd();
|
||||
|
@ -5963,11 +6132,11 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
{
|
||||
for(int i = 0; i < (int)pEnvelope->m_vPoints.size() - 1; i++)
|
||||
{
|
||||
float t0 = pEnvelope->m_vPoints[i].m_Time / 1000.0f / EndTime;
|
||||
float t1 = pEnvelope->m_vPoints[i + 1].m_Time / 1000.0f / EndTime;
|
||||
float t0 = fxt2f(pEnvelope->m_vPoints[i].m_Time);
|
||||
float t1 = fxt2f(pEnvelope->m_vPoints[i + 1].m_Time);
|
||||
|
||||
CUIRect CurveButton;
|
||||
CurveButton.x = CurveBar.x + (t0 + (t1 - t0) * 0.5f) * CurveBar.w;
|
||||
CurveButton.x = EnvelopeToScreenX(View, t0 + (t1 - t0) * 0.5f);
|
||||
CurveButton.y = CurveBar.y;
|
||||
CurveButton.h = CurveBar.h;
|
||||
CurveButton.w = CurveBar.h;
|
||||
|
@ -5977,14 +6146,29 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
const char *pTypeName = "!?";
|
||||
if(0 <= pEnvelope->m_vPoints[i].m_Curvetype && pEnvelope->m_vPoints[i].m_Curvetype < (int)std::size(apTypeName))
|
||||
pTypeName = apTypeName[pEnvelope->m_vPoints[i].m_Curvetype];
|
||||
|
||||
if(CurveButton.x >= View.x)
|
||||
{
|
||||
if(DoButton_Editor(pID, pTypeName, 0, &CurveButton, 0, "Switch curve type (N = step, L = linear, S = slow, F = fast, M = smooth, B = bezier)"))
|
||||
pEnvelope->m_vPoints[i].m_Curvetype = (pEnvelope->m_vPoints[i].m_Curvetype + 1) % NUM_CURVETYPES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render colorbar
|
||||
if(ShowColorBar)
|
||||
{
|
||||
UI()->ClipEnable(&ColorBar);
|
||||
|
||||
float StartX = maximum(EnvelopeToScreenX(View, 0), ColorBar.x);
|
||||
float EndX = EnvelopeToScreenX(View, pEnvelope->EndTime());
|
||||
CUIRect BackgroundView{
|
||||
StartX,
|
||||
ColorBar.y,
|
||||
minimum(EndX - StartX, ColorBar.x + ColorBar.w - StartX),
|
||||
ColorBar.h};
|
||||
RenderBackground(BackgroundView, m_CheckerTexture, 16.0f, 1.0f);
|
||||
|
||||
Graphics()->TextureClear();
|
||||
Graphics()->QuadsBegin();
|
||||
for(int i = 0; i < (int)pEnvelope->m_vPoints.size() - 1; i++)
|
||||
|
@ -6004,13 +6188,14 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
IGraphics::CColorVertex(3, r0, g0, b0, a0)};
|
||||
Graphics()->SetColorVertex(Array, 4);
|
||||
|
||||
float x0 = pEnvelope->m_vPoints[i].m_Time / 1000.0f / EndTime;
|
||||
float x1 = pEnvelope->m_vPoints[i + 1].m_Time / 1000.0f / EndTime;
|
||||
float x0 = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i].m_Time));
|
||||
float x1 = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i + 1].m_Time));
|
||||
|
||||
IGraphics::CQuadItem QuadItem(ColorBar.x + x0 * ColorBar.w, ColorBar.y, (x1 - x0) * ColorBar.w, ColorBar.h);
|
||||
IGraphics::CQuadItem QuadItem(x0, ColorBar.y, x1 - x0, ColorBar.h);
|
||||
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
||||
}
|
||||
Graphics()->QuadsEnd();
|
||||
UI()->ClipDisable();
|
||||
}
|
||||
|
||||
// render handles
|
||||
|
@ -6025,9 +6210,12 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
// update displayed text
|
||||
s_CurValueInput.SetFloat(0.0f);
|
||||
s_CurTimeInput.SetFloat(0.0f);
|
||||
|
||||
m_ResetZoomEnvelope = true;
|
||||
}
|
||||
|
||||
{
|
||||
UI()->ClipEnable(&View);
|
||||
Graphics()->TextureClear();
|
||||
Graphics()->QuadsBegin();
|
||||
for(int c = 0; c < pEnvelope->GetChannels(); c++)
|
||||
|
@ -6039,11 +6227,9 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
{
|
||||
// point handle
|
||||
{
|
||||
const float PosX = pEnvelope->m_vPoints[i].m_Time / 1000.0f / EndTime;
|
||||
const float PosY = (fx2f(pEnvelope->m_vPoints[i].m_aValues[c]) - Bottom) / (Top - Bottom);
|
||||
CUIRect Final;
|
||||
Final.x = View.x + PosX * View.w;
|
||||
Final.y = View.y + View.h - PosY * View.h;
|
||||
Final.x = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i].m_Time));
|
||||
Final.y = EnvelopeToScreenY(View, fx2f(pEnvelope->m_vPoints[i].m_aValues[c]));
|
||||
Final.x -= 2.0f;
|
||||
Final.y -= 2.0f;
|
||||
Final.w = 4.0f;
|
||||
|
@ -6051,7 +6237,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
|
||||
const void *pID = &pEnvelope->m_vPoints[i].m_aValues[c];
|
||||
|
||||
if(UI()->MouseInside(&Final))
|
||||
if(UI()->MouseInside(&Final) && UI()->MouseInside(&View))
|
||||
UI()->SetHotItem(pID);
|
||||
|
||||
float ColorMod = 1.0f;
|
||||
|
@ -6063,27 +6249,69 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
m_SelectedQuadEnvelope = -1;
|
||||
m_SelectedEnvelopePoint = -1;
|
||||
|
||||
s_Operation = OP_NONE;
|
||||
|
||||
UI()->SetActiveItem(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Input()->ShiftIsPressed())
|
||||
{
|
||||
if(i != 0)
|
||||
if(s_Operation == OP_NONE || s_Operation == OP_DRAG_POINT_Y)
|
||||
{
|
||||
float DeltaX = m_MouseDeltaX * TimeScale * (Input()->ModifierIsPressed() ? 1.0f : 1000.0f);
|
||||
DeltaX = DeltaX < 0 ? -std::ceil(-DeltaX) : std::ceil(DeltaX);
|
||||
pEnvelope->m_vPoints[i].m_Time += (int)DeltaX;
|
||||
s_Operation = OP_DRAG_POINT_X;
|
||||
s_AccurateDragValueX = pEnvelope->m_vPoints[i].m_Time;
|
||||
}
|
||||
else
|
||||
{
|
||||
float DeltaX = ScreenToEnvelopeDX(View, UI()->MouseDeltaX()) * (Input()->ModifierIsPressed() ? 50.0f : 1000.0f);
|
||||
s_AccurateDragValueX += DeltaX;
|
||||
|
||||
if(pEnvelope->m_vPoints[i].m_Time < pEnvelope->m_vPoints[i - 1].m_Time)
|
||||
pEnvelope->m_vPoints[i].m_Time = std::round(s_AccurateDragValueX);
|
||||
if(i == 0 && pEnvelope->m_vPoints[i].m_Time != 0)
|
||||
{
|
||||
RemoveTimeOffsetEnvelope(pEnvelope);
|
||||
s_AccurateDragValueX = 0.0f;
|
||||
}
|
||||
if(i != 0 && pEnvelope->m_vPoints[i].m_Time < pEnvelope->m_vPoints[i - 1].m_Time)
|
||||
{
|
||||
pEnvelope->m_vPoints[i].m_Time = pEnvelope->m_vPoints[i - 1].m_Time + 1;
|
||||
if(i + 1 != pEnvelope->m_vPoints.size() && pEnvelope->m_vPoints[i].m_Time > pEnvelope->m_vPoints[i + 1].m_Time)
|
||||
s_AccurateDragValueX = pEnvelope->m_vPoints[i - 1].m_Time + 1;
|
||||
}
|
||||
if(i < pEnvelope->m_vPoints.size() - 1 && pEnvelope->m_vPoints[i].m_Time > pEnvelope->m_vPoints[i + 1].m_Time)
|
||||
{
|
||||
pEnvelope->m_vPoints[i].m_Time = pEnvelope->m_vPoints[i + 1].m_Time - 1;
|
||||
s_AccurateDragValueX = pEnvelope->m_vPoints[i + 1].m_Time - 1;
|
||||
}
|
||||
|
||||
pEnvelope->m_vPoints[i].m_Time = clamp(pEnvelope->m_vPoints[i].m_Time, f2fxt(ScreenToEnvelopeX(View, View.x)), f2fxt(ScreenToEnvelopeX(View, View.x + View.w)));
|
||||
s_AccurateDragValueX = clamp<float>(s_AccurateDragValueX, f2fxt(ScreenToEnvelopeX(View, View.x)), f2fxt(ScreenToEnvelopeX(View, View.x + View.w)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pEnvelope->m_vPoints[i].m_aValues[c] -= f2fx(m_MouseDeltaY * (Input()->ModifierIsPressed() ? 0.001f : ValueScale));
|
||||
if(s_Operation == OP_NONE || s_Operation == OP_DRAG_POINT_X)
|
||||
{
|
||||
s_Operation = OP_DRAG_POINT_Y;
|
||||
s_AccurateDragValueY = pEnvelope->m_vPoints[i].m_aValues[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
float DeltaY = ScreenToEnvelopeDY(View, UI()->MouseDeltaY()) * (Input()->ModifierIsPressed() ? 51.2f : 1024.0f);
|
||||
s_AccurateDragValueY -= DeltaY;
|
||||
|
||||
pEnvelope->m_vPoints[i].m_aValues[c] = std::round(s_AccurateDragValueY);
|
||||
if(pEnvelope->GetChannels() == 4)
|
||||
{
|
||||
pEnvelope->m_vPoints[i].m_aValues[c] = clamp(pEnvelope->m_vPoints[i].m_aValues[c], 0, 1024);
|
||||
s_AccurateDragValueY = clamp<float>(s_AccurateDragValueY, 0, 1024);
|
||||
}
|
||||
else
|
||||
{
|
||||
pEnvelope->m_vPoints[i].m_aValues[c] = clamp(pEnvelope->m_vPoints[i].m_aValues[c], f2fx(ScreenToEnvelopeY(View, View.y + View.h)), f2fx(ScreenToEnvelopeY(View, View.y)));
|
||||
s_AccurateDragValueY = clamp<float>(s_AccurateDragValueY, f2fx(ScreenToEnvelopeY(View, View.y + View.h)), f2fx(ScreenToEnvelopeY(View, View.y)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_SelectedQuadEnvelope = m_SelectedEnvelope;
|
||||
|
@ -6104,7 +6332,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
}
|
||||
|
||||
// remove point
|
||||
if(UI()->MouseButtonClicked(1))
|
||||
if(UI()->MouseButtonClicked(1) && pEnvelope->m_vPoints.size() > 2)
|
||||
{
|
||||
if(s_pSelectedPoint == pID)
|
||||
{
|
||||
|
@ -6165,18 +6393,12 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
|
||||
// tangent handles for bezier curves
|
||||
{
|
||||
const float PosX = pEnvelope->m_vPoints[i].m_Time / 1000.0f / EndTime;
|
||||
const float PosY = (fx2f(pEnvelope->m_vPoints[i].m_aValues[c]) - Bottom) / (Top - Bottom);
|
||||
|
||||
// Out-Tangent handle
|
||||
if(pEnvelope->m_vPoints[i].m_Curvetype == CURVETYPE_BEZIER)
|
||||
{
|
||||
const float OutTangentX = PosX + (pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] / 1000.0f / EndTime);
|
||||
const float OutTangentY = PosY + fx2f(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c]) / (Top - Bottom);
|
||||
|
||||
CUIRect Final;
|
||||
Final.x = View.x + OutTangentX * View.w;
|
||||
Final.y = View.y + View.h - OutTangentY * View.h;
|
||||
Final.x = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i].m_Time + pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c]));
|
||||
Final.y = EnvelopeToScreenY(View, fx2f(pEnvelope->m_vPoints[i].m_aValues[c] + pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c]));
|
||||
Final.x -= 2.0f;
|
||||
Final.y -= 2.0f;
|
||||
Final.w = 4.0f;
|
||||
|
@ -6187,7 +6409,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
const void *pID = &pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c];
|
||||
|
||||
float ColorMod = 1.0f;
|
||||
if(UI()->MouseInside(&Final))
|
||||
if(UI()->MouseInside(&Final) && UI()->MouseInside(&View))
|
||||
UI()->SetHotItem(pID);
|
||||
|
||||
if(UI()->CheckActiveItem(pID))
|
||||
|
@ -6197,17 +6419,32 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
m_SelectedQuadEnvelope = -1;
|
||||
m_SelectedEnvelopePoint = -1;
|
||||
|
||||
s_Operation = OP_NONE;
|
||||
|
||||
UI()->SetActiveItem(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
float DeltaX = m_MouseDeltaX * TimeScale * (Input()->ModifierIsPressed() ? 1.0f : 1000.0f);
|
||||
DeltaX = DeltaX < 0 ? -std::ceil(-DeltaX) : std::ceil(DeltaX);
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] += (int)DeltaX;
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c] -= f2fx(m_MouseDeltaY * (Input()->ModifierIsPressed() ? 0.005f : ValueScale));
|
||||
if(s_Operation == OP_NONE)
|
||||
{
|
||||
s_Operation = OP_DRAG_POINT;
|
||||
s_AccurateDragValueX = pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c];
|
||||
s_AccurateDragValueY = pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
float DeltaX = ScreenToEnvelopeDX(View, UI()->MouseDeltaX()) * (Input()->ModifierIsPressed() ? 50.0f : 1000.0f);
|
||||
float DeltaY = ScreenToEnvelopeDY(View, UI()->MouseDeltaY()) * (Input()->ModifierIsPressed() ? 51.2f : 1024.0f);
|
||||
s_AccurateDragValueX += DeltaX;
|
||||
s_AccurateDragValueY -= DeltaY;
|
||||
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] = std::round(s_AccurateDragValueX);
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c] = std::round(s_AccurateDragValueY);
|
||||
|
||||
// clamp time value
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] = clamp<int>(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c], 0, EndTime * 1000.0f - pEnvelope->m_vPoints[i].m_Time);
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] = clamp<int>(pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c], 0, f2fxt(ScreenToEnvelopeX(View, View.x + View.w)) - pEnvelope->m_vPoints[i].m_Time);
|
||||
s_AccurateDragValueX = clamp<float>(s_AccurateDragValueX, 0, f2fxt(ScreenToEnvelopeX(View, View.x + View.w)) - pEnvelope->m_vPoints[i].m_Time);
|
||||
}
|
||||
|
||||
m_SelectedQuadEnvelope = m_SelectedEnvelope;
|
||||
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
||||
|
@ -6242,7 +6479,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
|
||||
if(pID == s_pSelectedPoint && UI()->ConsumeHotkey(CUI::HOTKEY_ENTER))
|
||||
{
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] = clamp<int>(s_CurTimeInput.GetFloat() * 1000.0f - pEnvelope->m_vPoints[i].m_Time, 0, EndTime * 1000.0f - pEnvelope->m_vPoints[i].m_Time);
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaX[c] = clamp<int>(s_CurTimeInput.GetFloat() * 1000.0f - pEnvelope->m_vPoints[i].m_Time, 0, pEnvelope->m_vPoints[i + 1].m_Time - pEnvelope->m_vPoints[i].m_Time);
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aOutTangentDeltaY[c] = f2fx(s_CurValueInput.GetFloat()) - pEnvelope->m_vPoints[i].m_aValues[c];
|
||||
Updated = true;
|
||||
}
|
||||
|
@ -6270,12 +6507,9 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
// In-Tangent handle
|
||||
if(i > 0 && pEnvelope->m_vPoints[i - 1].m_Curvetype == CURVETYPE_BEZIER)
|
||||
{
|
||||
const float InTangentX = PosX + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] / 1000.0f / EndTime;
|
||||
const float InTangentY = PosY + fx2f(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c]) / (Top - Bottom);
|
||||
|
||||
CUIRect Final;
|
||||
Final.x = View.x + InTangentX * View.w;
|
||||
Final.y = View.y + View.h - InTangentY * View.h;
|
||||
Final.x = EnvelopeToScreenX(View, fxt2f(pEnvelope->m_vPoints[i].m_Time + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c]));
|
||||
Final.y = EnvelopeToScreenY(View, fx2f(pEnvelope->m_vPoints[i].m_aValues[c] + pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c]));
|
||||
Final.x -= 2.0f;
|
||||
Final.y -= 2.0f;
|
||||
Final.w = 4.0f;
|
||||
|
@ -6286,7 +6520,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
const void *pID = &pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c];
|
||||
|
||||
float ColorMod = 1.0f;
|
||||
if(UI()->MouseInside(&Final))
|
||||
if(UI()->MouseInside(&Final) && UI()->MouseInside(&View))
|
||||
UI()->SetHotItem(pID);
|
||||
|
||||
if(UI()->CheckActiveItem(pID))
|
||||
|
@ -6296,17 +6530,32 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
m_SelectedQuadEnvelope = -1;
|
||||
m_SelectedEnvelopePoint = -1;
|
||||
|
||||
s_Operation = OP_NONE;
|
||||
|
||||
UI()->SetActiveItem(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
float DeltaX = m_MouseDeltaX * TimeScale * (Input()->ModifierIsPressed() ? 1.0f : 1000.0f);
|
||||
DeltaX = DeltaX < 0 ? -std::ceil(-DeltaX) : std::ceil(DeltaX);
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] += (int)DeltaX;
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c] -= f2fx(m_MouseDeltaY * (Input()->ModifierIsPressed() ? 0.005f : ValueScale));
|
||||
if(s_Operation == OP_NONE)
|
||||
{
|
||||
s_Operation = OP_DRAG_POINT;
|
||||
s_AccurateDragValueX = pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c];
|
||||
s_AccurateDragValueY = pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
float DeltaX = ScreenToEnvelopeDX(View, UI()->MouseDeltaX()) * (Input()->ModifierIsPressed() ? 50.0f : 1000.0f);
|
||||
float DeltaY = ScreenToEnvelopeDY(View, UI()->MouseDeltaY()) * (Input()->ModifierIsPressed() ? 51.2f : 1024.0f);
|
||||
s_AccurateDragValueX += DeltaX;
|
||||
s_AccurateDragValueY -= DeltaY;
|
||||
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] = std::round(s_AccurateDragValueX);
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaY[c] = std::round(s_AccurateDragValueY);
|
||||
|
||||
// clamp time value
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] = clamp(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c], -pEnvelope->m_vPoints[i].m_Time, 0);
|
||||
pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c] = clamp(pEnvelope->m_vPoints[i].m_Bezier.m_aInTangentDeltaX[c], f2fxt(ScreenToEnvelopeX(View, View.x)) - pEnvelope->m_vPoints[i].m_Time, 0);
|
||||
s_AccurateDragValueX = clamp<float>(s_AccurateDragValueX, f2fxt(ScreenToEnvelopeX(View, View.x)) - pEnvelope->m_vPoints[i].m_Time, 0);
|
||||
}
|
||||
|
||||
m_SelectedQuadEnvelope = m_SelectedEnvelope;
|
||||
m_ShowEnvelopePreview = SHOWENV_SELECTED;
|
||||
|
@ -6369,6 +6618,7 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
|
|||
}
|
||||
}
|
||||
Graphics()->QuadsEnd();
|
||||
UI()->ClipDisable();
|
||||
}
|
||||
|
||||
if(s_pSelectedPoint != nullptr)
|
||||
|
@ -6658,7 +6908,7 @@ void CEditor::RenderMenubar(CUIRect MenuBar)
|
|||
char aTimeStr[6];
|
||||
str_timestamp_format(aTimeStr, sizeof(aTimeStr), "%H:%M");
|
||||
|
||||
str_format(aBuf, sizeof(aBuf), "X: %.1f, Y: %.1f, Z: %.1f, A: %.1f, G: %i %s", UI()->MouseWorldX() / 32.0f, UI()->MouseWorldY() / 32.0f, m_Zoom, m_AnimateSpeed, m_GridFactor, aTimeStr);
|
||||
str_format(aBuf, sizeof(aBuf), "X: %.1f, Y: %.1f, Z: %.1f, A: %.1f, G: %i %s", UI()->MouseWorldX() / 32.0f, UI()->MouseWorldY() / 32.0f, m_ZoomMapView.GetZoom(), m_AnimateSpeed, m_GridFactor, aTimeStr);
|
||||
UI()->DoLabel(&Info, aBuf, 10.0f, TEXTALIGN_MR);
|
||||
|
||||
static int s_CloseButton = 0;
|
||||
|
@ -6715,14 +6965,14 @@ void CEditor::Render()
|
|||
{
|
||||
// handle zoom hotkeys
|
||||
if(Input()->KeyPress(KEY_KP_MINUS))
|
||||
ChangeZoom(50.0f);
|
||||
m_ZoomMapView.ChangeZoom(50.0f);
|
||||
if(Input()->KeyPress(KEY_KP_PLUS))
|
||||
ChangeZoom(-50.0f);
|
||||
m_ZoomMapView.ChangeZoom(-50.0f);
|
||||
if(Input()->KeyPress(KEY_KP_MULTIPLY))
|
||||
{
|
||||
m_EditorOffsetX = 0;
|
||||
m_EditorOffsetY = 0;
|
||||
SetZoom(100.0f);
|
||||
m_ZoomMapView.SetZoom(100.0f);
|
||||
}
|
||||
|
||||
// handle brush save/load hotkeys
|
||||
|
@ -6937,12 +7187,12 @@ void CEditor::Render()
|
|||
if(m_Dialog == DIALOG_NONE && !UI()->IsPopupHovered() && (!m_GuiActive || UI()->MouseInside(&View)))
|
||||
{
|
||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN))
|
||||
ChangeZoom(20.0f);
|
||||
m_ZoomMapView.ChangeZoom(20.0f);
|
||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP))
|
||||
ChangeZoom(-20.0f);
|
||||
m_ZoomMapView.ChangeZoom(-20.0f);
|
||||
}
|
||||
|
||||
UpdateZoom();
|
||||
UpdateZoomWorld();
|
||||
|
||||
// Popup menus must be rendered before the statusbar, because UI elements in
|
||||
// popup menus can set tooltips, which are rendered in the status bar.
|
||||
|
@ -7047,8 +7297,6 @@ void CEditor::Reset(bool CreateDefault)
|
|||
m_EditorOffsetX = 0.0f;
|
||||
m_EditorOffsetY = 0.0f;
|
||||
|
||||
m_Zoom = 200.0f;
|
||||
m_Zooming = false;
|
||||
m_WorldZoom = 1.0f;
|
||||
|
||||
m_MouseDeltaX = 0;
|
||||
|
@ -7064,52 +7312,26 @@ void CEditor::Reset(bool CreateDefault)
|
|||
|
||||
m_ShowEnvelopePreview = SHOWENV_NONE;
|
||||
m_ShiftBy = 1;
|
||||
|
||||
m_ResetZoomEnvelope = true;
|
||||
}
|
||||
|
||||
int CEditor::GetLineDistance() const
|
||||
{
|
||||
if(m_Zoom <= 100.0f)
|
||||
if(m_ZoomMapView.GetZoom() <= 100.0f)
|
||||
return 16;
|
||||
else if(m_Zoom <= 250.0f)
|
||||
else if(m_ZoomMapView.GetZoom() <= 250.0f)
|
||||
return 32;
|
||||
else if(m_Zoom <= 450.0f)
|
||||
else if(m_ZoomMapView.GetZoom() <= 450.0f)
|
||||
return 64;
|
||||
else if(m_Zoom <= 850.0f)
|
||||
else if(m_ZoomMapView.GetZoom() <= 850.0f)
|
||||
return 128;
|
||||
else if(m_Zoom <= 1550.0f)
|
||||
else if(m_ZoomMapView.GetZoom() <= 1550.0f)
|
||||
return 256;
|
||||
else
|
||||
return 512;
|
||||
}
|
||||
|
||||
void CEditor::SetZoom(float Target)
|
||||
{
|
||||
Target = clamp(Target, MinZoomLevel(), MaxZoomLevel());
|
||||
|
||||
const float Now = Client()->GlobalTime();
|
||||
float Current = m_Zoom;
|
||||
float Derivative = 0.0f;
|
||||
if(m_Zooming)
|
||||
{
|
||||
const float Progress = ZoomProgress(Now);
|
||||
Current = m_ZoomSmoothing.Evaluate(Progress);
|
||||
Derivative = m_ZoomSmoothing.Derivative(Progress);
|
||||
}
|
||||
|
||||
m_ZoomSmoothingTarget = Target;
|
||||
m_ZoomSmoothing = CCubicBezier::With(Current, Derivative, 0.0f, m_ZoomSmoothingTarget);
|
||||
m_ZoomSmoothingStart = Now;
|
||||
m_ZoomSmoothingEnd = Now + g_Config.m_EdSmoothZoomTime / 1000.0f;
|
||||
|
||||
m_Zooming = true;
|
||||
}
|
||||
|
||||
void CEditor::ChangeZoom(float Amount)
|
||||
{
|
||||
const float CurrentTarget = m_Zooming ? m_ZoomSmoothingTarget : m_Zoom;
|
||||
SetZoom(CurrentTarget + Amount);
|
||||
}
|
||||
|
||||
void CEditor::ZoomMouseTarget(float ZoomFactor)
|
||||
{
|
||||
// zoom to the current mouse position
|
||||
|
@ -7130,47 +7352,14 @@ void CEditor::ZoomMouseTarget(float ZoomFactor)
|
|||
m_WorldOffsetY += (Mwy - m_WorldOffsetY) * (1.0f - ZoomFactor);
|
||||
}
|
||||
|
||||
void CEditor::UpdateZoom()
|
||||
void CEditor::UpdateZoomWorld()
|
||||
{
|
||||
if(m_Zooming)
|
||||
{
|
||||
const float Time = Client()->GlobalTime();
|
||||
const float OldLevel = m_Zoom;
|
||||
if(Time >= m_ZoomSmoothingEnd)
|
||||
{
|
||||
m_Zoom = m_ZoomSmoothingTarget;
|
||||
m_Zooming = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Zoom = m_ZoomSmoothing.Evaluate(ZoomProgress(Time));
|
||||
if((OldLevel < m_ZoomSmoothingTarget && m_Zoom > m_ZoomSmoothingTarget) || (OldLevel > m_ZoomSmoothingTarget && m_Zoom < m_ZoomSmoothingTarget))
|
||||
{
|
||||
m_Zoom = m_ZoomSmoothingTarget;
|
||||
m_Zooming = false;
|
||||
}
|
||||
}
|
||||
m_Zoom = clamp(m_Zoom, MinZoomLevel(), MaxZoomLevel());
|
||||
if(g_Config.m_EdZoomTarget)
|
||||
ZoomMouseTarget(m_Zoom / OldLevel);
|
||||
}
|
||||
|
||||
m_WorldZoom = m_Zoom / 100.0f;
|
||||
}
|
||||
|
||||
float CEditor::MinZoomLevel() const
|
||||
{
|
||||
return 10.0f;
|
||||
}
|
||||
|
||||
float CEditor::MaxZoomLevel() const
|
||||
{
|
||||
return g_Config.m_EdLimitMaxZoomLevel ? 2000.0f : std::numeric_limits<float>::max();
|
||||
}
|
||||
|
||||
float CEditor::ZoomProgress(float CurrentTime) const
|
||||
{
|
||||
return (CurrentTime - m_ZoomSmoothingStart) / (m_ZoomSmoothingEnd - m_ZoomSmoothingStart);
|
||||
float OldLevel = m_ZoomMapView.GetZoom();
|
||||
m_ZoomMapView.SetZoomRange(10.0f, g_Config.m_EdLimitMaxZoomLevel ? 2000.0f : std::numeric_limits<float>::max());
|
||||
float NewLevel = m_ZoomMapView.GetZoom();
|
||||
if(m_ZoomMapView.UpdateZoom() && g_Config.m_EdZoomTarget)
|
||||
ZoomMouseTarget(NewLevel / OldLevel);
|
||||
m_WorldZoom = NewLevel / 100.0f;
|
||||
}
|
||||
|
||||
void CEditor::Goto(float X, float Y)
|
||||
|
@ -7813,3 +8002,90 @@ void CEditorMap::MakeTuneLayer(CLayer *pLayer)
|
|||
m_pTuneLayer->m_pEditor = m_pEditor;
|
||||
m_pTuneLayer->m_Texture = m_pEditor->GetTuneTexture();
|
||||
}
|
||||
|
||||
CSmoothZoom::CSmoothZoom(float InitialZoom, float Min, float Max, CEditor *pEditor)
|
||||
{
|
||||
m_Zoom = InitialZoom;
|
||||
m_MinZoomLevel = Min;
|
||||
m_MaxZoomLevel = Max;
|
||||
m_pEditor = pEditor;
|
||||
m_Zooming = false;
|
||||
}
|
||||
|
||||
void CSmoothZoom::SetZoom(float Target)
|
||||
{
|
||||
Target = clamp(Target, m_MinZoomLevel, m_MaxZoomLevel);
|
||||
|
||||
const float Now = m_pEditor->Client()->GlobalTime();
|
||||
float Current = m_Zoom;
|
||||
float Derivative = 0.0f;
|
||||
if(m_Zooming)
|
||||
{
|
||||
const float Progress = ZoomProgress(Now);
|
||||
Current = m_ZoomSmoothing.Evaluate(Progress);
|
||||
Derivative = m_ZoomSmoothing.Derivative(Progress);
|
||||
}
|
||||
|
||||
m_ZoomSmoothingTarget = Target;
|
||||
m_ZoomSmoothing = CCubicBezier::With(Current, Derivative, 0.0f, m_ZoomSmoothingTarget);
|
||||
m_ZoomSmoothingStart = Now;
|
||||
m_ZoomSmoothingEnd = Now + g_Config.m_EdSmoothZoomTime / 1000.0f;
|
||||
|
||||
m_Zooming = true;
|
||||
}
|
||||
|
||||
void CSmoothZoom::ChangeZoom(float Amount)
|
||||
{
|
||||
const float CurrentTarget = m_Zooming ? m_ZoomSmoothingTarget : m_Zoom;
|
||||
SetZoom(CurrentTarget + Amount);
|
||||
}
|
||||
|
||||
bool CSmoothZoom::UpdateZoom()
|
||||
{
|
||||
if(m_Zooming)
|
||||
{
|
||||
const float Time = m_pEditor->Client()->GlobalTime();
|
||||
const float OldLevel = m_Zoom;
|
||||
if(Time >= m_ZoomSmoothingEnd)
|
||||
{
|
||||
m_Zoom = m_ZoomSmoothingTarget;
|
||||
m_Zooming = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Zoom = m_ZoomSmoothing.Evaluate(ZoomProgress(Time));
|
||||
if((OldLevel < m_ZoomSmoothingTarget && m_Zoom > m_ZoomSmoothingTarget) || (OldLevel > m_ZoomSmoothingTarget && m_Zoom < m_ZoomSmoothingTarget))
|
||||
{
|
||||
m_Zoom = m_ZoomSmoothingTarget;
|
||||
m_Zooming = false;
|
||||
}
|
||||
}
|
||||
m_Zoom = clamp(m_Zoom, m_MinZoomLevel, m_MaxZoomLevel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float CSmoothZoom::ZoomProgress(float CurrentTime) const
|
||||
{
|
||||
return (CurrentTime - m_ZoomSmoothingStart) / (m_ZoomSmoothingEnd - m_ZoomSmoothingStart);
|
||||
}
|
||||
|
||||
float CSmoothZoom::GetZoom() const
|
||||
{
|
||||
return m_Zoom;
|
||||
}
|
||||
|
||||
void CSmoothZoom::SetZoomRange(float Min, float Max)
|
||||
{
|
||||
m_MinZoomLevel = Min;
|
||||
m_MaxZoomLevel = Max;
|
||||
}
|
||||
|
||||
void CSmoothZoom::SetZoomInstant(float Target)
|
||||
{
|
||||
m_Zooming = false;
|
||||
m_Zoom = Target;
|
||||
}
|
||||
|
|
|
@ -790,6 +790,34 @@ public:
|
|||
const char *GetTempFileName() const { return m_aTempFileName; }
|
||||
};
|
||||
|
||||
class CSmoothZoom
|
||||
{
|
||||
public:
|
||||
CSmoothZoom(float InitialZoom, float Min, float Max, CEditor *pEditor);
|
||||
|
||||
void SetZoomRange(float Min, float Max);
|
||||
void SetZoom(float Target);
|
||||
void SetZoomInstant(float Target);
|
||||
void ChangeZoom(float Amount);
|
||||
bool UpdateZoom();
|
||||
float GetZoom() const;
|
||||
|
||||
private:
|
||||
float ZoomProgress(float CurrentTime) const;
|
||||
|
||||
bool m_Zooming;
|
||||
float m_Zoom;
|
||||
CCubicBezier m_ZoomSmoothing;
|
||||
float m_ZoomSmoothingTarget;
|
||||
float m_ZoomSmoothingStart;
|
||||
float m_ZoomSmoothingEnd;
|
||||
|
||||
float m_MinZoomLevel;
|
||||
float m_MaxZoomLevel;
|
||||
|
||||
CEditor *m_pEditor;
|
||||
};
|
||||
|
||||
class CEditor : public IEditor
|
||||
{
|
||||
class IInput *m_pInput = nullptr;
|
||||
|
@ -837,6 +865,9 @@ public:
|
|||
CRenderTools *RenderTools() { return &m_RenderTools; }
|
||||
|
||||
CEditor() :
|
||||
m_ZoomMapView(200.0f, 10.0f, 2000.0f, this),
|
||||
m_ZoomEnvelopeX(1.0f, 0.1f, 600.0f, this),
|
||||
m_ZoomEnvelopeY(640.0f, 0.1f, 32000.0f, this),
|
||||
m_TilesetPicker(16, 16)
|
||||
{
|
||||
m_EntitiesTexture.Invalidate();
|
||||
|
@ -885,10 +916,12 @@ public:
|
|||
m_EditorOffsetX = 0.0f;
|
||||
m_EditorOffsetY = 0.0f;
|
||||
|
||||
m_Zoom = 200.0f;
|
||||
m_Zooming = false;
|
||||
m_WorldZoom = 1.0f;
|
||||
|
||||
m_ResetZoomEnvelope = true;
|
||||
m_OffsetEnvelopeX = 0.1f;
|
||||
m_OffsetEnvelopeY = 0.5f;
|
||||
|
||||
m_ShowMousePointer = true;
|
||||
m_MouseDeltaX = 0;
|
||||
m_MouseDeltaY = 0;
|
||||
|
@ -1158,14 +1191,17 @@ public:
|
|||
float m_EditorOffsetY;
|
||||
|
||||
// Zooming
|
||||
CCubicBezier m_ZoomSmoothing;
|
||||
float m_ZoomSmoothingStart;
|
||||
float m_ZoomSmoothingEnd;
|
||||
bool m_Zooming;
|
||||
float m_Zoom;
|
||||
float m_ZoomSmoothingTarget;
|
||||
CSmoothZoom m_ZoomMapView;
|
||||
float m_WorldZoom;
|
||||
|
||||
CSmoothZoom m_ZoomEnvelopeX;
|
||||
CSmoothZoom m_ZoomEnvelopeY;
|
||||
|
||||
bool m_ResetZoomEnvelope;
|
||||
|
||||
float m_OffsetEnvelopeX;
|
||||
float m_OffsetEnvelopeY;
|
||||
|
||||
bool m_ShowMousePointer;
|
||||
bool m_GuiActive;
|
||||
|
||||
|
@ -1464,13 +1500,23 @@ public:
|
|||
int GetLineDistance() const;
|
||||
|
||||
// Zooming
|
||||
void SetZoom(float Target);
|
||||
void ChangeZoom(float Amount);
|
||||
void ZoomMouseTarget(float ZoomFactor);
|
||||
void UpdateZoom();
|
||||
float ZoomProgress(float CurrentTime) const;
|
||||
float MinZoomLevel() const;
|
||||
float MaxZoomLevel() const;
|
||||
void UpdateZoomWorld();
|
||||
|
||||
void ZoomAdaptOffsetX(float ZoomFactor, const CUIRect &View);
|
||||
void UpdateZoomEnvelopeX(const CUIRect &View);
|
||||
|
||||
void ZoomAdaptOffsetY(float ZoomFactor, const CUIRect &View);
|
||||
void UpdateZoomEnvelopeY(const CUIRect &View);
|
||||
|
||||
void ResetZoomEnvelope(CEnvelope *pEnvelope, int ActiveChannels);
|
||||
void RemoveTimeOffsetEnvelope(CEnvelope *pEnvelope);
|
||||
float ScreenToEnvelopeX(const CUIRect &View, float x) const;
|
||||
float EnvelopeToScreenX(const CUIRect &View, float x) const;
|
||||
float ScreenToEnvelopeY(const CUIRect &View, float y) const;
|
||||
float EnvelopeToScreenY(const CUIRect &View, float y) const;
|
||||
float ScreenToEnvelopeDX(const CUIRect &View, float dx);
|
||||
float ScreenToEnvelopeDY(const CUIRect &View, float dy);
|
||||
|
||||
// DDRace
|
||||
|
||||
|
|
Loading…
Reference in a new issue