mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-17 13:38:18 +00:00
Add editor undo/redo feature
This commit is contained in:
parent
f910ac6a1c
commit
96e4c5f7cd
|
@ -2285,13 +2285,22 @@ if(CLIENT)
|
|||
component.h
|
||||
editor.cpp
|
||||
editor.h
|
||||
editor_action.h
|
||||
editor_actions.cpp
|
||||
editor_actions.h
|
||||
editor_history.cpp
|
||||
editor_history.h
|
||||
editor_object.cpp
|
||||
editor_object.h
|
||||
editor_props.cpp
|
||||
editor_trackers.cpp
|
||||
editor_trackers.h
|
||||
explanations.cpp
|
||||
map_grid.cpp
|
||||
map_grid.h
|
||||
map_view.cpp
|
||||
map_view.h
|
||||
mapitems.h
|
||||
mapitems/envelope.cpp
|
||||
mapitems/envelope.h
|
||||
mapitems/image.cpp
|
||||
|
|
|
@ -248,6 +248,7 @@ MACRO_CONFIG_INT(ClRefreshRateInactive, cl_refresh_rate_inactive, 120, 0, 10000,
|
|||
MACRO_CONFIG_INT(ClEditor, cl_editor, 0, 0, 1, CFGFLAG_CLIENT, "Open the map editor")
|
||||
MACRO_CONFIG_INT(ClEditorDilate, cl_editor_dilate, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Automatically dilates embedded images")
|
||||
MACRO_CONFIG_STR(ClSkinFilterString, cl_skin_filter_string, 25, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Skin filtering string")
|
||||
MACRO_CONFIG_INT(ClEditorMaxHistory, cl_editor_max_history, 50, 1, 500, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Maximum number of undo actions in the editor history (not shared between editor, envelope editor and server settings editor)")
|
||||
|
||||
MACRO_CONFIG_INT(ClAutoDemoRecord, cl_auto_demo_record, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Automatically record demos")
|
||||
MACRO_CONFIG_INT(ClAutoDemoOnConnect, cl_auto_demo_on_connect, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Only start a new demo when connect while automatically record demos")
|
||||
|
|
|
@ -140,6 +140,8 @@ MAYBE_UNUSED static const char *FONT_ICON_DICE_FIVE = "\xEF\x94\xA3";
|
|||
MAYBE_UNUSED static const char *FONT_ICON_DICE_SIX = "\xEF\x94\xA6";
|
||||
|
||||
MAYBE_UNUSED static const char *FONT_ICON_LAYER_GROUP = "\xEF\x97\xBD";
|
||||
MAYBE_UNUSED static const char *FONT_ICON_UNDO = "\xEF\x8B\xAA";
|
||||
MAYBE_UNUSED static const char *FONT_ICON_REDO = "\xEF\x8B\xB9";
|
||||
} // end namespace FontIcons
|
||||
|
||||
enum ETextCursorSelectionMode
|
||||
|
|
|
@ -490,19 +490,37 @@ int CUI::DoDraggableButtonLogic(const void *pID, int Checked, const CUIRect *pRe
|
|||
return ReturnValue;
|
||||
}
|
||||
|
||||
int CUI::DoPickerLogic(const void *pID, const CUIRect *pRect, float *pX, float *pY)
|
||||
EEditState CUI::DoPickerLogic(const void *pID, const CUIRect *pRect, float *pX, float *pY)
|
||||
{
|
||||
static const void *s_pEditing = nullptr;
|
||||
|
||||
if(MouseHovered(pRect))
|
||||
SetHotItem(pID);
|
||||
|
||||
EEditState Res = EEditState::EDITING;
|
||||
|
||||
if(HotItem() == pID && MouseButtonClicked(0))
|
||||
{
|
||||
SetActiveItem(pID);
|
||||
if(!s_pEditing)
|
||||
{
|
||||
s_pEditing = pID;
|
||||
Res = EEditState::START;
|
||||
}
|
||||
}
|
||||
|
||||
if(CheckActiveItem(pID) && !MouseButton(0))
|
||||
{
|
||||
SetActiveItem(nullptr);
|
||||
if(s_pEditing == pID)
|
||||
{
|
||||
s_pEditing = nullptr;
|
||||
Res = EEditState::END;
|
||||
}
|
||||
}
|
||||
|
||||
if(!CheckActiveItem(pID))
|
||||
return 0;
|
||||
if(!CheckActiveItem(pID) && Res == EEditState::EDITING)
|
||||
return EEditState::NONE;
|
||||
|
||||
if(Input()->ShiftIsPressed())
|
||||
m_MouseSlow = true;
|
||||
|
@ -512,7 +530,7 @@ int CUI::DoPickerLogic(const void *pID, const CUIRect *pRect, float *pX, float *
|
|||
if(pY)
|
||||
*pY = clamp(m_MouseY - pRect->y, 0.0f, pRect->h);
|
||||
|
||||
return 1;
|
||||
return Res;
|
||||
}
|
||||
|
||||
void CUI::DoSmoothScrollLogic(float *pScrollOffset, float *pScrollOffsetChange, float ViewPortSize, float TotalSize, bool SmoothClamp, float ScrollSpeed)
|
||||
|
@ -981,12 +999,19 @@ int CUI::DoButton_PopupMenu(CButtonContainer *pButtonContainer, const char *pTex
|
|||
}
|
||||
|
||||
int64_t CUI::DoValueSelector(const void *pID, const CUIRect *pRect, const char *pLabel, int64_t Current, int64_t Min, int64_t Max, const SValueSelectorProperties &Props)
|
||||
{
|
||||
return DoValueSelectorWithState(pID, pRect, pLabel, Current, Min, Max, Props).m_Value;
|
||||
}
|
||||
|
||||
SEditResult<int64_t> CUI::DoValueSelectorWithState(const void *pID, const CUIRect *pRect, const char *pLabel, int64_t Current, int64_t Min, int64_t Max, const SValueSelectorProperties &Props)
|
||||
{
|
||||
// logic
|
||||
static float s_Value;
|
||||
static CLineInputNumber s_NumberInput;
|
||||
static const void *s_pLastTextID = pID;
|
||||
const bool Inside = MouseInside(pRect);
|
||||
static const void *s_pEditing = nullptr;
|
||||
EEditState State = EEditState::NONE;
|
||||
|
||||
if(Inside)
|
||||
SetHotItem(pID);
|
||||
|
@ -1091,7 +1116,23 @@ int64_t CUI::DoValueSelector(const void *pID, const CUIRect *pRect, const char *
|
|||
if(!m_ValueSelectorTextMode)
|
||||
s_NumberInput.Clear();
|
||||
|
||||
return Current;
|
||||
if(s_pEditing == pID)
|
||||
State = EEditState::EDITING;
|
||||
|
||||
bool MouseLocked = CheckMouseLock();
|
||||
if((MouseLocked || m_ValueSelectorTextMode) && !s_pEditing)
|
||||
{
|
||||
State = EEditState::START;
|
||||
s_pEditing = pID;
|
||||
}
|
||||
|
||||
if(!CheckMouseLock() && !m_ValueSelectorTextMode && s_pEditing == pID)
|
||||
{
|
||||
State = EEditState::END;
|
||||
s_pEditing = nullptr;
|
||||
}
|
||||
|
||||
return SEditResult<int64_t>{State, Current};
|
||||
}
|
||||
|
||||
float CUI::DoScrollbarV(const void *pID, const CUIRect *pRect, float Current)
|
||||
|
@ -1686,6 +1727,7 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View
|
|||
{
|
||||
SColorPickerPopupContext *pColorPicker = static_cast<SColorPickerPopupContext *>(pContext);
|
||||
CUI *pUI = pColorPicker->m_pUI;
|
||||
pColorPicker->m_State = EEditState::NONE;
|
||||
|
||||
CUIRect ColorsArea, HueArea, BottomArea, ModeButtonArea, HueRect, SatRect, ValueRect, HexRect, AlphaRect;
|
||||
|
||||
|
@ -1759,10 +1801,10 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View
|
|||
HuePartialArea.Draw4(TL, TL, BL, BL, IGraphics::CORNER_NONE, 0.0f);
|
||||
}
|
||||
|
||||
const auto &&RenderAlphaSelector = [&](unsigned OldA) -> unsigned {
|
||||
const auto &&RenderAlphaSelector = [&](unsigned OldA) -> SEditResult<int64_t> {
|
||||
if(pColorPicker->m_Alpha)
|
||||
{
|
||||
return pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[3], &AlphaRect, "A:", OldA, 0, 255);
|
||||
return pUI->DoValueSelectorWithState(&pColorPicker->m_aValueSelectorIds[3], &AlphaRect, "A:", OldA, 0, 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1770,7 +1812,7 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View
|
|||
str_format(aBuf, sizeof(aBuf), "A: %d", OldA);
|
||||
pUI->DoLabel(&AlphaRect, aBuf, 10.0f, TEXTALIGN_MC);
|
||||
AlphaRect.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.65f), IGraphics::CORNER_ALL, 3.0f);
|
||||
return OldA;
|
||||
return {EEditState::NONE, OldA};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1782,10 +1824,10 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View
|
|||
const unsigned OldV = (unsigned)(PickerColorHSV.v * 255.0f);
|
||||
const unsigned OldA = (unsigned)(PickerColorHSV.a * 255.0f);
|
||||
|
||||
const unsigned H = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[0], &HueRect, "H:", OldH, 0, 255);
|
||||
const unsigned S = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[1], &SatRect, "S:", OldS, 0, 255);
|
||||
const unsigned V = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[2], &ValueRect, "V:", OldV, 0, 255);
|
||||
const unsigned A = RenderAlphaSelector(OldA);
|
||||
const auto [StateH, H] = pUI->DoValueSelectorWithState(&pColorPicker->m_aValueSelectorIds[0], &HueRect, "H:", OldH, 0, 255);
|
||||
const auto [StateS, S] = pUI->DoValueSelectorWithState(&pColorPicker->m_aValueSelectorIds[1], &SatRect, "S:", OldS, 0, 255);
|
||||
const auto [StateV, V] = pUI->DoValueSelectorWithState(&pColorPicker->m_aValueSelectorIds[2], &ValueRect, "V:", OldV, 0, 255);
|
||||
const auto [StateA, A] = RenderAlphaSelector(OldA);
|
||||
|
||||
if(OldH != H || OldS != S || OldV != V || OldA != A)
|
||||
{
|
||||
|
@ -1793,6 +1835,15 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View
|
|||
PickerColorHSL = color_cast<ColorHSLA>(PickerColorHSV);
|
||||
PickerColorRGB = color_cast<ColorRGBA>(PickerColorHSL);
|
||||
}
|
||||
|
||||
for(auto State : {StateH, StateS, StateV, StateA})
|
||||
{
|
||||
if(State != EEditState::NONE)
|
||||
{
|
||||
pColorPicker->m_State = State;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(pColorPicker->m_ColorMode == SColorPickerPopupContext::MODE_RGBA)
|
||||
{
|
||||
|
@ -1801,10 +1852,10 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View
|
|||
const unsigned OldB = (unsigned)(PickerColorRGB.b * 255.0f);
|
||||
const unsigned OldA = (unsigned)(PickerColorRGB.a * 255.0f);
|
||||
|
||||
const unsigned R = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[0], &HueRect, "R:", OldR, 0, 255);
|
||||
const unsigned G = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[1], &SatRect, "G:", OldG, 0, 255);
|
||||
const unsigned B = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[2], &ValueRect, "B:", OldB, 0, 255);
|
||||
const unsigned A = RenderAlphaSelector(OldA);
|
||||
const auto [StateR, R] = pUI->DoValueSelectorWithState(&pColorPicker->m_aValueSelectorIds[0], &HueRect, "R:", OldR, 0, 255);
|
||||
const auto [StateG, G] = pUI->DoValueSelectorWithState(&pColorPicker->m_aValueSelectorIds[1], &SatRect, "G:", OldG, 0, 255);
|
||||
const auto [StateB, B] = pUI->DoValueSelectorWithState(&pColorPicker->m_aValueSelectorIds[2], &ValueRect, "B:", OldB, 0, 255);
|
||||
const auto [StateA, A] = RenderAlphaSelector(OldA);
|
||||
|
||||
if(OldR != R || OldG != G || OldB != B || OldA != A)
|
||||
{
|
||||
|
@ -1812,6 +1863,15 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View
|
|||
PickerColorHSL = color_cast<ColorHSLA>(PickerColorRGB);
|
||||
PickerColorHSV = color_cast<ColorHSVA>(PickerColorHSL);
|
||||
}
|
||||
|
||||
for(auto State : {StateR, StateG, StateB, StateA})
|
||||
{
|
||||
if(State != EEditState::NONE)
|
||||
{
|
||||
pColorPicker->m_State = State;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(pColorPicker->m_ColorMode == SColorPickerPopupContext::MODE_HSLA)
|
||||
{
|
||||
|
@ -1820,10 +1880,10 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View
|
|||
const unsigned OldL = (unsigned)(PickerColorHSL.l * 255.0f);
|
||||
const unsigned OldA = (unsigned)(PickerColorHSL.a * 255.0f);
|
||||
|
||||
const unsigned H = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[0], &HueRect, "H:", OldH, 0, 255);
|
||||
const unsigned S = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[1], &SatRect, "S:", OldS, 0, 255);
|
||||
const unsigned L = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[2], &ValueRect, "L:", OldL, 0, 255);
|
||||
const unsigned A = RenderAlphaSelector(OldA);
|
||||
const auto [StateH, H] = pUI->DoValueSelectorWithState(&pColorPicker->m_aValueSelectorIds[0], &HueRect, "H:", OldH, 0, 255);
|
||||
const auto [StateS, S] = pUI->DoValueSelectorWithState(&pColorPicker->m_aValueSelectorIds[1], &SatRect, "S:", OldS, 0, 255);
|
||||
const auto [StateL, L] = pUI->DoValueSelectorWithState(&pColorPicker->m_aValueSelectorIds[2], &ValueRect, "L:", OldL, 0, 255);
|
||||
const auto [StateA, A] = RenderAlphaSelector(OldA);
|
||||
|
||||
if(OldH != H || OldS != S || OldL != L || OldA != A)
|
||||
{
|
||||
|
@ -1831,6 +1891,15 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View
|
|||
PickerColorHSV = color_cast<ColorHSVA>(PickerColorHSL);
|
||||
PickerColorRGB = color_cast<ColorRGBA>(PickerColorHSL);
|
||||
}
|
||||
|
||||
for(auto State : {StateH, StateS, StateL, StateA})
|
||||
{
|
||||
if(State != EEditState::NONE)
|
||||
{
|
||||
pColorPicker->m_State = State;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1842,7 +1911,7 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View
|
|||
Props.m_IsHex = true;
|
||||
Props.m_HexPrefix = pColorPicker->m_Alpha ? 8 : 6;
|
||||
const unsigned OldHex = PickerColorRGB.PackAlphaLast(pColorPicker->m_Alpha);
|
||||
const unsigned Hex = pUI->DoValueSelector(&pColorPicker->m_aValueSelectorIds[4], &HexRect, "Hex:", OldHex, 0, pColorPicker->m_Alpha ? 0xFFFFFFFFll : 0xFFFFFFll, Props);
|
||||
auto [HexState, Hex] = pUI->DoValueSelectorWithState(&pColorPicker->m_aValueSelectorIds[4], &HexRect, "Hex:", OldHex, 0, pColorPicker->m_Alpha ? 0xFFFFFFFFll : 0xFFFFFFll, Props);
|
||||
if(OldHex != Hex)
|
||||
{
|
||||
const float OldAlpha = PickerColorRGB.a;
|
||||
|
@ -1853,21 +1922,28 @@ CUI::EPopupMenuFunctionResult CUI::PopupColorPicker(void *pContext, CUIRect View
|
|||
PickerColorHSV = color_cast<ColorHSVA>(PickerColorHSL);
|
||||
}
|
||||
|
||||
if(HexState != EEditState::NONE)
|
||||
pColorPicker->m_State = HexState;
|
||||
|
||||
// Logic
|
||||
float PickerX, PickerY;
|
||||
if(pUI->DoPickerLogic(&pColorPicker->m_ColorPickerId, &ColorsArea, &PickerX, &PickerY))
|
||||
EEditState ColorPickerRes = pUI->DoPickerLogic(&pColorPicker->m_ColorPickerId, &ColorsArea, &PickerX, &PickerY);
|
||||
if(ColorPickerRes != EEditState::NONE)
|
||||
{
|
||||
PickerColorHSV.y = PickerX / ColorsArea.w;
|
||||
PickerColorHSV.z = 1.0f - PickerY / ColorsArea.h;
|
||||
PickerColorHSL = color_cast<ColorHSLA>(PickerColorHSV);
|
||||
PickerColorRGB = color_cast<ColorRGBA>(PickerColorHSL);
|
||||
pColorPicker->m_State = ColorPickerRes;
|
||||
}
|
||||
|
||||
if(pUI->DoPickerLogic(&pColorPicker->m_HuePickerId, &HueArea, &PickerX, &PickerY))
|
||||
EEditState HuePickerRes = pUI->DoPickerLogic(&pColorPicker->m_HuePickerId, &HueArea, &PickerX, &PickerY);
|
||||
if(HuePickerRes != EEditState::NONE)
|
||||
{
|
||||
PickerColorHSV.x = 1.0f - PickerY / HueArea.h;
|
||||
PickerColorHSL = color_cast<ColorHSLA>(PickerColorHSV);
|
||||
PickerColorRGB = color_cast<ColorRGBA>(PickerColorHSL);
|
||||
pColorPicker->m_State = HuePickerRes;
|
||||
}
|
||||
|
||||
// Marker Color Area
|
||||
|
|
|
@ -18,6 +18,22 @@ class IClient;
|
|||
class IGraphics;
|
||||
class IKernel;
|
||||
|
||||
enum class EEditState
|
||||
{
|
||||
NONE,
|
||||
START,
|
||||
EDITING,
|
||||
END,
|
||||
ONE_GO
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SEditResult
|
||||
{
|
||||
EEditState m_State;
|
||||
T m_Value;
|
||||
};
|
||||
|
||||
struct SUIAnimator
|
||||
{
|
||||
bool m_Active;
|
||||
|
@ -488,7 +504,7 @@ public:
|
|||
|
||||
int DoButtonLogic(const void *pID, int Checked, const CUIRect *pRect);
|
||||
int DoDraggableButtonLogic(const void *pID, int Checked, const CUIRect *pRect, bool *pClicked, bool *pAbrupted);
|
||||
int DoPickerLogic(const void *pID, const CUIRect *pRect, float *pX, float *pY);
|
||||
EEditState DoPickerLogic(const void *pID, const CUIRect *pRect, float *pX, float *pY);
|
||||
void DoSmoothScrollLogic(float *pScrollOffset, float *pScrollOffsetChange, float ViewPortSize, float TotalSize, bool SmoothClamp = false, float ScrollSpeed = 10.0f);
|
||||
static vec2 CalcAlignedCursorPos(const CUIRect *pRect, vec2 TextSize, int Align, const float *pBiggestCharHeight = nullptr);
|
||||
|
||||
|
@ -505,6 +521,7 @@ public:
|
|||
int DoButton_PopupMenu(CButtonContainer *pButtonContainer, const char *pText, const CUIRect *pRect, float Size, int Align, float Padding = 0.0f, bool TransparentInactive = false, bool Enabled = true);
|
||||
|
||||
// value selector
|
||||
SEditResult<int64_t> DoValueSelectorWithState(const void *pID, const CUIRect *pRect, const char *pLabel, int64_t Current, int64_t Min, int64_t Max, const SValueSelectorProperties &Props = {});
|
||||
int64_t DoValueSelector(const void *pID, const CUIRect *pRect, const char *pLabel, int64_t Current, int64_t Min, int64_t Max, const SValueSelectorProperties &Props = {});
|
||||
bool IsValueSelectorTextMode() const { return m_ValueSelectorTextMode; }
|
||||
void SetValueSelectorTextMode(bool TextMode) { m_ValueSelectorTextMode = TextMode; }
|
||||
|
@ -620,6 +637,7 @@ public:
|
|||
const char m_ColorPickerId = 0;
|
||||
const char m_aValueSelectorIds[5] = {0};
|
||||
CButtonContainer m_aModeButtons[(int)MODE_HSLA + 1];
|
||||
EEditState m_State;
|
||||
};
|
||||
void ShowPopupColorPicker(float X, float Y, SColorPickerPopupContext *pContext);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "auto_map.h"
|
||||
#include "editor.h" // TODO: only needs CLayerTiles
|
||||
#include "editor_actions.h"
|
||||
|
||||
// Based on triple32inc from https://github.com/skeeto/hash-prospector/tree/79a6074062a84907df6e45b756134b74e2956760
|
||||
static uint32_t HashUInt32(uint32_t Num)
|
||||
|
@ -173,9 +174,9 @@ void CAutoMapper::Load(const char *pTileName)
|
|||
{
|
||||
Value = CPosRule::NOTINDEX;
|
||||
CIndexInfo NewIndexInfo1 = {0, 0, false};
|
||||
//CIndexInfo NewIndexInfo2 = {-1, 0};
|
||||
// CIndexInfo NewIndexInfo2 = {-1, 0};
|
||||
vNewIndexList.push_back(NewIndexInfo1);
|
||||
//vNewIndexList.push_back(NewIndexInfo2);
|
||||
// vNewIndexList.push_back(NewIndexInfo2);
|
||||
}
|
||||
else if(!str_comp(aValue, "INDEX") || !str_comp(aValue, "NOTINDEX"))
|
||||
{
|
||||
|
@ -425,8 +426,10 @@ void CAutoMapper::ProceedLocalized(CLayerTiles *pLayer, int ConfigID, int Seed,
|
|||
{
|
||||
CTile *pIn = &pUpdateLayer->m_pTiles[(y - UpdateFromY) * pUpdateLayer->m_Width + x - UpdateFromX];
|
||||
CTile *pOut = &pLayer->m_pTiles[y * pLayer->m_Width + x];
|
||||
CTile Previous = *pOut;
|
||||
pOut->m_Index = pIn->m_Index;
|
||||
pOut->m_Flags = pIn->m_Flags;
|
||||
pLayer->RecordStateChange(x, y, Previous, *pOut);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -442,6 +445,7 @@ void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID, int Seed, int SeedO
|
|||
Seed = rand();
|
||||
|
||||
CConfiguration *pConf = &m_vConfigs[ConfigID];
|
||||
pLayer->ClearHistory();
|
||||
|
||||
// for every run: copy tiles, automap, overwrite tiles
|
||||
for(size_t h = 0; h < pConf->m_vRuns.size(); ++h)
|
||||
|
@ -534,8 +538,10 @@ void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID, int Seed, int SeedO
|
|||
if(RespectRules &&
|
||||
(pIndexRule->m_RandomProbability >= 1.0f || HashLocation(Seed, h, i, x + SeedOffsetX, y + SeedOffsetY) < HASH_MAX * pIndexRule->m_RandomProbability))
|
||||
{
|
||||
CTile Previous = *pTile;
|
||||
pTile->m_Index = pIndexRule->m_ID;
|
||||
pTile->m_Flags = pIndexRule->m_Flag;
|
||||
pLayer->RecordStateChange(x, y, Previous, *pTile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -30,6 +30,8 @@
|
|||
#include <engine/shared/jobs.h>
|
||||
|
||||
#include "auto_map.h"
|
||||
#include "editor_history.h"
|
||||
#include "editor_trackers.h"
|
||||
#include "map_view.h"
|
||||
#include "smooth_value.h"
|
||||
|
||||
|
@ -452,7 +454,7 @@ public:
|
|||
bool Save(const char *pFilename) override;
|
||||
bool Load(const char *pFilename, int StorageType) override;
|
||||
bool HandleMapDrop(const char *pFilename, int StorageType) override;
|
||||
bool Append(const char *pFilename, int StorageType);
|
||||
bool Append(const char *pFilename, int StorageType, bool IgnoreHistory = false);
|
||||
void LoadCurrentMap();
|
||||
void Render();
|
||||
|
||||
|
@ -494,7 +496,10 @@ public:
|
|||
bool IsTangentInSelected() const;
|
||||
bool IsTangentOutSelected() const;
|
||||
bool IsTangentSelected() const;
|
||||
std::pair<int, int> EnvGetSelectedTimeAndValue() const;
|
||||
|
||||
template<typename E>
|
||||
SEditResult<E> DoPropertiesWithState(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color = ColorRGBA(1, 1, 1, 0.5f));
|
||||
int DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color = ColorRGBA(1, 1, 1, 0.5f));
|
||||
|
||||
CUI::SColorPickerPopupContext m_ColorPickerPopupContext;
|
||||
|
@ -694,10 +699,11 @@ public:
|
|||
EXTRAEDITOR_NONE = -1,
|
||||
EXTRAEDITOR_ENVELOPES,
|
||||
EXTRAEDITOR_SERVER_SETTINGS,
|
||||
EXTRAEDITOR_HISTORY,
|
||||
NUM_EXTRAEDITORS,
|
||||
};
|
||||
EExtraEditor m_ActiveExtraEditor = EXTRAEDITOR_NONE;
|
||||
float m_aExtraEditorSplits[NUM_EXTRAEDITORS] = {250.0f, 250.0f};
|
||||
float m_aExtraEditorSplits[NUM_EXTRAEDITORS] = {250.0f, 250.0f, 250.0f};
|
||||
|
||||
enum EShowEnvelope
|
||||
{
|
||||
|
@ -752,7 +758,7 @@ public:
|
|||
|
||||
CImageInfo m_TileartImageInfo;
|
||||
char m_aTileartFilename[IO_MAX_PATH_LENGTH];
|
||||
void AddTileart();
|
||||
void AddTileart(bool IgnoreHistory = false);
|
||||
void TileartCheckColors();
|
||||
|
||||
void PlaceBorderTiles();
|
||||
|
@ -779,7 +785,7 @@ public:
|
|||
|
||||
void RenderBackground(CUIRect View, IGraphics::CTextureHandle Texture, float Size, float Brightness);
|
||||
|
||||
int UiDoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, int Current, int Min, int Max, int Step, float Scale, const char *pToolTip, bool IsDegree = false, bool IsHex = false, int corners = IGraphics::CORNER_ALL, ColorRGBA *pColor = nullptr, bool ShowValue = true);
|
||||
SEditResult<int> UiDoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, int Current, int Min, int Max, int Step, float Scale, const char *pToolTip, bool IsDegree = false, bool IsHex = false, int corners = IGraphics::CORNER_ALL, ColorRGBA *pColor = nullptr, bool ShowValue = true);
|
||||
|
||||
static CUI::EPopupMenuFunctionResult PopupMenuFile(void *pContext, CUIRect View, bool Active);
|
||||
static CUI::EPopupMenuFunctionResult PopupMenuTools(void *pContext, CUIRect View, bool Active);
|
||||
|
@ -789,6 +795,7 @@ public:
|
|||
{
|
||||
CEditor *m_pEditor;
|
||||
std::vector<std::shared_ptr<CLayerTiles>> m_vpLayers;
|
||||
std::vector<int> m_vLayerIndices;
|
||||
CLayerTiles::SCommonPropState m_CommonPropState;
|
||||
};
|
||||
static CUI::EPopupMenuFunctionResult PopupLayer(void *pContext, CUIRect View, bool Active);
|
||||
|
@ -837,7 +844,7 @@ public:
|
|||
|
||||
void DoQuadEnvelopes(const std::vector<CQuad> &vQuads, IGraphics::CTextureHandle Texture = IGraphics::CTextureHandle());
|
||||
void DoQuadEnvPoint(const CQuad *pQuad, int QIndex, int pIndex);
|
||||
void DoQuadPoint(CQuad *pQuad, int QuadIndex, int v);
|
||||
void DoQuadPoint(const std::shared_ptr<CLayerQuads> &pLayer, CQuad *pQuad, int QuadIndex, int v);
|
||||
void SetHotQuadPoint(const std::shared_ptr<CLayerQuads> &pLayer);
|
||||
|
||||
float TriangleArea(vec2 A, vec2 B, vec2 C);
|
||||
|
@ -849,7 +856,7 @@ public:
|
|||
void DoMapEditor(CUIRect View);
|
||||
void DoToolbarLayers(CUIRect Toolbar);
|
||||
void DoToolbarSounds(CUIRect Toolbar);
|
||||
void DoQuad(CQuad *pQuad, int Index);
|
||||
void DoQuad(const std::shared_ptr<CLayerQuads> &pLayer, CQuad *pQuad, int Index);
|
||||
ColorRGBA GetButtonColor(const void *pID, int Checked);
|
||||
|
||||
bool ReplaceImage(const char *pFilename, int StorageType, bool CheckDuplicate);
|
||||
|
@ -874,6 +881,7 @@ public:
|
|||
|
||||
void RenderEnvelopeEditor(CUIRect View);
|
||||
void RenderServerSettingsEditor(CUIRect View, bool ShowServerSettingsEditorLast);
|
||||
void RenderEditorHistory(CUIRect View);
|
||||
|
||||
void RenderExtraEditorDragBar(CUIRect View, CUIRect DragBar);
|
||||
|
||||
|
@ -883,7 +891,7 @@ public:
|
|||
void RenderFileDialog();
|
||||
|
||||
void SelectGameLayer();
|
||||
void SortImages();
|
||||
std::vector<int> SortImages();
|
||||
bool SelectLayerByTile();
|
||||
|
||||
void DoAudioPreview(CUIRect View, const void *pPlayPauseButtonID, const void *pStopButtonID, const void *pSeekBarID, const int SampleID);
|
||||
|
@ -1002,6 +1010,17 @@ public:
|
|||
|
||||
unsigned char m_SwitchNum;
|
||||
unsigned char m_SwitchDelay;
|
||||
|
||||
// Undo/Redo
|
||||
CEditorHistory m_EditorHistory;
|
||||
CEditorHistory m_ServerSettingsHistory;
|
||||
CEditorHistory m_EnvelopeEditorHistory;
|
||||
CQuadEditTracker m_QuadTracker;
|
||||
CEnvelopeEditorOperationTracker m_EnvOpTracker;
|
||||
|
||||
private:
|
||||
void UndoLastAction();
|
||||
void RedoLastAction();
|
||||
};
|
||||
|
||||
// make sure to inline this function
|
||||
|
|
30
src/game/editor/editor_action.h
Normal file
30
src/game/editor/editor_action.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef GAME_EDITOR_EDITOR_ACTION_H
|
||||
#define GAME_EDITOR_EDITOR_ACTION_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class CEditor;
|
||||
|
||||
class IEditorAction
|
||||
{
|
||||
public:
|
||||
IEditorAction(CEditor *pEditor) :
|
||||
m_pEditor(pEditor) {}
|
||||
|
||||
IEditorAction() = default;
|
||||
|
||||
virtual ~IEditorAction() = default;
|
||||
|
||||
virtual void Undo() = 0;
|
||||
virtual void Redo() = 0;
|
||||
|
||||
virtual bool IsEmpty() { return false; }
|
||||
|
||||
const char *DisplayText() const { return m_aDisplayText; }
|
||||
|
||||
protected:
|
||||
CEditor *m_pEditor;
|
||||
char m_aDisplayText[256];
|
||||
};
|
||||
|
||||
#endif
|
2065
src/game/editor/editor_actions.cpp
Normal file
2065
src/game/editor/editor_actions.cpp
Normal file
File diff suppressed because it is too large
Load diff
648
src/game/editor/editor_actions.h
Normal file
648
src/game/editor/editor_actions.h
Normal file
|
@ -0,0 +1,648 @@
|
|||
#ifndef GAME_EDITOR_EDITOR_ACTIONS_H
|
||||
#define GAME_EDITOR_EDITOR_ACTIONS_H
|
||||
|
||||
#include "editor.h"
|
||||
#include "editor_action.h"
|
||||
|
||||
class CEditorActionLayerBase : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorActionLayerBase(CEditor *pEditor, int GroupIndex, int LayerIndex);
|
||||
|
||||
virtual void Undo() override {}
|
||||
virtual void Redo() override {}
|
||||
|
||||
protected:
|
||||
int m_GroupIndex;
|
||||
int m_LayerIndex;
|
||||
std::shared_ptr<CLayer> m_pLayer;
|
||||
};
|
||||
|
||||
class CEditorBrushDrawAction : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorBrushDrawAction(CEditor *pEditor, int Group);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
bool IsEmpty() override;
|
||||
|
||||
private:
|
||||
int m_Group;
|
||||
// m_vTileChanges is a list of changes for each layer that was modified.
|
||||
// The std::pair is used to pair one layer (index) with its history (2D map).
|
||||
// EditorTileStateChangeHistory<T> is a 2D map, storing a change item at a specific y,x position.
|
||||
std::vector<std::pair<int, EditorTileStateChangeHistory<STileStateChange>>> m_vTileChanges;
|
||||
EditorTileStateChangeHistory<STeleTileStateChange> m_TeleTileChanges;
|
||||
EditorTileStateChangeHistory<SSpeedupTileStateChange> m_SpeedupTileChanges;
|
||||
EditorTileStateChangeHistory<SSwitchTileStateChange> m_SwitchTileChanges;
|
||||
EditorTileStateChangeHistory<STuneTileStateChange> m_TuneTileChanges;
|
||||
|
||||
int m_TotalTilesDrawn;
|
||||
int m_TotalLayers;
|
||||
|
||||
void Apply(bool Undo);
|
||||
void SetInfos();
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------
|
||||
|
||||
class CEditorActionQuadPlace : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionQuadPlace(CEditor *pEditor, int GroupIndex, int LayerIndex, std::vector<CQuad> &vBrush);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
std::vector<CQuad> m_vBrush;
|
||||
};
|
||||
|
||||
class CEditorActionSoundPlace : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionSoundPlace(CEditor *pEditor, int GroupIndex, int LayerIndex, std::vector<CSoundSource> &vBrush);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
std::vector<CSoundSource> m_vBrush;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
class CEditorActionDeleteQuad : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionDeleteQuad(CEditor *pEditor, int GroupIndex, int LayerIndex, std::vector<int> const &vQuadsIndices, std::vector<CQuad> const &vDeletedQuads);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
std::vector<int> m_vQuadsIndices;
|
||||
std::vector<CQuad> m_vDeletedQuads;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
class CEditorActionEditQuadPoint : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionEditQuadPoint(CEditor *pEditor, int GroupIndex, int LayerIndex, int QuadIndex, std::vector<CPoint> const &vPreviousPoints, std::vector<CPoint> const &vCurrentPoints);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_QuadIndex;
|
||||
std::vector<CPoint> m_vPreviousPoints;
|
||||
std::vector<CPoint> m_vCurrentPoints;
|
||||
};
|
||||
|
||||
class CEditorActionEditQuadProp : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionEditQuadProp(CEditor *pEditor, int GroupIndex, int LayerIndex, int QuadIndex, EQuadProp Prop, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_QuadIndex;
|
||||
EQuadProp m_Prop;
|
||||
int m_Previous;
|
||||
int m_Current;
|
||||
|
||||
void Apply(int Value);
|
||||
};
|
||||
|
||||
class CEditorActionEditQuadPointProp : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionEditQuadPointProp(CEditor *pEditor, int GroupIndex, int LayerIndex, int QuadIndex, int PointIndex, EQuadPointProp Prop, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_QuadIndex;
|
||||
int m_PointIndex;
|
||||
EQuadPointProp m_Prop;
|
||||
int m_Previous;
|
||||
int m_Current;
|
||||
|
||||
void Apply(int Value);
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
class CEditorActionBulk : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorActionBulk(CEditor *pEditor, const std::vector<std::shared_ptr<IEditorAction>> &vpActions, const char *pDisplay = nullptr, bool Reverse = false);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<IEditorAction>> m_vpActions;
|
||||
std::string m_Display;
|
||||
bool m_Reverse;
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
class CEditorActionAutoMap : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionAutoMap(CEditor *pEditor, int GroupIndex, int LayerIndex, const EditorTileStateChangeHistory<STileStateChange> &Changes);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
EditorTileStateChangeHistory<STileStateChange> m_Changes;
|
||||
int m_TotalChanges;
|
||||
|
||||
void ComputeInfos();
|
||||
void Apply(bool Undo);
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
class CEditorActionAddLayer : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionAddLayer(CEditor *pEditor, int GroupIndex, int LayerIndex, bool Duplicate = false);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
bool m_Duplicate;
|
||||
};
|
||||
|
||||
class CEditorActionDeleteLayer : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionDeleteLayer(CEditor *pEditor, int GroupIndex, int LayerIndex);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
};
|
||||
|
||||
class CEditorActionGroup : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorActionGroup(CEditor *pEditor, int GroupIndex, bool Delete);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_GroupIndex;
|
||||
bool m_Delete;
|
||||
std::shared_ptr<CLayerGroup> m_pGroup;
|
||||
};
|
||||
|
||||
class CEditorActionEditGroupProp : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorActionEditGroupProp(CEditor *pEditor, int GroupIndex, EGroupProp Prop, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_GroupIndex;
|
||||
EGroupProp m_Prop;
|
||||
int m_Previous;
|
||||
int m_Current;
|
||||
|
||||
void Apply(int Value);
|
||||
};
|
||||
|
||||
template<typename E>
|
||||
class CEditorActionEditLayerPropBase : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionEditLayerPropBase(CEditor *pEditor, int GroupIndex, int LayerIndex, E Prop, int Previous, int Current);
|
||||
|
||||
virtual void Undo() override {}
|
||||
virtual void Redo() override {}
|
||||
|
||||
protected:
|
||||
E m_Prop;
|
||||
int m_Previous;
|
||||
int m_Current;
|
||||
};
|
||||
|
||||
class CEditorActionEditLayerProp : public CEditorActionEditLayerPropBase<ELayerProp>
|
||||
{
|
||||
public:
|
||||
CEditorActionEditLayerProp(CEditor *pEditor, int GroupIndex, int LayerIndex, ELayerProp Prop, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
void Apply(int Value);
|
||||
};
|
||||
|
||||
class CEditorActionEditLayerTilesProp : public CEditorActionEditLayerPropBase<ETilesProp>
|
||||
{
|
||||
public:
|
||||
CEditorActionEditLayerTilesProp(CEditor *pEditor, int GroupIndex, int LayerIndex, ETilesProp Prop, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
void SetSavedLayers(const std::map<int, std::shared_ptr<CLayer>> &SavedLayers);
|
||||
|
||||
private:
|
||||
std::map<int, std::shared_ptr<CLayer>> m_SavedLayers;
|
||||
|
||||
void RestoreLayer(int Layer, const std::shared_ptr<CLayerTiles> &pLayerTiles);
|
||||
};
|
||||
|
||||
class CEditorActionEditLayerQuadsProp : public CEditorActionEditLayerPropBase<ELayerQuadsProp>
|
||||
{
|
||||
public:
|
||||
CEditorActionEditLayerQuadsProp(CEditor *pEditor, int GroupIndex, int LayerIndex, ELayerQuadsProp Prop, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
void Apply(int Value);
|
||||
};
|
||||
|
||||
class CEditorActionEditLayersGroupAndOrder : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorActionEditLayersGroupAndOrder(CEditor *pEditor, int GroupIndex, const std::vector<int> &LayerIndices, int NewGroupIndex, const std::vector<int> &NewLayerIndices);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_GroupIndex;
|
||||
std::vector<int> m_LayerIndices;
|
||||
int m_NewGroupIndex;
|
||||
std::vector<int> m_NewLayerIndices;
|
||||
};
|
||||
|
||||
// --------------
|
||||
|
||||
class CEditorActionAppendMap : public IEditorAction
|
||||
{
|
||||
public:
|
||||
struct SPrevInfo
|
||||
{
|
||||
int m_Groups;
|
||||
int m_Images;
|
||||
int m_Sounds;
|
||||
int m_Envelopes;
|
||||
};
|
||||
|
||||
public:
|
||||
CEditorActionAppendMap(CEditor *pEditor, const char *pMapName, const SPrevInfo &PrevInfo, std::vector<int> &vImageIndexMap);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
char m_aMapName[IO_MAX_PATH_LENGTH];
|
||||
SPrevInfo m_PrevInfo;
|
||||
std::vector<int> m_vImageIndexMap;
|
||||
};
|
||||
|
||||
// --------------
|
||||
|
||||
class CEditorActionTileArt : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorActionTileArt(CEditor *pEditor, int PreviousImageCount, const char *pTileArtFile, std::vector<int> &vImageIndexMap);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_PreviousImageCount;
|
||||
char m_aTileArtFile[IO_MAX_PATH_LENGTH];
|
||||
std::vector<int> m_vImageIndexMap;
|
||||
};
|
||||
|
||||
// ----------------------
|
||||
|
||||
class CEditorCommandAction : public IEditorAction
|
||||
{
|
||||
public:
|
||||
enum class EType
|
||||
{
|
||||
DELETE,
|
||||
ADD,
|
||||
EDIT,
|
||||
MOVE_UP,
|
||||
MOVE_DOWN
|
||||
};
|
||||
|
||||
CEditorCommandAction(CEditor *pEditor, EType Type, int *pSelectedCommandIndex, int CommandIndex, const char *pPreviousCommand = nullptr, const char *pCurrentCommand = nullptr);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
EType m_Type;
|
||||
int *m_pSelectedCommandIndex;
|
||||
int m_CommandIndex;
|
||||
std::string m_PreviousCommand;
|
||||
std::string m_CurrentCommand;
|
||||
};
|
||||
|
||||
// ------------------------------
|
||||
|
||||
class CEditorActionEnvelopeAdd : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorActionEnvelopeAdd(CEditor *pEditor, const std::shared_ptr<CEnvelope> &pEnv);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<CEnvelope> m_pEnv;
|
||||
};
|
||||
|
||||
class CEditorActionEveloppeDelete : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorActionEveloppeDelete(CEditor *pEditor, int EnvelopeIndex);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_EnvelopeIndex;
|
||||
std::shared_ptr<CEnvelope> m_pEnv;
|
||||
};
|
||||
|
||||
class CEditorActionEnvelopeEdit : public IEditorAction
|
||||
{
|
||||
public:
|
||||
enum class EEditType
|
||||
{
|
||||
SYNC,
|
||||
ORDER
|
||||
};
|
||||
|
||||
CEditorActionEnvelopeEdit(CEditor *pEditor, int EnvelopeIndex, EEditType EditType, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_EnvelopeIndex;
|
||||
EEditType m_EditType;
|
||||
int m_Previous;
|
||||
int m_Current;
|
||||
std::shared_ptr<CEnvelope> m_pEnv;
|
||||
};
|
||||
|
||||
class CEditorActionEnvelopeEditPoint : public IEditorAction
|
||||
{
|
||||
public:
|
||||
enum class EEditType
|
||||
{
|
||||
TIME,
|
||||
VALUE,
|
||||
CURVE_TYPE,
|
||||
HANDLE
|
||||
};
|
||||
|
||||
CEditorActionEnvelopeEditPoint(CEditor *pEditor, int EnvelopeIndex, int PointIndex, int Channel, EEditType EditType, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_EnvelopeIndex;
|
||||
int m_PointIndex;
|
||||
int m_Channel;
|
||||
EEditType m_EditType;
|
||||
int m_Previous;
|
||||
int m_Current;
|
||||
std::shared_ptr<CEnvelope> m_pEnv;
|
||||
|
||||
void Apply(int Value);
|
||||
};
|
||||
|
||||
class CEditorActionAddEnvelopePoint : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorActionAddEnvelopePoint(CEditor *pEditor, int EnvIndex, int Time, ColorRGBA Channels);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_EnvIndex;
|
||||
int m_Time;
|
||||
ColorRGBA m_Channels;
|
||||
};
|
||||
|
||||
class CEditorActionDeleteEnvelopePoint : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorActionDeleteEnvelopePoint(CEditor *pEditor, int EnvIndex, int PointIndex);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_EnvIndex;
|
||||
int m_PointIndex;
|
||||
CEnvPoint_runtime m_Point;
|
||||
};
|
||||
|
||||
class CEditorActionEditEnvelopePointValue : public IEditorAction
|
||||
{
|
||||
public:
|
||||
enum class EType
|
||||
{
|
||||
TANGENT_IN,
|
||||
TANGENT_OUT,
|
||||
POINT
|
||||
};
|
||||
|
||||
CEditorActionEditEnvelopePointValue(CEditor *pEditor, int EnvIndex, int PointIndex, int Channel, EType Type, int OldTime, int OldValue, int NewTime, int NewValue);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_EnvIndex;
|
||||
int m_PtIndex;
|
||||
int m_Channel;
|
||||
EType m_Type;
|
||||
int m_OldTime;
|
||||
int m_OldValue;
|
||||
int m_NewTime;
|
||||
int m_NewValue;
|
||||
|
||||
void Apply(bool Undo);
|
||||
};
|
||||
|
||||
class CEditorActionResetEnvelopePointTangent : public IEditorAction
|
||||
{
|
||||
public:
|
||||
CEditorActionResetEnvelopePointTangent(CEditor *pEditor, int EnvIndex, int PointIndex, int Channel, bool In);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_EnvIndex;
|
||||
int m_PointIndex;
|
||||
int m_Channel;
|
||||
bool m_In;
|
||||
int m_Previous[2];
|
||||
};
|
||||
|
||||
class CEditorActionEditLayerSoundsProp : public CEditorActionEditLayerPropBase<ELayerSoundsProp>
|
||||
{
|
||||
public:
|
||||
CEditorActionEditLayerSoundsProp(CEditor *pEditor, int GroupIndex, int LayerIndex, ELayerSoundsProp Prop, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
void Apply(int Value);
|
||||
};
|
||||
|
||||
class CEditorActionDeleteSoundSource : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionDeleteSoundSource(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_SourceIndex;
|
||||
CSoundSource m_Source;
|
||||
};
|
||||
|
||||
class CEditorActionEditSoundSource : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
enum class EEditType
|
||||
{
|
||||
SHAPE
|
||||
};
|
||||
|
||||
CEditorActionEditSoundSource(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex, EEditType Type, int Value);
|
||||
~CEditorActionEditSoundSource() override;
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_SourceIndex;
|
||||
EEditType m_EditType;
|
||||
int m_CurrentValue;
|
||||
|
||||
std::vector<int> m_vOriginalValues;
|
||||
void *m_pSavedObject;
|
||||
|
||||
void Save();
|
||||
};
|
||||
|
||||
class CEditorActionEditSoundSourceProp : public CEditorActionEditLayerPropBase<ESoundProp>
|
||||
{
|
||||
public:
|
||||
CEditorActionEditSoundSourceProp(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex, ESoundProp Prop, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_SourceIndex;
|
||||
|
||||
private:
|
||||
void Apply(int Value);
|
||||
};
|
||||
|
||||
class CEditorActionEditRectSoundSourceShapeProp : public CEditorActionEditLayerPropBase<ERectangleShapeProp>
|
||||
{
|
||||
public:
|
||||
CEditorActionEditRectSoundSourceShapeProp(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex, ERectangleShapeProp Prop, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_SourceIndex;
|
||||
|
||||
private:
|
||||
void Apply(int Value);
|
||||
};
|
||||
|
||||
class CEditorActionEditCircleSoundSourceShapeProp : public CEditorActionEditLayerPropBase<ECircleShapeProp>
|
||||
{
|
||||
public:
|
||||
CEditorActionEditCircleSoundSourceShapeProp(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex, ECircleShapeProp Prop, int Previous, int Current);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_SourceIndex;
|
||||
|
||||
private:
|
||||
void Apply(int Value);
|
||||
};
|
||||
|
||||
class CEditorActionNewEmptySound : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionNewEmptySound(CEditor *pEditor, int GroupIndex, int LayerIndex, int x, int y);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_X;
|
||||
int m_Y;
|
||||
};
|
||||
|
||||
class CEditorActionNewEmptyQuad : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionNewEmptyQuad(CEditor *pEditor, int GroupIndex, int LayerIndex, int x, int y);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
int m_X;
|
||||
int m_Y;
|
||||
};
|
||||
|
||||
class CEditorActionNewQuad : public CEditorActionLayerBase
|
||||
{
|
||||
public:
|
||||
CEditorActionNewQuad(CEditor *pEditor, int GroupIndex, int LayerIndex);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
CQuad m_Quad;
|
||||
};
|
||||
|
||||
#endif
|
65
src/game/editor/editor_history.cpp
Normal file
65
src/game/editor/editor_history.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include <engine/shared/config.h>
|
||||
|
||||
#include "editor.h"
|
||||
#include "editor_actions.h"
|
||||
#include "editor_history.h"
|
||||
|
||||
void CEditorHistory::RecordAction(const std::shared_ptr<IEditorAction> &pAction)
|
||||
{
|
||||
RecordAction(pAction, nullptr);
|
||||
}
|
||||
|
||||
void CEditorHistory::Execute(const std::shared_ptr<IEditorAction> &pAction, const char *pDisplay)
|
||||
{
|
||||
pAction->Redo();
|
||||
RecordAction(pAction, pDisplay);
|
||||
}
|
||||
|
||||
void CEditorHistory::RecordAction(const std::shared_ptr<IEditorAction> &pAction, const char *pDisplay)
|
||||
{
|
||||
m_vpRedoActions.clear();
|
||||
|
||||
if((int)m_vpUndoActions.size() >= g_Config.m_ClEditorMaxHistory)
|
||||
{
|
||||
m_vpUndoActions.pop_front();
|
||||
}
|
||||
|
||||
if(pDisplay == nullptr)
|
||||
m_vpUndoActions.emplace_back(pAction);
|
||||
else
|
||||
m_vpUndoActions.emplace_back(std::make_shared<CEditorActionBulk>(m_pEditor, std::vector<std::shared_ptr<IEditorAction>>{pAction}, pDisplay));
|
||||
}
|
||||
|
||||
bool CEditorHistory::Undo()
|
||||
{
|
||||
if(m_vpUndoActions.empty())
|
||||
return false;
|
||||
|
||||
auto pLastAction = m_vpUndoActions.back();
|
||||
m_vpUndoActions.pop_back();
|
||||
|
||||
pLastAction->Undo();
|
||||
|
||||
m_vpRedoActions.emplace_back(pLastAction);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CEditorHistory::Redo()
|
||||
{
|
||||
if(m_vpRedoActions.empty())
|
||||
return false;
|
||||
|
||||
auto pLastAction = m_vpRedoActions.back();
|
||||
m_vpRedoActions.pop_back();
|
||||
|
||||
pLastAction->Redo();
|
||||
|
||||
m_vpUndoActions.emplace_back(pLastAction);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CEditorHistory::Clear()
|
||||
{
|
||||
m_vpUndoActions.clear();
|
||||
m_vpRedoActions.clear();
|
||||
}
|
37
src/game/editor/editor_history.h
Normal file
37
src/game/editor/editor_history.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef GAME_EDITOR_EDITOR_HISTORY_H
|
||||
#define GAME_EDITOR_EDITOR_HISTORY_H
|
||||
|
||||
#include "editor_action.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
class CEditorHistory
|
||||
{
|
||||
public:
|
||||
CEditorHistory()
|
||||
{
|
||||
m_pEditor = nullptr;
|
||||
}
|
||||
|
||||
~CEditorHistory()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void RecordAction(const std::shared_ptr<IEditorAction> &pAction);
|
||||
void RecordAction(const std::shared_ptr<IEditorAction> &pAction, const char *pDisplay);
|
||||
void Execute(const std::shared_ptr<IEditorAction> &pAction, const char *pDisplay = nullptr);
|
||||
|
||||
bool Undo();
|
||||
bool Redo();
|
||||
|
||||
void Clear();
|
||||
bool CanUndo() const { return !m_vpUndoActions.empty(); }
|
||||
bool CanRedo() const { return !m_vpRedoActions.empty(); }
|
||||
|
||||
CEditor *m_pEditor;
|
||||
std::deque<std::shared_ptr<IEditorAction>> m_vpUndoActions;
|
||||
std::deque<std::shared_ptr<IEditorAction>> m_vpRedoActions;
|
||||
};
|
||||
|
||||
#endif
|
282
src/game/editor/editor_props.cpp
Normal file
282
src/game/editor/editor_props.cpp
Normal file
|
@ -0,0 +1,282 @@
|
|||
#include "editor.h"
|
||||
|
||||
#include <game/editor/mapitems/image.h>
|
||||
#include <game/editor/mapitems/sound.h>
|
||||
|
||||
int CEditor::DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color)
|
||||
{
|
||||
auto Res = DoPropertiesWithState<int>(pToolbox, pProps, pIDs, pNewVal, Color);
|
||||
return Res.m_Value;
|
||||
}
|
||||
|
||||
template<typename E>
|
||||
SEditResult<E> CEditor::DoPropertiesWithState(CUIRect *pToolBox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color)
|
||||
{
|
||||
int Change = -1;
|
||||
EEditState State = EEditState::EDITING;
|
||||
|
||||
for(int i = 0; pProps[i].m_pName; i++)
|
||||
{
|
||||
CUIRect Slot;
|
||||
pToolBox->HSplitTop(13.0f, &Slot, pToolBox);
|
||||
CUIRect Label, Shifter;
|
||||
Slot.VSplitMid(&Label, &Shifter);
|
||||
Shifter.HMargin(1.0f, &Shifter);
|
||||
UI()->DoLabel(&Label, pProps[i].m_pName, 10.0f, TEXTALIGN_ML);
|
||||
|
||||
if(pProps[i].m_Type == PROPTYPE_INT_STEP)
|
||||
{
|
||||
CUIRect Inc, Dec;
|
||||
char aBuf[64];
|
||||
|
||||
Shifter.VSplitRight(10.0f, &Shifter, &Inc);
|
||||
Shifter.VSplitLeft(10.0f, &Dec, &Shifter);
|
||||
str_from_int(pProps[i].m_Value, aBuf);
|
||||
auto NewValueRes = UiDoValueSelector((char *)&pIDs[i], &Shifter, "", pProps[i].m_Value, pProps[i].m_Min, pProps[i].m_Max, 1, 1.0f, "Use left mouse button to drag and change the value. Hold shift to be more precise. Rightclick to edit as text.", false, false, 0, &Color);
|
||||
int NewValue = NewValueRes.m_Value;
|
||||
if(NewValue != pProps[i].m_Value || NewValueRes.m_State != EEditState::EDITING)
|
||||
{
|
||||
*pNewVal = NewValue;
|
||||
Change = i;
|
||||
State = NewValueRes.m_State;
|
||||
}
|
||||
if(DoButton_ButtonDec((char *)&pIDs[i] + 1, nullptr, 0, &Dec, 0, "Decrease"))
|
||||
{
|
||||
*pNewVal = pProps[i].m_Value - 1;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
if(DoButton_ButtonInc(((char *)&pIDs[i]) + 2, nullptr, 0, &Inc, 0, "Increase"))
|
||||
{
|
||||
*pNewVal = pProps[i].m_Value + 1;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
}
|
||||
else if(pProps[i].m_Type == PROPTYPE_BOOL)
|
||||
{
|
||||
CUIRect No, Yes;
|
||||
Shifter.VSplitMid(&No, &Yes);
|
||||
if(DoButton_ButtonDec(&pIDs[i], "No", !pProps[i].m_Value, &No, 0, ""))
|
||||
{
|
||||
*pNewVal = 0;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
if(DoButton_ButtonInc(((char *)&pIDs[i]) + 1, "Yes", pProps[i].m_Value, &Yes, 0, ""))
|
||||
{
|
||||
*pNewVal = 1;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
}
|
||||
else if(pProps[i].m_Type == PROPTYPE_INT_SCROLL)
|
||||
{
|
||||
auto NewValueRes = UiDoValueSelector(&pIDs[i], &Shifter, "", pProps[i].m_Value, pProps[i].m_Min, pProps[i].m_Max, 1, 1.0f, "Use left mouse button to drag and change the value. Hold shift to be more precise. Rightclick to edit as text.");
|
||||
int NewValue = NewValueRes.m_Value;
|
||||
if(NewValue != pProps[i].m_Value || NewValueRes.m_State != EEditState::EDITING)
|
||||
{
|
||||
*pNewVal = NewValue;
|
||||
Change = i;
|
||||
State = NewValueRes.m_State;
|
||||
}
|
||||
}
|
||||
else if(pProps[i].m_Type == PROPTYPE_ANGLE_SCROLL)
|
||||
{
|
||||
CUIRect Inc, Dec;
|
||||
Shifter.VSplitRight(10.0f, &Shifter, &Inc);
|
||||
Shifter.VSplitLeft(10.0f, &Dec, &Shifter);
|
||||
const bool Shift = Input()->ShiftIsPressed();
|
||||
int Step = Shift ? 1 : 45;
|
||||
int Value = pProps[i].m_Value;
|
||||
|
||||
auto NewValueRes = UiDoValueSelector(&pIDs[i], &Shifter, "", Value, pProps[i].m_Min, pProps[i].m_Max, Shift ? 1 : 45, Shift ? 1.0f : 10.0f, "Use left mouse button to drag and change the value. Hold shift to be more precise. Rightclick to edit as text.", false, false, 0);
|
||||
int NewValue = NewValueRes.m_Value;
|
||||
if(DoButton_ButtonDec(&pIDs[i] + 1, nullptr, 0, &Dec, 0, "Decrease"))
|
||||
{
|
||||
NewValue = (std::ceil((pProps[i].m_Value / (float)Step)) - 1) * Step;
|
||||
if(NewValue < 0)
|
||||
NewValue += 360;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
if(DoButton_ButtonInc(&pIDs[i] + 2, nullptr, 0, &Inc, 0, "Increase"))
|
||||
{
|
||||
NewValue = (pProps[i].m_Value + Step) / Step * Step;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
|
||||
if(NewValue != pProps[i].m_Value || NewValueRes.m_State != EEditState::EDITING)
|
||||
{
|
||||
*pNewVal = NewValue % 360;
|
||||
Change = i;
|
||||
State = NewValueRes.m_State;
|
||||
}
|
||||
}
|
||||
else if(pProps[i].m_Type == PROPTYPE_COLOR)
|
||||
{
|
||||
const auto &&SetColor = [&](ColorRGBA NewColor) {
|
||||
const int NewValue = NewColor.PackAlphaLast();
|
||||
if(NewValue != pProps[i].m_Value || m_ColorPickerPopupContext.m_State != EEditState::EDITING)
|
||||
{
|
||||
*pNewVal = NewValue;
|
||||
Change = i;
|
||||
State = m_ColorPickerPopupContext.m_State;
|
||||
}
|
||||
};
|
||||
DoColorPickerButton(&pIDs[i], &Shifter, ColorRGBA::UnpackAlphaLast<ColorRGBA>(pProps[i].m_Value), SetColor);
|
||||
}
|
||||
else if(pProps[i].m_Type == PROPTYPE_IMAGE)
|
||||
{
|
||||
const char *pName;
|
||||
if(pProps[i].m_Value < 0)
|
||||
pName = "None";
|
||||
else
|
||||
pName = m_Map.m_vpImages[pProps[i].m_Value]->m_aName;
|
||||
|
||||
if(DoButton_Ex(&pIDs[i], pName, 0, &Shifter, 0, nullptr, IGraphics::CORNER_ALL))
|
||||
PopupSelectImageInvoke(pProps[i].m_Value, UI()->MouseX(), UI()->MouseY());
|
||||
|
||||
int r = PopupSelectImageResult();
|
||||
if(r >= -1)
|
||||
{
|
||||
*pNewVal = r;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
}
|
||||
else if(pProps[i].m_Type == PROPTYPE_SHIFT)
|
||||
{
|
||||
CUIRect Left, Right, Up, Down;
|
||||
Shifter.VSplitMid(&Left, &Up, 2.0f);
|
||||
Left.VSplitLeft(10.0f, &Left, &Shifter);
|
||||
Shifter.VSplitRight(10.0f, &Shifter, &Right);
|
||||
Shifter.Draw(ColorRGBA(1, 1, 1, 0.5f), 0, 0.0f);
|
||||
UI()->DoLabel(&Shifter, "X", 10.0f, TEXTALIGN_MC);
|
||||
Up.VSplitLeft(10.0f, &Up, &Shifter);
|
||||
Shifter.VSplitRight(10.0f, &Shifter, &Down);
|
||||
Shifter.Draw(ColorRGBA(1, 1, 1, 0.5f), 0, 0.0f);
|
||||
UI()->DoLabel(&Shifter, "Y", 10.0f, TEXTALIGN_MC);
|
||||
if(DoButton_ButtonDec(&pIDs[i], "-", 0, &Left, 0, "Left"))
|
||||
{
|
||||
*pNewVal = DIRECTION_LEFT;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
if(DoButton_ButtonInc(((char *)&pIDs[i]) + 3, "+", 0, &Right, 0, "Right"))
|
||||
{
|
||||
*pNewVal = DIRECTION_RIGHT;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
if(DoButton_ButtonDec(((char *)&pIDs[i]) + 1, "-", 0, &Up, 0, "Up"))
|
||||
{
|
||||
*pNewVal = DIRECTION_UP;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
if(DoButton_ButtonInc(((char *)&pIDs[i]) + 2, "+", 0, &Down, 0, "Down"))
|
||||
{
|
||||
*pNewVal = DIRECTION_DOWN;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
}
|
||||
else if(pProps[i].m_Type == PROPTYPE_SOUND)
|
||||
{
|
||||
const char *pName;
|
||||
if(pProps[i].m_Value < 0)
|
||||
pName = "None";
|
||||
else
|
||||
pName = m_Map.m_vpSounds[pProps[i].m_Value]->m_aName;
|
||||
|
||||
if(DoButton_Ex(&pIDs[i], pName, 0, &Shifter, 0, nullptr, IGraphics::CORNER_ALL))
|
||||
PopupSelectSoundInvoke(pProps[i].m_Value, UI()->MouseX(), UI()->MouseY());
|
||||
|
||||
int r = PopupSelectSoundResult();
|
||||
if(r >= -1)
|
||||
{
|
||||
*pNewVal = r;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
}
|
||||
else if(pProps[i].m_Type == PROPTYPE_AUTOMAPPER)
|
||||
{
|
||||
const char *pName;
|
||||
if(pProps[i].m_Value < 0 || pProps[i].m_Min < 0 || pProps[i].m_Min >= (int)m_Map.m_vpImages.size())
|
||||
pName = "None";
|
||||
else
|
||||
pName = m_Map.m_vpImages[pProps[i].m_Min]->m_AutoMapper.GetConfigName(pProps[i].m_Value);
|
||||
|
||||
if(DoButton_Ex(&pIDs[i], pName, 0, &Shifter, 0, nullptr, IGraphics::CORNER_ALL))
|
||||
PopupSelectConfigAutoMapInvoke(pProps[i].m_Value, UI()->MouseX(), UI()->MouseY());
|
||||
|
||||
int r = PopupSelectConfigAutoMapResult();
|
||||
if(r >= -1)
|
||||
{
|
||||
*pNewVal = r;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
}
|
||||
else if(pProps[i].m_Type == PROPTYPE_ENVELOPE)
|
||||
{
|
||||
CUIRect Inc, Dec;
|
||||
char aBuf[8];
|
||||
int CurValue = pProps[i].m_Value;
|
||||
|
||||
Shifter.VSplitRight(10.0f, &Shifter, &Inc);
|
||||
Shifter.VSplitLeft(10.0f, &Dec, &Shifter);
|
||||
|
||||
if(CurValue <= 0)
|
||||
str_copy(aBuf, "None:");
|
||||
else if(m_Map.m_vpEnvelopes[CurValue - 1]->m_aName[0])
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "%s:", m_Map.m_vpEnvelopes[CurValue - 1]->m_aName);
|
||||
if(!str_endswith(aBuf, ":"))
|
||||
{
|
||||
aBuf[sizeof(aBuf) - 2] = ':';
|
||||
aBuf[sizeof(aBuf) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
aBuf[0] = '\0';
|
||||
|
||||
auto NewValueRes = UiDoValueSelector((char *)&pIDs[i], &Shifter, aBuf, CurValue, 0, m_Map.m_vpEnvelopes.size(), 1, 1.0f, "Set Envelope", false, false, IGraphics::CORNER_NONE);
|
||||
int NewVal = NewValueRes.m_Value;
|
||||
if(NewVal != CurValue || NewValueRes.m_State != EEditState::EDITING)
|
||||
{
|
||||
*pNewVal = NewVal;
|
||||
Change = i;
|
||||
State = NewValueRes.m_State;
|
||||
}
|
||||
|
||||
if(DoButton_ButtonDec((char *)&pIDs[i] + 1, nullptr, 0, &Dec, 0, "Previous Envelope"))
|
||||
{
|
||||
*pNewVal = pProps[i].m_Value - 1;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
if(DoButton_ButtonInc(((char *)&pIDs[i]) + 2, nullptr, 0, &Inc, 0, "Next Envelope"))
|
||||
{
|
||||
*pNewVal = pProps[i].m_Value + 1;
|
||||
Change = i;
|
||||
State = EEditState::ONE_GO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SEditResult<E>{State, static_cast<E>(Change)};
|
||||
}
|
||||
|
||||
template SEditResult<ECircleShapeProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, ColorRGBA);
|
||||
template SEditResult<ERectangleShapeProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, ColorRGBA);
|
||||
template SEditResult<EGroupProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, ColorRGBA);
|
||||
template SEditResult<ELayerProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, ColorRGBA);
|
||||
template SEditResult<ELayerQuadsProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, ColorRGBA);
|
||||
template SEditResult<ETilesProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, ColorRGBA);
|
||||
template SEditResult<ETilesCommonProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, ColorRGBA);
|
||||
template SEditResult<ELayerSoundsProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, ColorRGBA);
|
||||
template SEditResult<EQuadProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, ColorRGBA);
|
||||
template SEditResult<EQuadPointProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, ColorRGBA);
|
||||
template SEditResult<ESoundProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, ColorRGBA);
|
632
src/game/editor/editor_trackers.cpp
Normal file
632
src/game/editor/editor_trackers.cpp
Normal file
|
@ -0,0 +1,632 @@
|
|||
#include "editor_trackers.h"
|
||||
|
||||
#include <game/editor/mapitems/layer_group.h>
|
||||
#include <game/editor/mapitems/layer_tiles.h>
|
||||
|
||||
#include "editor.h"
|
||||
#include "editor_actions.h"
|
||||
|
||||
CQuadEditTracker::CQuadEditTracker() :
|
||||
m_pEditor(nullptr), m_TrackedProp(EQuadProp::PROP_NONE) {}
|
||||
|
||||
CQuadEditTracker::~CQuadEditTracker()
|
||||
{
|
||||
m_InitalPoints.clear();
|
||||
m_vSelectedQuads.clear();
|
||||
}
|
||||
|
||||
void CQuadEditTracker::BeginQuadTrack(const std::shared_ptr<CLayerQuads> &pLayer, const std::vector<int> &vSelectedQuads)
|
||||
{
|
||||
if(m_Tracking)
|
||||
return;
|
||||
m_Tracking = true;
|
||||
m_vSelectedQuads.clear();
|
||||
m_pLayer = pLayer;
|
||||
// Init all points
|
||||
for(auto QuadIndex : vSelectedQuads)
|
||||
{
|
||||
auto &pQuad = pLayer->m_vQuads[QuadIndex];
|
||||
m_InitalPoints[QuadIndex] = std::vector<CPoint>(pQuad.m_aPoints, pQuad.m_aPoints + 5);
|
||||
m_vSelectedQuads.push_back(QuadIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void CQuadEditTracker::EndQuadTrack()
|
||||
{
|
||||
if(!m_Tracking)
|
||||
return;
|
||||
m_Tracking = false;
|
||||
|
||||
int GroupIndex = m_pEditor->m_SelectedGroup;
|
||||
int LayerIndex = m_pEditor->m_vSelectedLayers[0];
|
||||
|
||||
// Record all moved stuff
|
||||
std::vector<std::shared_ptr<IEditorAction>> vpActions;
|
||||
for(auto QuadIndex : m_vSelectedQuads)
|
||||
{
|
||||
auto &pQuad = m_pLayer->m_vQuads[QuadIndex];
|
||||
auto vCurrentPoints = std::vector<CPoint>(pQuad.m_aPoints, pQuad.m_aPoints + 5);
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditQuadPoint>(m_pEditor, GroupIndex, LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints));
|
||||
}
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions));
|
||||
}
|
||||
|
||||
void CQuadEditTracker::BeginQuadPropTrack(const std::shared_ptr<CLayerQuads> &pLayer, const std::vector<int> &vSelectedQuads, EQuadProp Prop)
|
||||
{
|
||||
if(m_TrackedProp != EQuadProp::PROP_NONE)
|
||||
return;
|
||||
m_TrackedProp = Prop;
|
||||
m_pLayer = pLayer;
|
||||
m_vSelectedQuads = vSelectedQuads;
|
||||
m_PreviousValues.clear();
|
||||
|
||||
for(auto QuadIndex : vSelectedQuads)
|
||||
{
|
||||
auto &Quad = pLayer->m_vQuads[QuadIndex];
|
||||
if(Prop == EQuadProp::PROP_POS_X || Prop == EQuadProp::PROP_POS_Y)
|
||||
m_InitalPoints[QuadIndex] = std::vector<CPoint>(Quad.m_aPoints, Quad.m_aPoints + 5);
|
||||
else if(Prop == EQuadProp::PROP_POS_ENV)
|
||||
m_PreviousValues[QuadIndex] = Quad.m_PosEnv;
|
||||
else if(Prop == EQuadProp::PROP_POS_ENV_OFFSET)
|
||||
m_PreviousValues[QuadIndex] = Quad.m_PosEnvOffset;
|
||||
else if(Prop == EQuadProp::PROP_COLOR_ENV)
|
||||
m_PreviousValues[QuadIndex] = Quad.m_ColorEnv;
|
||||
else if(Prop == EQuadProp::PROP_COLOR_ENV_OFFSET)
|
||||
m_PreviousValues[QuadIndex] = Quad.m_ColorEnvOffset;
|
||||
}
|
||||
}
|
||||
void CQuadEditTracker::EndQuadPropTrack(EQuadProp Prop)
|
||||
{
|
||||
if(m_TrackedProp != Prop)
|
||||
return;
|
||||
m_TrackedProp = EQuadProp::PROP_NONE;
|
||||
|
||||
std::vector<std::shared_ptr<IEditorAction>> vpActions;
|
||||
|
||||
int GroupIndex = m_pEditor->m_SelectedGroup;
|
||||
int LayerIndex = m_pEditor->m_vSelectedLayers[0];
|
||||
|
||||
for(auto QuadIndex : m_vSelectedQuads)
|
||||
{
|
||||
auto &Quad = m_pLayer->m_vQuads[QuadIndex];
|
||||
if(Prop == EQuadProp::PROP_POS_X || Prop == EQuadProp::PROP_POS_Y)
|
||||
{
|
||||
auto vCurrentPoints = std::vector<CPoint>(Quad.m_aPoints, Quad.m_aPoints + 5);
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditQuadPoint>(m_pEditor, GroupIndex, LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints));
|
||||
}
|
||||
else
|
||||
{
|
||||
int Value = 0;
|
||||
if(Prop == EQuadProp::PROP_POS_ENV)
|
||||
Value = Quad.m_PosEnv;
|
||||
else if(Prop == EQuadProp::PROP_POS_ENV_OFFSET)
|
||||
Value = Quad.m_PosEnvOffset;
|
||||
else if(Prop == EQuadProp::PROP_COLOR_ENV)
|
||||
Value = Quad.m_ColorEnv;
|
||||
else if(Prop == EQuadProp::PROP_COLOR_ENV_OFFSET)
|
||||
Value = Quad.m_ColorEnvOffset;
|
||||
|
||||
if(Value != m_PreviousValues[QuadIndex])
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditQuadProp>(m_pEditor, GroupIndex, LayerIndex, QuadIndex, Prop, m_PreviousValues[QuadIndex], Value));
|
||||
}
|
||||
}
|
||||
|
||||
if(!vpActions.empty())
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions));
|
||||
}
|
||||
|
||||
void CQuadEditTracker::BeginQuadPointPropTrack(const std::shared_ptr<CLayerQuads> &pLayer, const std::vector<int> &vSelectedQuads, int SelectedQuadPoints)
|
||||
{
|
||||
if(!m_vTrackedProps.empty())
|
||||
return;
|
||||
|
||||
m_pLayer = pLayer;
|
||||
m_SelectedQuadPoints = SelectedQuadPoints;
|
||||
m_vSelectedQuads = vSelectedQuads;
|
||||
m_PreviousValuesPoint.clear();
|
||||
|
||||
for(auto QuadIndex : vSelectedQuads)
|
||||
{
|
||||
m_PreviousValuesPoint[QuadIndex] = std::vector<std::map<EQuadPointProp, int>>(4);
|
||||
}
|
||||
}
|
||||
|
||||
void CQuadEditTracker::AddQuadPointPropTrack(EQuadPointProp Prop)
|
||||
{
|
||||
if(std::find(m_vTrackedProps.begin(), m_vTrackedProps.end(), Prop) != m_vTrackedProps.end())
|
||||
return;
|
||||
|
||||
m_vTrackedProps.push_back(Prop);
|
||||
|
||||
for(auto QuadIndex : m_vSelectedQuads)
|
||||
{
|
||||
auto &Quad = m_pLayer->m_vQuads[QuadIndex];
|
||||
if(Prop == EQuadPointProp::PROP_POS_X || Prop == EQuadPointProp::PROP_POS_Y)
|
||||
m_InitalPoints[QuadIndex] = std::vector<CPoint>(Quad.m_aPoints, Quad.m_aPoints + 5);
|
||||
else if(Prop == EQuadPointProp::PROP_COLOR)
|
||||
{
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
if(m_SelectedQuadPoints & (1 << v))
|
||||
{
|
||||
int Color = PackColor(Quad.m_aColors[v]);
|
||||
m_PreviousValuesPoint[QuadIndex][v][Prop] = Color;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(Prop == EQuadPointProp::PROP_TEX_U)
|
||||
{
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
if(m_SelectedQuadPoints & (1 << v))
|
||||
{
|
||||
m_PreviousValuesPoint[QuadIndex][v][Prop] = Quad.m_aTexcoords[v].x;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(Prop == EQuadPointProp::PROP_TEX_V)
|
||||
{
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
if(m_SelectedQuadPoints & (1 << v))
|
||||
{
|
||||
m_PreviousValuesPoint[QuadIndex][v][Prop] = Quad.m_aTexcoords[v].y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CQuadEditTracker::EndQuadPointPropTrack(EQuadPointProp Prop)
|
||||
{
|
||||
auto It = std::find(m_vTrackedProps.begin(), m_vTrackedProps.end(), Prop);
|
||||
if(It == m_vTrackedProps.end())
|
||||
return;
|
||||
|
||||
m_vTrackedProps.erase(It);
|
||||
|
||||
std::vector<std::shared_ptr<IEditorAction>> vpActions;
|
||||
|
||||
int GroupIndex = m_pEditor->m_SelectedGroup;
|
||||
int LayerIndex = m_pEditor->m_vSelectedLayers[0];
|
||||
|
||||
for(auto QuadIndex : m_vSelectedQuads)
|
||||
{
|
||||
auto &Quad = m_pLayer->m_vQuads[QuadIndex];
|
||||
if(Prop == EQuadPointProp::PROP_POS_X || Prop == EQuadPointProp::PROP_POS_Y)
|
||||
{
|
||||
auto vCurrentPoints = std::vector<CPoint>(Quad.m_aPoints, Quad.m_aPoints + 5);
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditQuadPoint>(m_pEditor, GroupIndex, LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints));
|
||||
}
|
||||
else
|
||||
{
|
||||
int Value = 0;
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
if(m_SelectedQuadPoints & (1 << v))
|
||||
{
|
||||
if(Prop == EQuadPointProp::PROP_COLOR)
|
||||
{
|
||||
Value = PackColor(Quad.m_aColors[v]);
|
||||
}
|
||||
else if(Prop == EQuadPointProp::PROP_TEX_U)
|
||||
{
|
||||
Value = Quad.m_aTexcoords[v].x;
|
||||
}
|
||||
else if(Prop == EQuadPointProp::PROP_TEX_V)
|
||||
{
|
||||
Value = Quad.m_aTexcoords[v].y;
|
||||
}
|
||||
|
||||
if(Value != m_PreviousValuesPoint[QuadIndex][v][Prop])
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditQuadPointProp>(m_pEditor, GroupIndex, LayerIndex, QuadIndex, v, Prop, m_PreviousValuesPoint[QuadIndex][v][Prop], Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!vpActions.empty())
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions));
|
||||
}
|
||||
|
||||
void CQuadEditTracker::EndQuadPointPropTrackAll()
|
||||
{
|
||||
std::vector<std::shared_ptr<IEditorAction>> vpActions;
|
||||
for(auto &Prop : m_vTrackedProps)
|
||||
{
|
||||
int GroupIndex = m_pEditor->m_SelectedGroup;
|
||||
int LayerIndex = m_pEditor->m_vSelectedLayers[0];
|
||||
|
||||
for(auto QuadIndex : m_vSelectedQuads)
|
||||
{
|
||||
auto &Quad = m_pLayer->m_vQuads[QuadIndex];
|
||||
if(Prop == EQuadPointProp::PROP_POS_X || Prop == EQuadPointProp::PROP_POS_Y)
|
||||
{
|
||||
auto vCurrentPoints = std::vector<CPoint>(Quad.m_aPoints, Quad.m_aPoints + 5);
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditQuadPoint>(m_pEditor, GroupIndex, LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints));
|
||||
}
|
||||
else
|
||||
{
|
||||
int Value = 0;
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
if(m_SelectedQuadPoints & (1 << v))
|
||||
{
|
||||
if(Prop == EQuadPointProp::PROP_COLOR)
|
||||
{
|
||||
Value = PackColor(Quad.m_aColors[v]);
|
||||
}
|
||||
else if(Prop == EQuadPointProp::PROP_TEX_U)
|
||||
{
|
||||
Value = Quad.m_aTexcoords[v].x;
|
||||
}
|
||||
else if(Prop == EQuadPointProp::PROP_TEX_V)
|
||||
{
|
||||
Value = Quad.m_aTexcoords[v].y;
|
||||
}
|
||||
|
||||
if(Value != m_PreviousValuesPoint[QuadIndex][v][Prop])
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditQuadPointProp>(m_pEditor, GroupIndex, LayerIndex, QuadIndex, v, Prop, m_PreviousValuesPoint[QuadIndex][v][Prop], Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!vpActions.empty())
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions));
|
||||
|
||||
m_vTrackedProps.clear();
|
||||
}
|
||||
|
||||
void CEditorPropTracker::BeginPropTrack(int Prop, int Value)
|
||||
{
|
||||
if(m_TrackedProp != -1 || m_TrackedProp == Prop)
|
||||
return;
|
||||
m_TrackedProp = Prop;
|
||||
m_PreviousValue = Value;
|
||||
}
|
||||
|
||||
void CEditorPropTracker::StopPropTrack(int Prop, int Value)
|
||||
{
|
||||
if(Prop != m_TrackedProp)
|
||||
return;
|
||||
m_TrackedProp = -1;
|
||||
m_CurrentValue = Value;
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
|
||||
void CEnvelopeEditorOperationTracker::Begin(EEnvelopeEditorOp Operation)
|
||||
{
|
||||
if(m_TrackedOp == Operation)
|
||||
return;
|
||||
|
||||
if(m_TrackedOp != EEnvelopeEditorOp::OP_NONE)
|
||||
{
|
||||
Stop(true);
|
||||
}
|
||||
|
||||
m_TrackedOp = Operation;
|
||||
|
||||
if(Operation == EEnvelopeEditorOp::OP_DRAG_POINT || Operation == EEnvelopeEditorOp::OP_DRAG_POINT_X || Operation == EEnvelopeEditorOp::OP_DRAG_POINT_Y || Operation == EEnvelopeEditorOp::OP_SCALE)
|
||||
{
|
||||
HandlePointDragStart();
|
||||
}
|
||||
}
|
||||
|
||||
void CEnvelopeEditorOperationTracker::Stop(bool Switch)
|
||||
{
|
||||
if(m_TrackedOp == EEnvelopeEditorOp::OP_NONE)
|
||||
return;
|
||||
|
||||
if(m_TrackedOp == EEnvelopeEditorOp::OP_DRAG_POINT || m_TrackedOp == EEnvelopeEditorOp::OP_DRAG_POINT_X || m_TrackedOp == EEnvelopeEditorOp::OP_DRAG_POINT_Y || m_TrackedOp == EEnvelopeEditorOp::OP_SCALE)
|
||||
{
|
||||
HandlePointDragEnd(Switch);
|
||||
}
|
||||
|
||||
m_TrackedOp = EEnvelopeEditorOp::OP_NONE;
|
||||
}
|
||||
|
||||
void CEnvelopeEditorOperationTracker::HandlePointDragStart()
|
||||
{
|
||||
// Figure out which points are selected and which channels
|
||||
// Save their X and Y position (time and value)
|
||||
auto pEnv = m_pEditor->m_Map.m_vpEnvelopes[m_pEditor->m_SelectedEnvelope];
|
||||
|
||||
for(auto [PointIndex, Channel] : m_pEditor->m_vSelectedEnvelopePoints)
|
||||
{
|
||||
auto &Point = pEnv->m_vPoints[PointIndex];
|
||||
auto &Data = m_SavedValues[PointIndex];
|
||||
Data.m_Values[Channel] = Point.m_aValues[Channel];
|
||||
if(Data.m_Used)
|
||||
continue;
|
||||
Data.m_Time = Point.m_Time;
|
||||
Data.m_Used = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CEnvelopeEditorOperationTracker::HandlePointDragEnd(bool Switch)
|
||||
{
|
||||
if(Switch && m_TrackedOp != EEnvelopeEditorOp::OP_SCALE)
|
||||
return;
|
||||
|
||||
int EnvIndex = m_pEditor->m_SelectedEnvelope;
|
||||
auto pEnv = m_pEditor->m_Map.m_vpEnvelopes[EnvIndex];
|
||||
std::vector<std::shared_ptr<IEditorAction>> vpActions;
|
||||
|
||||
for(auto const &Entry : m_SavedValues)
|
||||
{
|
||||
int PointIndex = Entry.first;
|
||||
auto &Point = pEnv->m_vPoints[PointIndex];
|
||||
const auto &Data = Entry.second;
|
||||
|
||||
if(Data.m_Time != Point.m_Time)
|
||||
{ // Save time
|
||||
vpActions.push_back(std::make_shared<CEditorActionEnvelopeEditPoint>(m_pEditor, EnvIndex, PointIndex, 0, CEditorActionEnvelopeEditPoint::EEditType::TIME, Data.m_Time, Point.m_Time));
|
||||
}
|
||||
|
||||
for(auto Value : Data.m_Values)
|
||||
{
|
||||
// Value.second is the saved value, Value.first is the channel
|
||||
int Channel = Value.first;
|
||||
if(Value.second != Point.m_aValues[Channel])
|
||||
{ // Save value
|
||||
vpActions.push_back(std::make_shared<CEditorActionEnvelopeEditPoint>(m_pEditor, EnvIndex, PointIndex, Channel, CEditorActionEnvelopeEditPoint::EEditType::VALUE, Value.second, Point.m_aValues[Channel]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!vpActions.empty())
|
||||
{
|
||||
m_pEditor->m_EnvelopeEditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions, "Envelope point drag"));
|
||||
}
|
||||
|
||||
m_SavedValues.clear();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
void CLayerPropTracker::OnEnd(ELayerProp Prop, int Value)
|
||||
{
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionEditLayerProp>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], Prop, m_OriginalValue, Value));
|
||||
}
|
||||
|
||||
int CLayerPropTracker::PropToValue(ELayerProp Prop)
|
||||
{
|
||||
switch(Prop)
|
||||
{
|
||||
case ELayerProp::PROP_GROUP: return m_pEditor->m_SelectedGroup;
|
||||
case ELayerProp::PROP_HQ: return m_pObject->m_Flags;
|
||||
case ELayerProp::PROP_ORDER: return m_pEditor->m_vSelectedLayers[0];
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
bool CLayerTilesPropTracker::EndChecker(ETilesProp Prop, EEditState State, int Value)
|
||||
{
|
||||
return (State == EEditState::END || State == EEditState::ONE_GO) && (Value != m_OriginalValue || Prop == ETilesProp::PROP_SHIFT);
|
||||
}
|
||||
|
||||
void CLayerTilesPropTracker::OnStart(ETilesProp Prop)
|
||||
{
|
||||
if(Prop == ETilesProp::PROP_WIDTH || Prop == ETilesProp::PROP_HEIGHT)
|
||||
{
|
||||
m_SavedLayers[LAYERTYPE_TILES] = m_pObject->Duplicate();
|
||||
if(m_pObject->m_Game || m_pObject->m_Front || m_pObject->m_Switch || m_pObject->m_Speedup || m_pObject->m_Tune || m_pObject->m_Tele)
|
||||
{ // Need to save all entities layers when any entity layer
|
||||
if(m_pEditor->m_Map.m_pFrontLayer && !m_pObject->m_Front)
|
||||
m_SavedLayers[LAYERTYPE_FRONT] = m_pEditor->m_Map.m_pFrontLayer->Duplicate();
|
||||
if(m_pEditor->m_Map.m_pTeleLayer && !m_pObject->m_Tele)
|
||||
m_SavedLayers[LAYERTYPE_TELE] = m_pEditor->m_Map.m_pTeleLayer->Duplicate();
|
||||
if(m_pEditor->m_Map.m_pSwitchLayer && !m_pObject->m_Switch)
|
||||
m_SavedLayers[LAYERTYPE_SWITCH] = m_pEditor->m_Map.m_pSwitchLayer->Duplicate();
|
||||
if(m_pEditor->m_Map.m_pSpeedupLayer && !m_pObject->m_Speedup)
|
||||
m_SavedLayers[LAYERTYPE_SPEEDUP] = m_pEditor->m_Map.m_pSpeedupLayer->Duplicate();
|
||||
if(m_pEditor->m_Map.m_pTuneLayer && !m_pObject->m_Tune)
|
||||
m_SavedLayers[LAYERTYPE_TUNE] = m_pEditor->m_Map.m_pTuneLayer->Duplicate();
|
||||
if(!m_pObject->m_Game)
|
||||
m_SavedLayers[LAYERTYPE_GAME] = m_pEditor->m_Map.m_pGameLayer->Duplicate();
|
||||
}
|
||||
}
|
||||
else if(Prop == ETilesProp::PROP_SHIFT)
|
||||
{
|
||||
m_SavedLayers[LAYERTYPE_TILES] = m_pObject->Duplicate();
|
||||
}
|
||||
}
|
||||
|
||||
void CLayerTilesPropTracker::OnEnd(ETilesProp Prop, int Value)
|
||||
{
|
||||
auto pAction = std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], Prop, m_OriginalValue, Value);
|
||||
|
||||
pAction->SetSavedLayers(m_SavedLayers);
|
||||
m_SavedLayers.clear();
|
||||
|
||||
m_pEditor->m_EditorHistory.RecordAction(pAction);
|
||||
}
|
||||
|
||||
int CLayerTilesPropTracker::PropToValue(ETilesProp Prop)
|
||||
{
|
||||
switch(Prop)
|
||||
{
|
||||
case ETilesProp::PROP_AUTOMAPPER: return m_pObject->m_AutoMapperConfig;
|
||||
case ETilesProp::PROP_COLOR: return PackColor(m_pObject->m_Color);
|
||||
case ETilesProp::PROP_COLOR_ENV: return m_pObject->m_ColorEnv;
|
||||
case ETilesProp::PROP_COLOR_ENV_OFFSET: return m_pObject->m_ColorEnvOffset;
|
||||
case ETilesProp::PROP_HEIGHT: return m_pObject->m_Height;
|
||||
case ETilesProp::PROP_WIDTH: return m_pObject->m_Width;
|
||||
case ETilesProp::PROP_IMAGE: return m_pObject->m_Image;
|
||||
case ETilesProp::PROP_SEED: return m_pObject->m_Seed;
|
||||
case ETilesProp::PROP_SHIFT_BY: return m_pEditor->m_ShiftBy;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
|
||||
void CLayerTilesCommonPropTracker::OnStart(ETilesCommonProp Prop)
|
||||
{
|
||||
for(auto &pLayer : m_vpLayers)
|
||||
{
|
||||
if(Prop == ETilesCommonProp::PROP_SHIFT)
|
||||
{
|
||||
m_SavedLayers[pLayer][LAYERTYPE_TILES] = pLayer->Duplicate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CLayerTilesCommonPropTracker::OnEnd(ETilesCommonProp Prop, int Value)
|
||||
{
|
||||
std::vector<std::shared_ptr<IEditorAction>> vpActions;
|
||||
|
||||
static std::map<ETilesCommonProp, ETilesProp> s_PropMap{
|
||||
{ETilesCommonProp::PROP_COLOR, ETilesProp::PROP_COLOR},
|
||||
{ETilesCommonProp::PROP_SHIFT, ETilesProp::PROP_SHIFT},
|
||||
{ETilesCommonProp::PROP_SHIFT_BY, ETilesProp::PROP_SHIFT_BY}};
|
||||
|
||||
int j = 0;
|
||||
for(auto &pLayer : m_vpLayers)
|
||||
{
|
||||
int LayerIndex = m_vLayerIndices[j++];
|
||||
auto pAction = std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, LayerIndex, s_PropMap[Prop], m_OriginalValue, Value);
|
||||
pAction->SetSavedLayers(m_SavedLayers[pLayer]);
|
||||
vpActions.push_back(pAction);
|
||||
}
|
||||
|
||||
char aDisplay[256];
|
||||
static const char *s_apNames[] = {
|
||||
"width",
|
||||
"height",
|
||||
"shift",
|
||||
"shift by",
|
||||
"color",
|
||||
};
|
||||
|
||||
str_format(aDisplay, sizeof(aDisplay), "Edit %d layers common property: %s", (int)m_vpLayers.size(), s_apNames[(int)Prop]);
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions, aDisplay));
|
||||
}
|
||||
|
||||
bool CLayerTilesCommonPropTracker::EndChecker(ETilesCommonProp Prop, EEditState State, int Value)
|
||||
{
|
||||
return (State == EEditState::END || State == EEditState::ONE_GO) && (Value != m_OriginalValue || Prop == ETilesCommonProp::PROP_SHIFT);
|
||||
}
|
||||
|
||||
int CLayerTilesCommonPropTracker::PropToValue(ETilesCommonProp Prop)
|
||||
{
|
||||
if(Prop == ETilesCommonProp::PROP_SHIFT_BY)
|
||||
return m_pEditor->m_ShiftBy;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
|
||||
void CLayerGroupPropTracker::OnEnd(EGroupProp Prop, int Value)
|
||||
{
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionEditGroupProp>(m_pEditor, m_pEditor->m_SelectedGroup, Prop, m_OriginalValue, Value));
|
||||
}
|
||||
|
||||
int CLayerGroupPropTracker::PropToValue(EGroupProp Prop)
|
||||
{
|
||||
switch(Prop)
|
||||
{
|
||||
case EGroupProp::PROP_ORDER: return m_pEditor->m_SelectedGroup;
|
||||
case EGroupProp::PROP_POS_X: return m_pObject->m_OffsetX;
|
||||
case EGroupProp::PROP_POS_Y: return m_pObject->m_OffsetY;
|
||||
case EGroupProp::PROP_PARA_X: return m_pObject->m_ParallaxX;
|
||||
case EGroupProp::PROP_PARA_Y: return m_pObject->m_ParallaxY;
|
||||
case EGroupProp::PROP_USE_CLIPPING: return m_pObject->m_UseClipping;
|
||||
case EGroupProp::PROP_CLIP_X: return m_pObject->m_ClipX;
|
||||
case EGroupProp::PROP_CLIP_Y: return m_pObject->m_ClipY;
|
||||
case EGroupProp::PROP_CLIP_W: return m_pObject->m_ClipW;
|
||||
case EGroupProp::PROP_CLIP_H: return m_pObject->m_ClipH;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
void CLayerQuadsPropTracker::OnEnd(ELayerQuadsProp Prop, int Value)
|
||||
{
|
||||
auto pAction = std::make_shared<CEditorActionEditLayerQuadsProp>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], Prop, m_OriginalValue, Value);
|
||||
m_pEditor->m_EditorHistory.RecordAction(pAction);
|
||||
}
|
||||
|
||||
int CLayerQuadsPropTracker::PropToValue(ELayerQuadsProp Prop)
|
||||
{
|
||||
if(Prop == ELayerQuadsProp::PROP_IMAGE)
|
||||
return m_pObject->m_Image;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
void CLayerSoundsPropTracker::OnEnd(ELayerSoundsProp Prop, int Value)
|
||||
{
|
||||
auto pAction = std::make_shared<CEditorActionEditLayerSoundsProp>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], Prop, m_OriginalValue, Value);
|
||||
m_pEditor->m_EditorHistory.RecordAction(pAction);
|
||||
}
|
||||
|
||||
int CLayerSoundsPropTracker::PropToValue(ELayerSoundsProp Prop)
|
||||
{
|
||||
if(Prop == ELayerSoundsProp::PROP_SOUND)
|
||||
return m_pObject->m_Sound;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----
|
||||
|
||||
void CSoundSourcePropTracker::OnEnd(ESoundProp Prop, int Value)
|
||||
{
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionEditSoundSourceProp>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], m_pEditor->m_SelectedSource, Prop, m_OriginalValue, Value));
|
||||
}
|
||||
|
||||
int CSoundSourcePropTracker::PropToValue(ESoundProp Prop)
|
||||
{
|
||||
switch(Prop)
|
||||
{
|
||||
case ESoundProp::PROP_POS_X: return m_pObject->m_Position.x;
|
||||
case ESoundProp::PROP_POS_Y: return m_pObject->m_Position.y;
|
||||
case ESoundProp::PROP_LOOP: return m_pObject->m_Loop;
|
||||
case ESoundProp::PROP_PAN: return m_pObject->m_Pan;
|
||||
case ESoundProp::PROP_TIME_DELAY: return m_pObject->m_TimeDelay;
|
||||
case ESoundProp::PROP_FALLOFF: return m_pObject->m_Falloff;
|
||||
case ESoundProp::PROP_POS_ENV: return m_pObject->m_PosEnv;
|
||||
case ESoundProp::PROP_POS_ENV_OFFSET: return m_pObject->m_PosEnvOffset;
|
||||
case ESoundProp::PROP_SOUND_ENV: return m_pObject->m_SoundEnv;
|
||||
case ESoundProp::PROP_SOUND_ENV_OFFSET: return m_pObject->m_SoundEnvOffset;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
|
||||
void CSoundSourceRectShapePropTracker::OnEnd(ERectangleShapeProp Prop, int Value)
|
||||
{
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionEditRectSoundSourceShapeProp>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], m_pEditor->m_SelectedSource, Prop, m_OriginalValue, Value));
|
||||
}
|
||||
|
||||
int CSoundSourceRectShapePropTracker::PropToValue(ERectangleShapeProp Prop)
|
||||
{
|
||||
switch(Prop)
|
||||
{
|
||||
case ERectangleShapeProp::PROP_RECTANGLE_WIDTH: return m_pObject->m_Shape.m_Rectangle.m_Width;
|
||||
case ERectangleShapeProp::PROP_RECTANGLE_HEIGHT: return m_pObject->m_Shape.m_Rectangle.m_Height;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CSoundSourceCircleShapePropTracker::OnEnd(ECircleShapeProp Prop, int Value)
|
||||
{
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionEditCircleSoundSourceShapeProp>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], m_pEditor->m_SelectedSource, Prop, m_OriginalValue, Value));
|
||||
}
|
||||
|
||||
int CSoundSourceCircleShapePropTracker::PropToValue(ECircleShapeProp Prop)
|
||||
{
|
||||
switch(Prop)
|
||||
{
|
||||
case ECircleShapeProp::PROP_CIRCLE_RADIUS: return m_pObject->m_Shape.m_Circle.m_Radius;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
271
src/game/editor/editor_trackers.h
Normal file
271
src/game/editor/editor_trackers.h
Normal file
|
@ -0,0 +1,271 @@
|
|||
#ifndef GAME_EDITOR_EDITOR_TRACKERS_H
|
||||
#define GAME_EDITOR_EDITOR_TRACKERS_H
|
||||
|
||||
#include <game/editor/mapitems.h>
|
||||
#include <game/editor/mapitems/layer_quads.h>
|
||||
#include <game/mapitems.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class CEditor;
|
||||
class CLayerTiles;
|
||||
class CLayerGroup;
|
||||
class CLayerSounds;
|
||||
struct CSoundSource;
|
||||
|
||||
class CQuadEditTracker
|
||||
{
|
||||
public:
|
||||
CQuadEditTracker();
|
||||
~CQuadEditTracker();
|
||||
|
||||
void BeginQuadTrack(const std::shared_ptr<CLayerQuads> &pLayer, const std::vector<int> &vSelectedQuads);
|
||||
void EndQuadTrack();
|
||||
|
||||
void BeginQuadPropTrack(const std::shared_ptr<CLayerQuads> &pLayer, const std::vector<int> &vSelectedQuads, EQuadProp Prop);
|
||||
void EndQuadPropTrack(EQuadProp Prop);
|
||||
|
||||
void BeginQuadPointPropTrack(const std::shared_ptr<CLayerQuads> &pLayer, const std::vector<int> &vSelectedQuads, int SelectedQuadPoints);
|
||||
void AddQuadPointPropTrack(EQuadPointProp Prop);
|
||||
void EndQuadPointPropTrack(EQuadPointProp Prop);
|
||||
void EndQuadPointPropTrackAll();
|
||||
|
||||
CEditor *m_pEditor;
|
||||
|
||||
private:
|
||||
std::vector<int> m_vSelectedQuads;
|
||||
int m_SelectedQuadPoints;
|
||||
std::map<int, std::vector<CPoint>> m_InitalPoints;
|
||||
|
||||
bool m_Tracking = false;
|
||||
std::shared_ptr<CLayerQuads> m_pLayer;
|
||||
|
||||
EQuadProp m_TrackedProp;
|
||||
std::vector<EQuadPointProp> m_vTrackedProps;
|
||||
std::map<int, int> m_PreviousValues;
|
||||
std::map<int, std::vector<std::map<EQuadPointProp, int>>> m_PreviousValuesPoint;
|
||||
};
|
||||
|
||||
class CEditorPropTracker
|
||||
{
|
||||
public:
|
||||
CEditorPropTracker() = default;
|
||||
|
||||
void BeginPropTrack(int Prop, int Value);
|
||||
void StopPropTrack(int Prop, int Value);
|
||||
inline void Reset() { m_TrackedProp = -1; }
|
||||
|
||||
CEditor *m_pEditor;
|
||||
int m_PreviousValue;
|
||||
int m_CurrentValue;
|
||||
|
||||
private:
|
||||
int m_TrackedProp = -1;
|
||||
};
|
||||
|
||||
enum class EEnvelopeEditorOp
|
||||
{
|
||||
OP_NONE = 0,
|
||||
OP_SELECT,
|
||||
OP_DRAG_POINT,
|
||||
OP_DRAG_POINT_X,
|
||||
OP_DRAG_POINT_Y,
|
||||
OP_CONTEXT_MENU,
|
||||
OP_BOX_SELECT,
|
||||
OP_SCALE
|
||||
};
|
||||
|
||||
class CEnvelopeEditorOperationTracker
|
||||
{
|
||||
public:
|
||||
CEnvelopeEditorOperationTracker() = default;
|
||||
|
||||
void Begin(EEnvelopeEditorOp Operation);
|
||||
void Stop(bool Switch = true);
|
||||
inline void Reset() { m_TrackedOp = EEnvelopeEditorOp::OP_NONE; }
|
||||
|
||||
CEditor *m_pEditor;
|
||||
|
||||
private:
|
||||
EEnvelopeEditorOp m_TrackedOp = EEnvelopeEditorOp::OP_NONE;
|
||||
|
||||
struct SPointData
|
||||
{
|
||||
bool m_Used;
|
||||
int m_Time;
|
||||
std::map<int, int> m_Values;
|
||||
};
|
||||
|
||||
std::map<int, SPointData> m_SavedValues;
|
||||
|
||||
void HandlePointDragStart();
|
||||
void HandlePointDragEnd(bool Switch);
|
||||
};
|
||||
|
||||
template<typename T, typename E>
|
||||
class CPropTracker
|
||||
{
|
||||
public:
|
||||
CPropTracker(CEditor *pEditor) :
|
||||
m_pEditor(pEditor), m_OriginalValue(0) {}
|
||||
CEditor *m_pEditor;
|
||||
|
||||
void Begin(T *pObject, E Prop, EEditState State)
|
||||
{
|
||||
if(Prop == static_cast<E>(-1))
|
||||
return;
|
||||
m_pObject = pObject;
|
||||
int Value = PropToValue(Prop);
|
||||
if(StartChecker(Prop, State, Value))
|
||||
{
|
||||
m_OriginalValue = Value;
|
||||
OnStart(Prop);
|
||||
}
|
||||
}
|
||||
|
||||
void End(E Prop, EEditState State)
|
||||
{
|
||||
if(Prop == static_cast<E>(-1))
|
||||
return;
|
||||
int Value = PropToValue(Prop);
|
||||
if(EndChecker(Prop, State, Value))
|
||||
{
|
||||
OnEnd(Prop, Value);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void OnStart(E Prop) {}
|
||||
virtual void OnEnd(E Prop, int Value) {}
|
||||
virtual int PropToValue(E Prop) { return 0; }
|
||||
virtual bool StartChecker(E Prop, EEditState State, int Value)
|
||||
{
|
||||
return State == EEditState::START || State == EEditState::ONE_GO;
|
||||
}
|
||||
virtual bool EndChecker(E Prop, EEditState State, int Value)
|
||||
{
|
||||
return (State == EEditState::END || State == EEditState::ONE_GO) && (Value != m_OriginalValue);
|
||||
}
|
||||
|
||||
int m_OriginalValue;
|
||||
T *m_pObject;
|
||||
};
|
||||
|
||||
class CLayerPropTracker : public CPropTracker<CLayer, ELayerProp>
|
||||
{
|
||||
public:
|
||||
CLayerPropTracker(CEditor *pEditor) :
|
||||
CPropTracker<CLayer, ELayerProp>(pEditor){};
|
||||
|
||||
protected:
|
||||
void OnEnd(ELayerProp Prop, int Value) override;
|
||||
int PropToValue(ELayerProp Prop) override;
|
||||
};
|
||||
|
||||
class CLayerTilesPropTracker : public CPropTracker<CLayerTiles, ETilesProp>
|
||||
{
|
||||
public:
|
||||
CLayerTilesPropTracker(CEditor *pEditor) :
|
||||
CPropTracker<CLayerTiles, ETilesProp>(pEditor){};
|
||||
|
||||
protected:
|
||||
void OnStart(ETilesProp Prop) override;
|
||||
void OnEnd(ETilesProp Prop, int Value) override;
|
||||
bool EndChecker(ETilesProp Prop, EEditState State, int Value) override;
|
||||
|
||||
int PropToValue(ETilesProp Prop) override;
|
||||
|
||||
private:
|
||||
std::map<int, std::shared_ptr<CLayer>> m_SavedLayers;
|
||||
};
|
||||
|
||||
class CLayerTilesCommonPropTracker : public CPropTracker<CLayerTiles, ETilesCommonProp>
|
||||
{
|
||||
public:
|
||||
CLayerTilesCommonPropTracker(CEditor *pEditor) :
|
||||
CPropTracker<CLayerTiles, ETilesCommonProp>(pEditor){};
|
||||
|
||||
protected:
|
||||
void OnStart(ETilesCommonProp Prop) override;
|
||||
void OnEnd(ETilesCommonProp Prop, int Value) override;
|
||||
bool EndChecker(ETilesCommonProp Prop, EEditState State, int Value) override;
|
||||
|
||||
int PropToValue(ETilesCommonProp Prop) override;
|
||||
|
||||
private:
|
||||
std::map<std::shared_ptr<CLayerTiles>, std::map<int, std::shared_ptr<CLayer>>> m_SavedLayers;
|
||||
|
||||
public:
|
||||
std::vector<std::shared_ptr<CLayerTiles>> m_vpLayers;
|
||||
std::vector<int> m_vLayerIndices;
|
||||
};
|
||||
|
||||
class CLayerGroupPropTracker : public CPropTracker<CLayerGroup, EGroupProp>
|
||||
{
|
||||
public:
|
||||
CLayerGroupPropTracker(CEditor *pEditor) :
|
||||
CPropTracker<CLayerGroup, EGroupProp>(pEditor){};
|
||||
|
||||
protected:
|
||||
void OnEnd(EGroupProp Prop, int Value) override;
|
||||
int PropToValue(EGroupProp Prop) override;
|
||||
};
|
||||
|
||||
class CLayerQuadsPropTracker : public CPropTracker<CLayerQuads, ELayerQuadsProp>
|
||||
{
|
||||
public:
|
||||
CLayerQuadsPropTracker(CEditor *pEditor) :
|
||||
CPropTracker<CLayerQuads, ELayerQuadsProp>(pEditor){};
|
||||
|
||||
protected:
|
||||
void OnEnd(ELayerQuadsProp Prop, int Value) override;
|
||||
int PropToValue(ELayerQuadsProp Prop) override;
|
||||
};
|
||||
|
||||
class CLayerSoundsPropTracker : public CPropTracker<CLayerSounds, ELayerSoundsProp>
|
||||
{
|
||||
public:
|
||||
CLayerSoundsPropTracker(CEditor *pEditor) :
|
||||
CPropTracker<CLayerSounds, ELayerSoundsProp>(pEditor){};
|
||||
|
||||
protected:
|
||||
void OnEnd(ELayerSoundsProp Prop, int Value) override;
|
||||
int PropToValue(ELayerSoundsProp Prop) override;
|
||||
};
|
||||
|
||||
class CSoundSourcePropTracker : public CPropTracker<CSoundSource, ESoundProp>
|
||||
{
|
||||
public:
|
||||
CSoundSourcePropTracker(CEditor *pEditor) :
|
||||
CPropTracker<CSoundSource, ESoundProp>(pEditor) {}
|
||||
|
||||
protected:
|
||||
void OnEnd(ESoundProp Prop, int Value) override;
|
||||
int PropToValue(ESoundProp Prop) override;
|
||||
};
|
||||
|
||||
class CSoundSourceRectShapePropTracker : public CPropTracker<CSoundSource, ERectangleShapeProp>
|
||||
{
|
||||
public:
|
||||
CSoundSourceRectShapePropTracker(CEditor *pEditor) :
|
||||
CPropTracker<CSoundSource, ERectangleShapeProp>(pEditor) {}
|
||||
|
||||
protected:
|
||||
void OnEnd(ERectangleShapeProp Prop, int Value) override;
|
||||
int PropToValue(ERectangleShapeProp Prop) override;
|
||||
};
|
||||
|
||||
class CSoundSourceCircleShapePropTracker : public CPropTracker<CSoundSource, ECircleShapeProp>
|
||||
{
|
||||
public:
|
||||
CSoundSourceCircleShapePropTracker(CEditor *pEditor) :
|
||||
CPropTracker<CSoundSource, ECircleShapeProp>(pEditor) {}
|
||||
|
||||
protected:
|
||||
void OnEnd(ECircleShapeProp Prop, int Value) override;
|
||||
int PropToValue(ECircleShapeProp Prop) override;
|
||||
};
|
||||
|
||||
#endif
|
125
src/game/editor/mapitems.h
Normal file
125
src/game/editor/mapitems.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
#ifndef GAME_EDITOR_MAPITEMS_H
|
||||
#define GAME_EDITOR_MAPITEMS_H
|
||||
|
||||
enum class EQuadProp
|
||||
{
|
||||
PROP_NONE = -1,
|
||||
PROP_ORDER,
|
||||
PROP_POS_X,
|
||||
PROP_POS_Y,
|
||||
PROP_POS_ENV,
|
||||
PROP_POS_ENV_OFFSET,
|
||||
PROP_COLOR_ENV,
|
||||
PROP_COLOR_ENV_OFFSET,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
enum class EQuadPointProp
|
||||
{
|
||||
PROP_NONE = -1,
|
||||
PROP_POS_X,
|
||||
PROP_POS_Y,
|
||||
PROP_COLOR,
|
||||
PROP_TEX_U,
|
||||
PROP_TEX_V,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
enum class ESoundProp
|
||||
{
|
||||
PROP_NONE = -1,
|
||||
PROP_POS_X,
|
||||
PROP_POS_Y,
|
||||
PROP_LOOP,
|
||||
PROP_PAN,
|
||||
PROP_TIME_DELAY,
|
||||
PROP_FALLOFF,
|
||||
PROP_POS_ENV,
|
||||
PROP_POS_ENV_OFFSET,
|
||||
PROP_SOUND_ENV,
|
||||
PROP_SOUND_ENV_OFFSET,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
enum class ERectangleShapeProp
|
||||
{
|
||||
PROP_NONE = -1,
|
||||
PROP_RECTANGLE_WIDTH,
|
||||
PROP_RECTANGLE_HEIGHT,
|
||||
NUM_RECTANGLE_PROPS,
|
||||
};
|
||||
|
||||
enum class ECircleShapeProp
|
||||
{
|
||||
PROP_NONE = -1,
|
||||
PROP_CIRCLE_RADIUS,
|
||||
NUM_CIRCLE_PROPS,
|
||||
};
|
||||
|
||||
enum class ELayerProp
|
||||
{
|
||||
PROP_NONE = -1,
|
||||
PROP_GROUP,
|
||||
PROP_ORDER,
|
||||
PROP_HQ,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
enum class ETilesProp
|
||||
{
|
||||
PROP_NONE = -1,
|
||||
PROP_WIDTH,
|
||||
PROP_HEIGHT,
|
||||
PROP_SHIFT,
|
||||
PROP_SHIFT_BY,
|
||||
PROP_IMAGE,
|
||||
PROP_COLOR,
|
||||
PROP_COLOR_ENV,
|
||||
PROP_COLOR_ENV_OFFSET,
|
||||
PROP_AUTOMAPPER,
|
||||
PROP_SEED,
|
||||
NUM_PROPS
|
||||
};
|
||||
|
||||
enum class ETilesCommonProp
|
||||
{
|
||||
PROP_NONE = -1,
|
||||
PROP_WIDTH,
|
||||
PROP_HEIGHT,
|
||||
PROP_SHIFT,
|
||||
PROP_SHIFT_BY,
|
||||
PROP_COLOR,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
enum class EGroupProp
|
||||
{
|
||||
PROP_NONE = -1,
|
||||
PROP_ORDER,
|
||||
PROP_POS_X,
|
||||
PROP_POS_Y,
|
||||
PROP_PARA_X,
|
||||
PROP_PARA_Y,
|
||||
PROP_USE_CLIPPING,
|
||||
PROP_CLIP_X,
|
||||
PROP_CLIP_Y,
|
||||
PROP_CLIP_W,
|
||||
PROP_CLIP_H,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
enum class ELayerQuadsProp
|
||||
{
|
||||
PROP_NONE = -1,
|
||||
PROP_IMAGE,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
enum class ELayerSoundsProp
|
||||
{
|
||||
PROP_NONE = -1,
|
||||
PROP_SOUND,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
#endif
|
|
@ -25,6 +25,7 @@ public:
|
|||
void AddPoint(int Time, int v0, int v1 = 0, int v2 = 0, int v3 = 0);
|
||||
float EndTime() const;
|
||||
int GetChannels() const;
|
||||
EType Type() const { return m_Type; }
|
||||
|
||||
private:
|
||||
void Resort();
|
||||
|
|
|
@ -62,6 +62,7 @@ public:
|
|||
virtual void ModifySoundIndex(FIndexModifyFunction pfnFunc) {}
|
||||
|
||||
virtual std::shared_ptr<CLayer> Duplicate() const = 0;
|
||||
virtual const char *TypeName() const = 0;
|
||||
|
||||
virtual void GetSize(float *pWidth, float *pHeight)
|
||||
{
|
||||
|
|
|
@ -45,3 +45,8 @@ void CLayerFront::Resize(int NewW, int NewH)
|
|||
if(m_pEditor->m_Map.m_pGameLayer->m_Width != NewW || m_pEditor->m_Map.m_pGameLayer->m_Height != NewH)
|
||||
m_pEditor->m_Map.m_pGameLayer->Resize(NewW, NewH);
|
||||
}
|
||||
|
||||
const char *CLayerFront::TypeName() const
|
||||
{
|
||||
return "front";
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ public:
|
|||
|
||||
void Resize(int NewW, int NewH) override;
|
||||
void SetTile(int x, int y, CTile Tile) override;
|
||||
const char *TypeName() const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -72,3 +72,8 @@ CUI::EPopupMenuFunctionResult CLayerGame::RenderProperties(CUIRect *pToolbox)
|
|||
m_Image = -1;
|
||||
return Result;
|
||||
}
|
||||
|
||||
const char *CLayerGame::TypeName() const
|
||||
{
|
||||
return "game";
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ public:
|
|||
|
||||
CTile GetTile(int x, int y) override;
|
||||
void SetTile(int x, int y, CTile Tile) override;
|
||||
const char *TypeName() const override;
|
||||
|
||||
CUI::EPopupMenuFunctionResult RenderProperties(CUIRect *pToolbox) override;
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "layer_quads.h"
|
||||
|
||||
#include <game/editor/editor.h>
|
||||
#include <game/editor/editor_actions.h>
|
||||
|
||||
#include "image.h"
|
||||
|
||||
|
@ -140,6 +141,7 @@ int CLayerQuads::BrushGrab(std::shared_ptr<CLayerGroup> pBrush, CUIRect Rect)
|
|||
void CLayerQuads::BrushPlace(std::shared_ptr<CLayer> pBrush, float wx, float wy)
|
||||
{
|
||||
std::shared_ptr<CLayerQuads> pQuadLayer = std::static_pointer_cast<CLayerQuads>(pBrush);
|
||||
std::vector<CQuad> vAddedQuads;
|
||||
for(const auto &Quad : pQuadLayer->m_vQuads)
|
||||
{
|
||||
CQuad n = Quad;
|
||||
|
@ -151,7 +153,9 @@ void CLayerQuads::BrushPlace(std::shared_ptr<CLayer> pBrush, float wx, float wy)
|
|||
}
|
||||
|
||||
m_vQuads.push_back(n);
|
||||
vAddedQuads.push_back(n);
|
||||
}
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionQuadPlace>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], vAddedQuads));
|
||||
m_pEditor->m_Map.OnModify();
|
||||
}
|
||||
|
||||
|
@ -219,26 +223,23 @@ void CLayerQuads::GetSize(float *pWidth, float *pHeight)
|
|||
|
||||
CUI::EPopupMenuFunctionResult CLayerQuads::RenderProperties(CUIRect *pToolBox)
|
||||
{
|
||||
enum
|
||||
{
|
||||
PROP_IMAGE = 0,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
CProperty aProps[] = {
|
||||
{"Image", m_Image, PROPTYPE_IMAGE, -1, 0},
|
||||
{nullptr},
|
||||
};
|
||||
|
||||
static int s_aIds[NUM_PROPS] = {0};
|
||||
static int s_aIds[(int)ELayerQuadsProp::NUM_PROPS] = {0};
|
||||
int NewVal = 0;
|
||||
int Prop = m_pEditor->DoProperties(pToolBox, aProps, s_aIds, &NewVal);
|
||||
if(Prop != -1)
|
||||
auto [State, Prop] = m_pEditor->DoPropertiesWithState<ELayerQuadsProp>(pToolBox, aProps, s_aIds, &NewVal);
|
||||
if(Prop != ELayerQuadsProp::PROP_NONE)
|
||||
{
|
||||
m_pEditor->m_Map.OnModify();
|
||||
}
|
||||
|
||||
if(Prop == PROP_IMAGE)
|
||||
static CLayerQuadsPropTracker s_Tracker(m_pEditor);
|
||||
s_Tracker.Begin(this, Prop, State);
|
||||
|
||||
if(Prop == ELayerQuadsProp::PROP_IMAGE)
|
||||
{
|
||||
if(NewVal >= 0)
|
||||
m_Image = NewVal % m_pEditor->m_Map.m_vpImages.size();
|
||||
|
@ -246,6 +247,8 @@ CUI::EPopupMenuFunctionResult CLayerQuads::RenderProperties(CUIRect *pToolBox)
|
|||
m_Image = -1;
|
||||
}
|
||||
|
||||
s_Tracker.End(Prop, State);
|
||||
|
||||
return CUI::POPUP_KEEP_OPEN;
|
||||
}
|
||||
|
||||
|
@ -280,3 +283,8 @@ int CLayerQuads::SwapQuads(int Index0, int Index1)
|
|||
std::swap(m_vQuads[Index0], m_vQuads[Index1]);
|
||||
return Index1;
|
||||
}
|
||||
|
||||
const char *CLayerQuads::TypeName() const
|
||||
{
|
||||
return "quads";
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
|
||||
void GetSize(float *pWidth, float *pHeight) override;
|
||||
std::shared_ptr<CLayer> Duplicate() const override;
|
||||
const char *TypeName() const override;
|
||||
|
||||
int m_Image;
|
||||
std::vector<CQuad> m_vQuads;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "layer_sounds.h"
|
||||
|
||||
#include <game/editor/editor.h>
|
||||
|
||||
#include <game/editor/editor_actions.h>
|
||||
#include <game/generated/client_data.h>
|
||||
|
||||
static const float s_SourceVisualSize = 32.0f;
|
||||
|
@ -171,6 +171,7 @@ int CLayerSounds::BrushGrab(std::shared_ptr<CLayerGroup> pBrush, CUIRect Rect)
|
|||
void CLayerSounds::BrushPlace(std::shared_ptr<CLayer> pBrush, float wx, float wy)
|
||||
{
|
||||
std::shared_ptr<CLayerSounds> pSoundLayer = std::static_pointer_cast<CLayerSounds>(pBrush);
|
||||
std::vector<CSoundSource> vAddedSources;
|
||||
for(const auto &Source : pSoundLayer->m_vSources)
|
||||
{
|
||||
CSoundSource n = Source;
|
||||
|
@ -179,32 +180,31 @@ void CLayerSounds::BrushPlace(std::shared_ptr<CLayer> pBrush, float wx, float wy
|
|||
n.m_Position.y += f2fx(wy);
|
||||
|
||||
m_vSources.push_back(n);
|
||||
vAddedSources.push_back(n);
|
||||
}
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionSoundPlace>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], vAddedSources));
|
||||
m_pEditor->m_Map.OnModify();
|
||||
}
|
||||
|
||||
CUI::EPopupMenuFunctionResult CLayerSounds::RenderProperties(CUIRect *pToolBox)
|
||||
{
|
||||
enum
|
||||
{
|
||||
PROP_SOUND = 0,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
CProperty aProps[] = {
|
||||
{"Sound", m_Sound, PROPTYPE_SOUND, -1, 0},
|
||||
{nullptr},
|
||||
};
|
||||
|
||||
static int s_aIds[NUM_PROPS] = {0};
|
||||
static int s_aIds[(int)ELayerSoundsProp::NUM_PROPS] = {0};
|
||||
int NewVal = 0;
|
||||
int Prop = m_pEditor->DoProperties(pToolBox, aProps, s_aIds, &NewVal);
|
||||
if(Prop != -1)
|
||||
auto [State, Prop] = m_pEditor->DoPropertiesWithState<ELayerSoundsProp>(pToolBox, aProps, s_aIds, &NewVal);
|
||||
if(Prop != ELayerSoundsProp::PROP_NONE)
|
||||
{
|
||||
m_pEditor->m_Map.OnModify();
|
||||
}
|
||||
|
||||
if(Prop == PROP_SOUND)
|
||||
static CLayerSoundsPropTracker s_Tracker(m_pEditor);
|
||||
s_Tracker.Begin(this, Prop, State);
|
||||
|
||||
if(Prop == ELayerSoundsProp::PROP_SOUND)
|
||||
{
|
||||
if(NewVal >= 0)
|
||||
m_Sound = NewVal % m_pEditor->m_Map.m_vpSounds.size();
|
||||
|
@ -212,6 +212,8 @@ CUI::EPopupMenuFunctionResult CLayerSounds::RenderProperties(CUIRect *pToolBox)
|
|||
m_Sound = -1;
|
||||
}
|
||||
|
||||
s_Tracker.End(Prop, State);
|
||||
|
||||
return CUI::POPUP_KEEP_OPEN;
|
||||
}
|
||||
|
||||
|
@ -233,3 +235,8 @@ std::shared_ptr<CLayer> CLayerSounds::Duplicate() const
|
|||
{
|
||||
return std::make_shared<CLayerSounds>(*this);
|
||||
}
|
||||
|
||||
const char *CLayerSounds::TypeName() const
|
||||
{
|
||||
return "sounds";
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ public:
|
|||
void ModifySoundIndex(FIndexModifyFunction pfnFunc) override;
|
||||
|
||||
std::shared_ptr<CLayer> Duplicate() const override;
|
||||
const char *TypeName() const override;
|
||||
|
||||
int m_Sound;
|
||||
std::vector<CSoundSource> m_vSources;
|
||||
|
|
|
@ -12,6 +12,16 @@ CLayerSpeedup::CLayerSpeedup(CEditor *pEditor, int w, int h) :
|
|||
mem_zero(m_pSpeedupTile, (size_t)w * h * sizeof(CSpeedupTile));
|
||||
}
|
||||
|
||||
CLayerSpeedup::CLayerSpeedup(const CLayerSpeedup &Other) :
|
||||
CLayerTiles(Other)
|
||||
{
|
||||
str_copy(m_aName, "Speedup copy");
|
||||
m_Speedup = 1;
|
||||
|
||||
m_pSpeedupTile = new CSpeedupTile[m_Width * m_Height];
|
||||
mem_copy(m_pSpeedupTile, Other.m_pSpeedupTile, (size_t)m_Width * m_Height * sizeof(CSpeedupTile));
|
||||
}
|
||||
|
||||
CLayerSpeedup::~CLayerSpeedup()
|
||||
{
|
||||
delete[] m_pSpeedupTile;
|
||||
|
@ -84,53 +94,78 @@ void CLayerSpeedup::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy
|
|||
if(!Destructive && GetTile(fx, fy).m_Index)
|
||||
continue;
|
||||
|
||||
int Index = fy * m_Width + fx;
|
||||
SSpeedupTileStateChange::SData Previous{
|
||||
m_pSpeedupTile[Index].m_Force,
|
||||
m_pSpeedupTile[Index].m_Angle,
|
||||
m_pSpeedupTile[Index].m_MaxSpeed,
|
||||
m_pSpeedupTile[Index].m_Type,
|
||||
m_pTiles[Index].m_Index};
|
||||
|
||||
if((m_pEditor->m_AllowPlaceUnusedTiles || IsValidSpeedupTile(pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index)) && pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index != TILE_AIR)
|
||||
{
|
||||
if(m_pEditor->m_SpeedupAngle != pSpeedupLayer->m_SpeedupAngle || m_pEditor->m_SpeedupForce != pSpeedupLayer->m_SpeedupForce || m_pEditor->m_SpeedupMaxSpeed != pSpeedupLayer->m_SpeedupMaxSpeed)
|
||||
{
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Force = m_pEditor->m_SpeedupForce;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_MaxSpeed = m_pEditor->m_SpeedupMaxSpeed;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Angle = m_pEditor->m_SpeedupAngle;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Type = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
m_pSpeedupTile[Index].m_Force = m_pEditor->m_SpeedupForce;
|
||||
m_pSpeedupTile[Index].m_MaxSpeed = m_pEditor->m_SpeedupMaxSpeed;
|
||||
m_pSpeedupTile[Index].m_Angle = m_pEditor->m_SpeedupAngle;
|
||||
m_pSpeedupTile[Index].m_Type = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
m_pTiles[Index].m_Index = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
}
|
||||
else if(pSpeedupLayer->m_pSpeedupTile[y * pSpeedupLayer->m_Width + x].m_Force)
|
||||
{
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Force = pSpeedupLayer->m_pSpeedupTile[y * pSpeedupLayer->m_Width + x].m_Force;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Angle = pSpeedupLayer->m_pSpeedupTile[y * pSpeedupLayer->m_Width + x].m_Angle;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_MaxSpeed = pSpeedupLayer->m_pSpeedupTile[y * pSpeedupLayer->m_Width + x].m_MaxSpeed;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Type = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
m_pSpeedupTile[Index].m_Force = pSpeedupLayer->m_pSpeedupTile[y * pSpeedupLayer->m_Width + x].m_Force;
|
||||
m_pSpeedupTile[Index].m_Angle = pSpeedupLayer->m_pSpeedupTile[y * pSpeedupLayer->m_Width + x].m_Angle;
|
||||
m_pSpeedupTile[Index].m_MaxSpeed = pSpeedupLayer->m_pSpeedupTile[y * pSpeedupLayer->m_Width + x].m_MaxSpeed;
|
||||
m_pSpeedupTile[Index].m_Type = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
m_pTiles[Index].m_Index = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
}
|
||||
else if(m_pEditor->m_SpeedupForce)
|
||||
{
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Force = m_pEditor->m_SpeedupForce;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_MaxSpeed = m_pEditor->m_SpeedupMaxSpeed;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Angle = m_pEditor->m_SpeedupAngle;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Type = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
m_pSpeedupTile[Index].m_Force = m_pEditor->m_SpeedupForce;
|
||||
m_pSpeedupTile[Index].m_MaxSpeed = m_pEditor->m_SpeedupMaxSpeed;
|
||||
m_pSpeedupTile[Index].m_Angle = m_pEditor->m_SpeedupAngle;
|
||||
m_pSpeedupTile[Index].m_Type = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
m_pTiles[Index].m_Index = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Force = 0;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_MaxSpeed = 0;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Angle = 0;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Type = 0;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = 0;
|
||||
m_pSpeedupTile[Index].m_Force = 0;
|
||||
m_pSpeedupTile[Index].m_MaxSpeed = 0;
|
||||
m_pSpeedupTile[Index].m_Angle = 0;
|
||||
m_pSpeedupTile[Index].m_Type = 0;
|
||||
m_pTiles[Index].m_Index = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Force = 0;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_MaxSpeed = 0;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Angle = 0;
|
||||
m_pSpeedupTile[fy * m_Width + fx].m_Type = 0;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = 0;
|
||||
m_pSpeedupTile[Index].m_Force = 0;
|
||||
m_pSpeedupTile[Index].m_MaxSpeed = 0;
|
||||
m_pSpeedupTile[Index].m_Angle = 0;
|
||||
m_pSpeedupTile[Index].m_Type = 0;
|
||||
m_pTiles[Index].m_Index = 0;
|
||||
}
|
||||
|
||||
SSpeedupTileStateChange::SData Current{
|
||||
m_pSpeedupTile[Index].m_Force,
|
||||
m_pSpeedupTile[Index].m_Angle,
|
||||
m_pSpeedupTile[Index].m_MaxSpeed,
|
||||
m_pSpeedupTile[Index].m_Type,
|
||||
m_pTiles[Index].m_Index};
|
||||
|
||||
RecordStateChange(fx, fy, Previous, Current);
|
||||
}
|
||||
FlagModified(sx, sy, pSpeedupLayer->m_Width, pSpeedupLayer->m_Height);
|
||||
}
|
||||
|
||||
void CLayerSpeedup::RecordStateChange(int x, int y, SSpeedupTileStateChange::SData Previous, SSpeedupTileStateChange::SData Current)
|
||||
{
|
||||
if(!m_History[y][x].m_Changed)
|
||||
m_History[y][x] = SSpeedupTileStateChange{true, Previous, Current};
|
||||
else
|
||||
m_History[y][x].m_Current = Current;
|
||||
}
|
||||
|
||||
void CLayerSpeedup::BrushFlipX()
|
||||
{
|
||||
CLayerTiles::BrushFlipX();
|
||||
|
@ -211,6 +246,13 @@ void CLayerSpeedup::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CU
|
|||
const int SrcIndex = Empty ? 0 : (y * pLt->m_Width + x % pLt->m_Width) % (pLt->m_Width * pLt->m_Height);
|
||||
const int TgtIndex = fy * m_Width + fx;
|
||||
|
||||
SSpeedupTileStateChange::SData Previous{
|
||||
m_pSpeedupTile[TgtIndex].m_Force,
|
||||
m_pSpeedupTile[TgtIndex].m_Angle,
|
||||
m_pSpeedupTile[TgtIndex].m_MaxSpeed,
|
||||
m_pSpeedupTile[TgtIndex].m_Type,
|
||||
m_pTiles[TgtIndex].m_Index};
|
||||
|
||||
if(Empty || (!m_pEditor->m_AllowPlaceUnusedTiles && !IsValidSpeedupTile((pLt->m_pTiles[SrcIndex]).m_Index))) // no speed up tile chosen: reset
|
||||
{
|
||||
m_pTiles[TgtIndex].m_Index = 0;
|
||||
|
@ -240,7 +282,26 @@ void CLayerSpeedup::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CU
|
|||
m_pSpeedupTile[TgtIndex].m_MaxSpeed = pLt->m_pSpeedupTile[SrcIndex].m_MaxSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
SSpeedupTileStateChange::SData Current{
|
||||
m_pSpeedupTile[TgtIndex].m_Force,
|
||||
m_pSpeedupTile[TgtIndex].m_Angle,
|
||||
m_pSpeedupTile[TgtIndex].m_MaxSpeed,
|
||||
m_pSpeedupTile[TgtIndex].m_Type,
|
||||
m_pTiles[TgtIndex].m_Index};
|
||||
|
||||
RecordStateChange(fx, fy, Previous, Current);
|
||||
}
|
||||
}
|
||||
FlagModified(sx, sy, w, h);
|
||||
}
|
||||
|
||||
std::shared_ptr<CLayer> CLayerSpeedup::Duplicate() const
|
||||
{
|
||||
return std::make_shared<CLayerSpeedup>(*this);
|
||||
}
|
||||
|
||||
const char *CLayerSpeedup::TypeName() const
|
||||
{
|
||||
return "speedup";
|
||||
}
|
||||
|
|
|
@ -3,10 +3,24 @@
|
|||
|
||||
#include "layer_tiles.h"
|
||||
|
||||
struct SSpeedupTileStateChange
|
||||
{
|
||||
bool m_Changed;
|
||||
struct SData
|
||||
{
|
||||
int m_Force;
|
||||
int m_Angle;
|
||||
int m_MaxSpeed;
|
||||
int m_Type;
|
||||
int m_Index;
|
||||
} m_Previous, m_Current;
|
||||
};
|
||||
|
||||
class CLayerSpeedup : public CLayerTiles
|
||||
{
|
||||
public:
|
||||
CLayerSpeedup(CEditor *pEditor, int w, int h);
|
||||
CLayerSpeedup(const CLayerSpeedup &Other);
|
||||
~CLayerSpeedup();
|
||||
|
||||
CSpeedupTile *m_pSpeedupTile;
|
||||
|
@ -22,6 +36,19 @@ public:
|
|||
void BrushFlipY() override;
|
||||
void BrushRotate(float Amount) override;
|
||||
void FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRect Rect) override;
|
||||
|
||||
EditorTileStateChangeHistory<SSpeedupTileStateChange> m_History;
|
||||
void ClearHistory() override
|
||||
{
|
||||
CLayerTiles::ClearHistory();
|
||||
m_History.clear();
|
||||
}
|
||||
|
||||
std::shared_ptr<CLayer> Duplicate() const override;
|
||||
const char *TypeName() const override;
|
||||
|
||||
private:
|
||||
void RecordStateChange(int x, int y, SSpeedupTileStateChange::SData Previous, SSpeedupTileStateChange::SData Current);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,6 +12,16 @@ CLayerSwitch::CLayerSwitch(CEditor *pEditor, int w, int h) :
|
|||
mem_zero(m_pSwitchTile, (size_t)w * h * sizeof(CSwitchTile));
|
||||
}
|
||||
|
||||
CLayerSwitch::CLayerSwitch(const CLayerSwitch &Other) :
|
||||
CLayerTiles(Other)
|
||||
{
|
||||
str_copy(m_aName, "Switch copy");
|
||||
m_Switch = 1;
|
||||
|
||||
m_pSwitchTile = new CSwitchTile[m_Width * m_Height];
|
||||
mem_copy(m_pSwitchTile, Other.m_pSwitchTile, (size_t)m_Width * m_Height * sizeof(CSwitchTile));
|
||||
}
|
||||
|
||||
CLayerSwitch::~CLayerSwitch()
|
||||
{
|
||||
delete[] m_pSwitchTile;
|
||||
|
@ -83,54 +93,79 @@ void CLayerSwitch::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy)
|
|||
if(!Destructive && GetTile(fx, fy).m_Index)
|
||||
continue;
|
||||
|
||||
int Index = fy * m_Width + fx;
|
||||
SSwitchTileStateChange::SData Previous{
|
||||
m_pSwitchTile[Index].m_Number,
|
||||
m_pSwitchTile[Index].m_Type,
|
||||
m_pSwitchTile[Index].m_Flags,
|
||||
m_pSwitchTile[Index].m_Delay,
|
||||
m_pTiles[Index].m_Index};
|
||||
|
||||
if((m_pEditor->m_AllowPlaceUnusedTiles || IsValidSwitchTile(pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index)) && pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index != TILE_AIR)
|
||||
{
|
||||
if(m_pEditor->m_SwitchNum != pSwitchLayer->m_SwitchNumber || m_pEditor->m_SwitchDelay != pSwitchLayer->m_SwitchDelay)
|
||||
{
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Number = m_pEditor->m_SwitchNum;
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Delay = m_pEditor->m_SwitchDelay;
|
||||
m_pSwitchTile[Index].m_Number = m_pEditor->m_SwitchNum;
|
||||
m_pSwitchTile[Index].m_Delay = m_pEditor->m_SwitchDelay;
|
||||
}
|
||||
else if(pSwitchLayer->m_pSwitchTile[y * pSwitchLayer->m_Width + x].m_Number)
|
||||
{
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Number = pSwitchLayer->m_pSwitchTile[y * pSwitchLayer->m_Width + x].m_Number;
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Delay = pSwitchLayer->m_pSwitchTile[y * pSwitchLayer->m_Width + x].m_Delay;
|
||||
m_pSwitchTile[Index].m_Number = pSwitchLayer->m_pSwitchTile[y * pSwitchLayer->m_Width + x].m_Number;
|
||||
m_pSwitchTile[Index].m_Delay = pSwitchLayer->m_pSwitchTile[y * pSwitchLayer->m_Width + x].m_Delay;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Number = m_pEditor->m_SwitchNum;
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Delay = m_pEditor->m_SwitchDelay;
|
||||
m_pSwitchTile[Index].m_Number = m_pEditor->m_SwitchNum;
|
||||
m_pSwitchTile[Index].m_Delay = m_pEditor->m_SwitchDelay;
|
||||
}
|
||||
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Type = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index;
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Flags = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Flags;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index;
|
||||
m_pTiles[fy * m_Width + fx].m_Flags = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Flags;
|
||||
m_pSwitchTile[Index].m_Type = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index;
|
||||
m_pSwitchTile[Index].m_Flags = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Flags;
|
||||
m_pTiles[Index].m_Index = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index;
|
||||
m_pTiles[Index].m_Flags = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Flags;
|
||||
|
||||
if(!IsSwitchTileFlagsUsed(pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index))
|
||||
{
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Flags = 0;
|
||||
m_pSwitchTile[Index].m_Flags = 0;
|
||||
}
|
||||
if(!IsSwitchTileNumberUsed(pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index))
|
||||
{
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Number = 0;
|
||||
m_pSwitchTile[Index].m_Number = 0;
|
||||
}
|
||||
if(!IsSwitchTileDelayUsed(pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index))
|
||||
{
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Delay = 0;
|
||||
m_pSwitchTile[Index].m_Delay = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Number = 0;
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Type = 0;
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Flags = 0;
|
||||
m_pSwitchTile[fy * m_Width + fx].m_Delay = 0;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = 0;
|
||||
m_pSwitchTile[Index].m_Number = 0;
|
||||
m_pSwitchTile[Index].m_Type = 0;
|
||||
m_pSwitchTile[Index].m_Flags = 0;
|
||||
m_pSwitchTile[Index].m_Delay = 0;
|
||||
m_pTiles[Index].m_Index = 0;
|
||||
}
|
||||
|
||||
SSwitchTileStateChange::SData Current{
|
||||
m_pSwitchTile[Index].m_Number,
|
||||
m_pSwitchTile[Index].m_Type,
|
||||
m_pSwitchTile[Index].m_Flags,
|
||||
m_pSwitchTile[Index].m_Delay,
|
||||
m_pTiles[Index].m_Index};
|
||||
|
||||
RecordStateChange(fx, fy, Previous, Current);
|
||||
}
|
||||
FlagModified(sx, sy, pSwitchLayer->m_Width, pSwitchLayer->m_Height);
|
||||
}
|
||||
|
||||
void CLayerSwitch::RecordStateChange(int x, int y, SSwitchTileStateChange::SData Previous, SSwitchTileStateChange::SData Current)
|
||||
{
|
||||
if(!m_History[y][x].m_Changed)
|
||||
m_History[y][x] = SSwitchTileStateChange{true, Previous, Current};
|
||||
else
|
||||
m_History[y][x].m_Current = Current;
|
||||
}
|
||||
|
||||
void CLayerSwitch::BrushFlipX()
|
||||
{
|
||||
CLayerTiles::BrushFlipX();
|
||||
|
@ -217,6 +252,13 @@ void CLayerSwitch::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUI
|
|||
const int SrcIndex = Empty ? 0 : (y * pLt->m_Width + x % pLt->m_Width) % (pLt->m_Width * pLt->m_Height);
|
||||
const int TgtIndex = fy * m_Width + fx;
|
||||
|
||||
SSwitchTileStateChange::SData Previous{
|
||||
m_pSwitchTile[TgtIndex].m_Number,
|
||||
m_pSwitchTile[TgtIndex].m_Type,
|
||||
m_pSwitchTile[TgtIndex].m_Flags,
|
||||
m_pSwitchTile[TgtIndex].m_Delay,
|
||||
m_pTiles[TgtIndex].m_Index};
|
||||
|
||||
if(Empty || (!m_pEditor->m_AllowPlaceUnusedTiles && !IsValidSwitchTile((pLt->m_pTiles[SrcIndex]).m_Index)))
|
||||
{
|
||||
m_pTiles[TgtIndex].m_Index = 0;
|
||||
|
@ -250,6 +292,15 @@ void CLayerSwitch::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUI
|
|||
m_pSwitchTile[TgtIndex].m_Flags = pLt->m_pSwitchTile[SrcIndex].m_Flags;
|
||||
}
|
||||
}
|
||||
|
||||
SSwitchTileStateChange::SData Current{
|
||||
m_pSwitchTile[TgtIndex].m_Number,
|
||||
m_pSwitchTile[TgtIndex].m_Type,
|
||||
m_pSwitchTile[TgtIndex].m_Flags,
|
||||
m_pSwitchTile[TgtIndex].m_Delay,
|
||||
m_pTiles[TgtIndex].m_Index};
|
||||
|
||||
RecordStateChange(fx, fy, Previous, Current);
|
||||
}
|
||||
}
|
||||
FlagModified(sx, sy, w, h);
|
||||
|
@ -270,3 +321,13 @@ bool CLayerSwitch::ContainsElementWithId(int Id)
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<CLayer> CLayerSwitch::Duplicate() const
|
||||
{
|
||||
return std::make_shared<CLayerSwitch>(*this);
|
||||
}
|
||||
|
||||
const char *CLayerSwitch::TypeName() const
|
||||
{
|
||||
return "switch";
|
||||
}
|
||||
|
|
|
@ -3,10 +3,24 @@
|
|||
|
||||
#include "layer_tiles.h"
|
||||
|
||||
struct SSwitchTileStateChange
|
||||
{
|
||||
bool m_Changed;
|
||||
struct SData
|
||||
{
|
||||
int m_Number;
|
||||
int m_Type;
|
||||
int m_Flags;
|
||||
int m_Delay;
|
||||
int m_Index;
|
||||
} m_Previous, m_Current;
|
||||
};
|
||||
|
||||
class CLayerSwitch : public CLayerTiles
|
||||
{
|
||||
public:
|
||||
CLayerSwitch(CEditor *pEditor, int w, int h);
|
||||
CLayerSwitch(const CLayerSwitch &Other);
|
||||
~CLayerSwitch();
|
||||
|
||||
CSwitchTile *m_pSwitchTile;
|
||||
|
@ -22,6 +36,19 @@ public:
|
|||
void BrushRotate(float Amount) override;
|
||||
void FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRect Rect) override;
|
||||
virtual bool ContainsElementWithId(int Id);
|
||||
|
||||
EditorTileStateChangeHistory<SSwitchTileStateChange> m_History;
|
||||
inline void ClearHistory() override
|
||||
{
|
||||
CLayerTiles::ClearHistory();
|
||||
m_History.clear();
|
||||
}
|
||||
|
||||
std::shared_ptr<CLayer> Duplicate() const override;
|
||||
const char *TypeName() const override;
|
||||
|
||||
private:
|
||||
void RecordStateChange(int x, int y, SSwitchTileStateChange::SData Previous, SSwitchTileStateChange::SData Current);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,6 +12,16 @@ CLayerTele::CLayerTele(CEditor *pEditor, int w, int h) :
|
|||
mem_zero(m_pTeleTile, (size_t)w * h * sizeof(CTeleTile));
|
||||
}
|
||||
|
||||
CLayerTele::CLayerTele(const CLayerTele &Other) :
|
||||
CLayerTiles(Other)
|
||||
{
|
||||
str_copy(m_aName, "Tele copy");
|
||||
m_Tele = 1;
|
||||
|
||||
m_pTeleTile = new CTeleTile[m_Width * m_Height];
|
||||
mem_copy(m_pTeleTile, Other.m_pTeleTile, (size_t)m_Width * m_Height * sizeof(CTeleTile));
|
||||
}
|
||||
|
||||
CLayerTele::~CLayerTele()
|
||||
{
|
||||
delete[] m_pTeleTile;
|
||||
|
@ -80,48 +90,80 @@ void CLayerTele::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy)
|
|||
if(!Destructive && GetTile(fx, fy).m_Index)
|
||||
continue;
|
||||
|
||||
int Index = fy * m_Width + fx;
|
||||
STeleTileStateChange::SData Previous{
|
||||
m_pTeleTile[Index].m_Number,
|
||||
m_pTeleTile[Index].m_Type,
|
||||
m_pTiles[Index].m_Index};
|
||||
|
||||
if((m_pEditor->m_AllowPlaceUnusedTiles || IsValidTeleTile(pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index)) && pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index != TILE_AIR)
|
||||
{
|
||||
if(!IsTeleTileNumberUsed(pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index))
|
||||
{
|
||||
// Tele tile number is unused. Set a known value which is not 0,
|
||||
// as tiles with number 0 would be ignored by previous versions.
|
||||
m_pTeleTile[fy * m_Width + fx].m_Number = 255;
|
||||
m_pTeleTile[Index].m_Number = 255;
|
||||
}
|
||||
else if(m_pEditor->m_TeleNumber != pTeleLayer->m_TeleNum)
|
||||
{
|
||||
m_pTeleTile[fy * m_Width + fx].m_Number = m_pEditor->m_TeleNumber;
|
||||
m_pTeleTile[Index].m_Number = m_pEditor->m_TeleNumber;
|
||||
}
|
||||
else if(pTeleLayer->m_pTeleTile[y * pTeleLayer->m_Width + x].m_Number)
|
||||
{
|
||||
m_pTeleTile[fy * m_Width + fx].m_Number = pTeleLayer->m_pTeleTile[y * pTeleLayer->m_Width + x].m_Number;
|
||||
m_pTeleTile[Index].m_Number = pTeleLayer->m_pTeleTile[y * pTeleLayer->m_Width + x].m_Number;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!m_pEditor->m_TeleNumber)
|
||||
{
|
||||
m_pTeleTile[fy * m_Width + fx].m_Number = 0;
|
||||
m_pTeleTile[fy * m_Width + fx].m_Type = 0;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = 0;
|
||||
m_pTeleTile[Index].m_Number = 0;
|
||||
m_pTeleTile[Index].m_Type = 0;
|
||||
m_pTiles[Index].m_Index = 0;
|
||||
|
||||
STeleTileStateChange::SData Current{
|
||||
m_pTeleTile[Index].m_Number,
|
||||
m_pTeleTile[Index].m_Type,
|
||||
m_pTiles[Index].m_Index};
|
||||
|
||||
RecordStateChange(fx, fy, Previous, Current);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
m_pTeleTile[fy * m_Width + fx].m_Number = m_pEditor->m_TeleNumber;
|
||||
{
|
||||
m_pTeleTile[Index].m_Number = m_pEditor->m_TeleNumber;
|
||||
}
|
||||
}
|
||||
|
||||
m_pTeleTile[fy * m_Width + fx].m_Type = pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index;
|
||||
m_pTeleTile[Index].m_Type = pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index;
|
||||
m_pTiles[Index].m_Index = pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pTeleTile[fy * m_Width + fx].m_Number = 0;
|
||||
m_pTeleTile[fy * m_Width + fx].m_Type = 0;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = 0;
|
||||
m_pTeleTile[Index].m_Number = 0;
|
||||
m_pTeleTile[Index].m_Type = 0;
|
||||
m_pTiles[Index].m_Index = 0;
|
||||
}
|
||||
|
||||
STeleTileStateChange::SData Current{
|
||||
m_pTeleTile[Index].m_Number,
|
||||
m_pTeleTile[Index].m_Type,
|
||||
m_pTiles[Index].m_Index};
|
||||
|
||||
RecordStateChange(fx, fy, Previous, Current);
|
||||
}
|
||||
FlagModified(sx, sy, pTeleLayer->m_Width, pTeleLayer->m_Height);
|
||||
}
|
||||
|
||||
void CLayerTele::RecordStateChange(int x, int y, STeleTileStateChange::SData Previous, STeleTileStateChange::SData Current)
|
||||
{
|
||||
if(!m_History[y][x].m_Changed)
|
||||
m_History[y][x] = STeleTileStateChange{true, Previous, Current};
|
||||
else
|
||||
{
|
||||
m_History[y][x].m_Current = Current;
|
||||
}
|
||||
}
|
||||
|
||||
void CLayerTele::BrushFlipX()
|
||||
{
|
||||
CLayerTiles::BrushFlipX();
|
||||
|
@ -202,6 +244,11 @@ void CLayerTele::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRe
|
|||
const int SrcIndex = Empty ? 0 : (y * pLt->m_Width + x % pLt->m_Width) % (pLt->m_Width * pLt->m_Height);
|
||||
const int TgtIndex = fy * m_Width + fx;
|
||||
|
||||
STeleTileStateChange::SData Previous{
|
||||
m_pTeleTile[TgtIndex].m_Number,
|
||||
m_pTeleTile[TgtIndex].m_Type,
|
||||
m_pTiles[TgtIndex].m_Index};
|
||||
|
||||
if(Empty || (!m_pEditor->m_AllowPlaceUnusedTiles && !IsValidTeleTile((pLt->m_pTiles[SrcIndex]).m_Index)))
|
||||
{
|
||||
m_pTiles[TgtIndex].m_Index = 0;
|
||||
|
@ -227,6 +274,13 @@ void CLayerTele::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRe
|
|||
m_pTeleTile[TgtIndex].m_Number = pLt->m_pTeleTile[SrcIndex].m_Number;
|
||||
}
|
||||
}
|
||||
|
||||
STeleTileStateChange::SData Current{
|
||||
m_pTeleTile[TgtIndex].m_Number,
|
||||
m_pTeleTile[TgtIndex].m_Type,
|
||||
m_pTiles[TgtIndex].m_Index};
|
||||
|
||||
RecordStateChange(fx, fy, Previous, Current);
|
||||
}
|
||||
}
|
||||
FlagModified(sx, sy, w, h);
|
||||
|
@ -247,3 +301,13 @@ bool CLayerTele::ContainsElementWithId(int Id)
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<CLayer> CLayerTele::Duplicate() const
|
||||
{
|
||||
return std::make_shared<CLayerTele>(*this);
|
||||
}
|
||||
|
||||
const char *CLayerTele::TypeName() const
|
||||
{
|
||||
return "tele";
|
||||
}
|
||||
|
|
|
@ -3,10 +3,22 @@
|
|||
|
||||
#include "layer_tiles.h"
|
||||
|
||||
struct STeleTileStateChange
|
||||
{
|
||||
bool m_Changed;
|
||||
struct SData
|
||||
{
|
||||
int m_Number;
|
||||
int m_Type;
|
||||
int m_Index;
|
||||
} m_Previous, m_Current;
|
||||
};
|
||||
|
||||
class CLayerTele : public CLayerTiles
|
||||
{
|
||||
public:
|
||||
CLayerTele(CEditor *pEditor, int w, int h);
|
||||
CLayerTele(const CLayerTele &Other);
|
||||
~CLayerTele();
|
||||
|
||||
CTeleTile *m_pTeleTile;
|
||||
|
@ -21,6 +33,21 @@ public:
|
|||
void BrushRotate(float Amount) override;
|
||||
void FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRect Rect) override;
|
||||
virtual bool ContainsElementWithId(int Id);
|
||||
|
||||
EditorTileStateChangeHistory<STeleTileStateChange> m_History;
|
||||
inline void ClearHistory() override
|
||||
{
|
||||
CLayerTiles::ClearHistory();
|
||||
m_History.clear();
|
||||
}
|
||||
|
||||
std::shared_ptr<CLayer> Duplicate() const override;
|
||||
const char *TypeName() const override;
|
||||
|
||||
private:
|
||||
void RecordStateChange(int x, int y, STeleTileStateChange::SData Previous, STeleTileStateChange::SData Current);
|
||||
|
||||
friend class CLayerTiles;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,10 +2,13 @@
|
|||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
#include "layer_tiles.h"
|
||||
|
||||
#include <game/editor/editor.h>
|
||||
|
||||
#include <engine/keys.h>
|
||||
#include <engine/shared/map.h>
|
||||
#include <game/editor/editor.h>
|
||||
#include <game/editor/editor_actions.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
|
||||
#include "image.h"
|
||||
|
||||
|
@ -75,10 +78,25 @@ CTile CLayerTiles::GetTile(int x, int y)
|
|||
}
|
||||
|
||||
void CLayerTiles::SetTile(int x, int y, CTile Tile)
|
||||
{
|
||||
auto CurrentTile = m_pTiles[y * m_Width + x];
|
||||
SetTileIgnoreHistory(x, y, Tile);
|
||||
RecordStateChange(x, y, CurrentTile, Tile);
|
||||
}
|
||||
|
||||
void CLayerTiles::SetTileIgnoreHistory(int x, int y, CTile Tile)
|
||||
{
|
||||
m_pTiles[y * m_Width + x] = Tile;
|
||||
}
|
||||
|
||||
void CLayerTiles::RecordStateChange(int x, int y, CTile Previous, CTile Tile)
|
||||
{
|
||||
if(!m_TilesHistory[y][x].m_Changed)
|
||||
m_TilesHistory[y][x] = STileStateChange{true, Previous, Tile};
|
||||
else
|
||||
m_TilesHistory[y][x].m_Current = Tile;
|
||||
}
|
||||
|
||||
void CLayerTiles::PrepareForSave()
|
||||
{
|
||||
for(int y = 0; y < m_Height; y++)
|
||||
|
@ -579,6 +597,11 @@ std::shared_ptr<CLayer> CLayerTiles::Duplicate() const
|
|||
return std::make_shared<CLayerTiles>(*this);
|
||||
}
|
||||
|
||||
const char *CLayerTiles::TypeName() const
|
||||
{
|
||||
return "tiles";
|
||||
}
|
||||
|
||||
void CLayerTiles::Resize(int NewW, int NewH)
|
||||
{
|
||||
CTile *pNewData = new CTile[NewW * NewH];
|
||||
|
@ -678,7 +701,6 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
static int s_GameTilesButton = 0;
|
||||
if(m_pEditor->DoButton_Editor(&s_GameTilesButton, "Game tiles", 0, &Button, 0, "Constructs game tiles from this layer"))
|
||||
m_pEditor->PopupSelectGametileOpInvoke(m_pEditor->UI()->MouseX(), m_pEditor->UI()->MouseY());
|
||||
|
||||
int Result = m_pEditor->PopupSelectGameTileOpResult();
|
||||
switch(Result)
|
||||
{
|
||||
|
@ -717,17 +739,49 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
const int OffsetX = -pGroup->m_OffsetX / 32;
|
||||
const int OffsetY = -pGroup->m_OffsetY / 32;
|
||||
|
||||
static const char *s_apGametileOpNames[] = {
|
||||
"Air",
|
||||
"Hookable",
|
||||
"Death",
|
||||
"Unhookable",
|
||||
"Hookthrough",
|
||||
"Freeze",
|
||||
"Unfreeze",
|
||||
"Deep Freeze",
|
||||
"Deep Unfreeze",
|
||||
"Blue Check-Tele",
|
||||
"Red Check-Tele",
|
||||
"Live Freeze",
|
||||
"Live Unfreeze",
|
||||
};
|
||||
|
||||
std::vector<std::shared_ptr<IEditorAction>> vpActions;
|
||||
std::shared_ptr<CLayerTiles> pGLayer = m_pEditor->m_Map.m_pGameLayer;
|
||||
int GameLayerIndex = std::find(m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(), m_pEditor->m_Map.m_pGameGroup->m_vpLayers.end(), pGLayer) - m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin();
|
||||
|
||||
if(Result != TILE_TELECHECKIN && Result != TILE_TELECHECKINEVIL)
|
||||
{
|
||||
std::shared_ptr<CLayerTiles> pGLayer = m_pEditor->m_Map.m_pGameLayer;
|
||||
|
||||
if(pGLayer->m_Width < m_Width + OffsetX || pGLayer->m_Height < m_Height + OffsetY)
|
||||
{
|
||||
std::map<int, std::shared_ptr<CLayer>> savedLayers;
|
||||
savedLayers[LAYERTYPE_TILES] = pGLayer->Duplicate();
|
||||
savedLayers[LAYERTYPE_GAME] = savedLayers[LAYERTYPE_TILES];
|
||||
|
||||
int PrevW = pGLayer->m_Width;
|
||||
int PrevH = pGLayer->m_Height;
|
||||
const int NewW = pGLayer->m_Width < m_Width + OffsetX ? m_Width + OffsetX : pGLayer->m_Width;
|
||||
const int NewH = pGLayer->m_Height < m_Height + OffsetY ? m_Height + OffsetY : pGLayer->m_Height;
|
||||
pGLayer->Resize(NewW, NewH);
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW));
|
||||
const std::shared_ptr<CEditorActionEditLayerTilesProp> &Action1 = std::static_pointer_cast<CEditorActionEditLayerTilesProp>(vpActions[vpActions.size() - 1]);
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH));
|
||||
const std::shared_ptr<CEditorActionEditLayerTilesProp> &Action2 = std::static_pointer_cast<CEditorActionEditLayerTilesProp>(vpActions[vpActions.size() - 1]);
|
||||
|
||||
Action1->SetSavedLayers(savedLayers);
|
||||
Action2->SetSavedLayers(savedLayers);
|
||||
}
|
||||
|
||||
int Changes = 0;
|
||||
for(int y = OffsetY < 0 ? -OffsetY : 0; y < m_Height; y++)
|
||||
{
|
||||
for(int x = OffsetX < 0 ? -OffsetX : 0; x < m_Width; x++)
|
||||
|
@ -736,40 +790,111 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
{
|
||||
const CTile ResultTile = {(unsigned char)Result};
|
||||
pGLayer->SetTile(x + OffsetX, y + OffsetY, ResultTile);
|
||||
Changes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vpActions.push_back(std::make_shared<CEditorBrushDrawAction>(m_pEditor, m_pEditor->m_SelectedGroup));
|
||||
char aDisplay[256];
|
||||
str_format(aDisplay, sizeof(aDisplay), "Construct '%s' game tiles (x%d)", s_apGametileOpNames[Result], Changes);
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions, aDisplay, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!m_pEditor->m_Map.m_pTeleLayer)
|
||||
{
|
||||
std::shared_ptr<CLayer> pLayer = std::make_shared<CLayerTele>(m_pEditor, m_Width, m_Height);
|
||||
std::shared_ptr<CLayerTele> pLayer = std::make_shared<CLayerTele>(m_pEditor, m_Width, m_Height);
|
||||
m_pEditor->m_Map.MakeTeleLayer(pLayer);
|
||||
m_pEditor->m_Map.m_pGameGroup->AddLayer(pLayer);
|
||||
|
||||
vpActions.push_back(std::make_shared<CEditorActionAddLayer>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_Map.m_pGameGroup->m_vpLayers.size() - 1));
|
||||
|
||||
if(m_Width != pGLayer->m_Width || m_Height > pGLayer->m_Height)
|
||||
{
|
||||
std::map<int, std::shared_ptr<CLayer>> savedLayers;
|
||||
savedLayers[LAYERTYPE_TILES] = pGLayer->Duplicate();
|
||||
savedLayers[LAYERTYPE_GAME] = savedLayers[LAYERTYPE_TILES];
|
||||
|
||||
int NewW = pGLayer->m_Width;
|
||||
int NewH = pGLayer->m_Height;
|
||||
if(m_Width > pGLayer->m_Width)
|
||||
{
|
||||
NewW = m_Width;
|
||||
}
|
||||
if(m_Height > pGLayer->m_Height)
|
||||
{
|
||||
NewH = m_Height;
|
||||
}
|
||||
|
||||
int PrevW = pGLayer->m_Width;
|
||||
int PrevH = pGLayer->m_Height;
|
||||
pLayer->Resize(NewW, NewH);
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW));
|
||||
const std::shared_ptr<CEditorActionEditLayerTilesProp> &Action1 = std::static_pointer_cast<CEditorActionEditLayerTilesProp>(vpActions[vpActions.size() - 1]);
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH));
|
||||
const std::shared_ptr<CEditorActionEditLayerTilesProp> &Action2 = std::static_pointer_cast<CEditorActionEditLayerTilesProp>(vpActions[vpActions.size() - 1]);
|
||||
|
||||
Action1->SetSavedLayers(savedLayers);
|
||||
Action2->SetSavedLayers(savedLayers);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<CLayerTele> pTLayer = m_pEditor->m_Map.m_pTeleLayer;
|
||||
int TeleLayerIndex = std::find(m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(), m_pEditor->m_Map.m_pGameGroup->m_vpLayers.end(), pTLayer) - m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin();
|
||||
|
||||
if(pTLayer->m_Width < m_Width + OffsetX || pTLayer->m_Height < m_Height + OffsetY)
|
||||
{
|
||||
std::map<int, std::shared_ptr<CLayer>> savedLayers;
|
||||
savedLayers[LAYERTYPE_TILES] = pTLayer->Duplicate();
|
||||
savedLayers[LAYERTYPE_TELE] = savedLayers[LAYERTYPE_TILES];
|
||||
|
||||
int PrevW = pTLayer->m_Width;
|
||||
int PrevH = pTLayer->m_Height;
|
||||
int NewW = pTLayer->m_Width < m_Width + OffsetX ? m_Width + OffsetX : pTLayer->m_Width;
|
||||
int NewH = pTLayer->m_Height < m_Height + OffsetY ? m_Height + OffsetY : pTLayer->m_Height;
|
||||
pTLayer->Resize(NewW, NewH);
|
||||
std::shared_ptr<CEditorActionEditLayerTilesProp> Action1, Action2;
|
||||
vpActions.push_back(Action1 = std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, TeleLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW));
|
||||
vpActions.push_back(Action2 = std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, TeleLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH));
|
||||
|
||||
Action1->SetSavedLayers(savedLayers);
|
||||
Action2->SetSavedLayers(savedLayers);
|
||||
}
|
||||
|
||||
int Changes = 0;
|
||||
for(int y = OffsetY < 0 ? -OffsetY : 0; y < m_Height; y++)
|
||||
{
|
||||
for(int x = OffsetX < 0 ? -OffsetX : 0; x < m_Width; x++)
|
||||
{
|
||||
if(GetTile(x, y).m_Index)
|
||||
{
|
||||
pTLayer->m_pTiles[(y + OffsetY) * pTLayer->m_Width + x + OffsetX].m_Index = TILE_AIR + Result;
|
||||
pTLayer->m_pTeleTile[(y + OffsetY) * pTLayer->m_Width + x + OffsetX].m_Number = 1;
|
||||
pTLayer->m_pTeleTile[(y + OffsetY) * pTLayer->m_Width + x + OffsetX].m_Type = TILE_AIR + Result;
|
||||
auto TileIndex = (y + OffsetY) * pTLayer->m_Width + x + OffsetX;
|
||||
Changes++;
|
||||
|
||||
STeleTileStateChange::SData Previous{
|
||||
pTLayer->m_pTeleTile[TileIndex].m_Number,
|
||||
pTLayer->m_pTeleTile[TileIndex].m_Type,
|
||||
pTLayer->m_pTiles[TileIndex].m_Index};
|
||||
|
||||
pTLayer->m_pTiles[TileIndex].m_Index = TILE_AIR + Result;
|
||||
pTLayer->m_pTeleTile[TileIndex].m_Number = 1;
|
||||
pTLayer->m_pTeleTile[TileIndex].m_Type = TILE_AIR + Result;
|
||||
|
||||
STeleTileStateChange::SData Current{
|
||||
pTLayer->m_pTeleTile[TileIndex].m_Number,
|
||||
pTLayer->m_pTeleTile[TileIndex].m_Type,
|
||||
pTLayer->m_pTiles[TileIndex].m_Index};
|
||||
|
||||
pTLayer->RecordStateChange(x, y, Previous, Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vpActions.push_back(std::make_shared<CEditorBrushDrawAction>(m_pEditor, m_pEditor->m_SelectedGroup));
|
||||
char aDisplay[256];
|
||||
str_format(aDisplay, sizeof(aDisplay), "Construct 'tele' game tiles (x%d)", Changes);
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions, aDisplay, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -790,6 +915,12 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
{
|
||||
m_AutoAutoMap = !m_AutoAutoMap;
|
||||
FlagModified(0, 0, m_Width, m_Height);
|
||||
if(!m_TilesHistory.empty()) // Sometimes pressing that button causes the automap to run so we should be able to undo that
|
||||
{
|
||||
// record undo
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAutoMap>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], m_TilesHistory));
|
||||
ClearHistory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -797,31 +928,15 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
if(m_pEditor->DoButton_Editor(&s_AutoMapperButton, "Automap", 0, &Button, 0, "Run the automapper"))
|
||||
{
|
||||
m_pEditor->m_Map.m_vpImages[m_Image]->m_AutoMapper.Proceed(this, m_AutoMapperConfig, m_Seed);
|
||||
// record undo
|
||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAutoMap>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], m_TilesHistory));
|
||||
ClearHistory();
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_WIDTH = 0,
|
||||
PROP_HEIGHT,
|
||||
PROP_SHIFT,
|
||||
PROP_SHIFT_BY,
|
||||
PROP_IMAGE,
|
||||
PROP_COLOR,
|
||||
PROP_COLOR_ENV,
|
||||
PROP_COLOR_ENV_OFFSET,
|
||||
PROP_AUTOMAPPER,
|
||||
PROP_SEED,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
int Color = 0;
|
||||
Color |= m_Color.r << 24;
|
||||
Color |= m_Color.g << 16;
|
||||
Color |= m_Color.b << 8;
|
||||
Color |= m_Color.a;
|
||||
int Color = PackColor(m_Color);
|
||||
|
||||
CProperty aProps[] = {
|
||||
{"Width", m_Width, PROPTYPE_INT_SCROLL, 1, 100000},
|
||||
|
@ -839,21 +954,24 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
|
||||
if(EntitiesLayer) // remove the image and color properties if this is a game layer
|
||||
{
|
||||
aProps[PROP_IMAGE].m_pName = nullptr;
|
||||
aProps[PROP_COLOR].m_pName = nullptr;
|
||||
aProps[PROP_AUTOMAPPER].m_pName = nullptr;
|
||||
aProps[(int)ETilesProp::PROP_IMAGE].m_pName = nullptr;
|
||||
aProps[(int)ETilesProp::PROP_COLOR].m_pName = nullptr;
|
||||
aProps[(int)ETilesProp::PROP_AUTOMAPPER].m_pName = nullptr;
|
||||
}
|
||||
if(m_Image == -1)
|
||||
{
|
||||
aProps[PROP_AUTOMAPPER].m_pName = nullptr;
|
||||
aProps[PROP_SEED].m_pName = nullptr;
|
||||
aProps[(int)ETilesProp::PROP_AUTOMAPPER].m_pName = nullptr;
|
||||
aProps[(int)ETilesProp::PROP_SEED].m_pName = nullptr;
|
||||
}
|
||||
|
||||
static int s_aIds[NUM_PROPS] = {0};
|
||||
static int s_aIds[(int)ETilesProp::NUM_PROPS] = {0};
|
||||
int NewVal = 0;
|
||||
int Prop = m_pEditor->DoProperties(pToolBox, aProps, s_aIds, &NewVal);
|
||||
auto [State, Prop] = m_pEditor->DoPropertiesWithState<ETilesProp>(pToolBox, aProps, s_aIds, &NewVal);
|
||||
|
||||
if(Prop == PROP_WIDTH && NewVal > 1)
|
||||
static CLayerTilesPropTracker s_Tracker(m_pEditor);
|
||||
s_Tracker.Begin(this, Prop, State);
|
||||
|
||||
if(Prop == ETilesProp::PROP_WIDTH && NewVal > 1)
|
||||
{
|
||||
if(NewVal > 1000 && !m_pEditor->m_LargeLayerWasWarned)
|
||||
{
|
||||
|
@ -863,7 +981,7 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
}
|
||||
Resize(NewVal, m_Height);
|
||||
}
|
||||
else if(Prop == PROP_HEIGHT && NewVal > 1)
|
||||
else if(Prop == ETilesProp::PROP_HEIGHT && NewVal > 1)
|
||||
{
|
||||
if(NewVal > 1000 && !m_pEditor->m_LargeLayerWasWarned)
|
||||
{
|
||||
|
@ -873,15 +991,15 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
}
|
||||
Resize(m_Width, NewVal);
|
||||
}
|
||||
else if(Prop == PROP_SHIFT)
|
||||
else if(Prop == ETilesProp::PROP_SHIFT)
|
||||
{
|
||||
Shift(NewVal);
|
||||
}
|
||||
else if(Prop == PROP_SHIFT_BY)
|
||||
else if(Prop == ETilesProp::PROP_SHIFT_BY)
|
||||
{
|
||||
m_pEditor->m_ShiftBy = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_IMAGE)
|
||||
else if(Prop == ETilesProp::PROP_IMAGE)
|
||||
{
|
||||
m_Image = NewVal;
|
||||
if(NewVal == -1)
|
||||
|
@ -901,14 +1019,14 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(Prop == PROP_COLOR)
|
||||
else if(Prop == ETilesProp::PROP_COLOR)
|
||||
{
|
||||
m_Color.r = (NewVal >> 24) & 0xff;
|
||||
m_Color.g = (NewVal >> 16) & 0xff;
|
||||
m_Color.b = (NewVal >> 8) & 0xff;
|
||||
m_Color.a = NewVal & 0xff;
|
||||
}
|
||||
else if(Prop == PROP_COLOR_ENV)
|
||||
else if(Prop == ETilesProp::PROP_COLOR_ENV)
|
||||
{
|
||||
int Index = clamp(NewVal - 1, -1, (int)m_pEditor->m_Map.m_vpEnvelopes.size() - 1);
|
||||
const int Step = (Index - m_ColorEnv) % 2;
|
||||
|
@ -924,15 +1042,15 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(Prop == PROP_COLOR_ENV_OFFSET)
|
||||
else if(Prop == ETilesProp::PROP_COLOR_ENV_OFFSET)
|
||||
{
|
||||
m_ColorEnvOffset = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_SEED)
|
||||
else if(Prop == ETilesProp::PROP_SEED)
|
||||
{
|
||||
m_Seed = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_AUTOMAPPER)
|
||||
else if(Prop == ETilesProp::PROP_AUTOMAPPER)
|
||||
{
|
||||
if(m_Image >= 0 && m_pEditor->m_Map.m_vpImages[m_Image]->m_AutoMapper.ConfigNamesNum() > 0 && NewVal >= 0)
|
||||
m_AutoMapperConfig = NewVal % m_pEditor->m_Map.m_vpImages[m_Image]->m_AutoMapper.ConfigNamesNum();
|
||||
|
@ -940,15 +1058,17 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
m_AutoMapperConfig = -1;
|
||||
}
|
||||
|
||||
if(Prop != -1)
|
||||
if(Prop != ETilesProp::PROP_NONE)
|
||||
{
|
||||
FlagModified(0, 0, m_Width, m_Height);
|
||||
}
|
||||
|
||||
s_Tracker.End(Prop, State);
|
||||
|
||||
return CUI::POPUP_KEEP_OPEN;
|
||||
}
|
||||
|
||||
CUI::EPopupMenuFunctionResult CLayerTiles::RenderCommonProperties(SCommonPropState &State, CEditor *pEditor, CUIRect *pToolbox, std::vector<std::shared_ptr<CLayerTiles>> &vpLayers)
|
||||
CUI::EPopupMenuFunctionResult CLayerTiles::RenderCommonProperties(SCommonPropState &State, CEditor *pEditor, CUIRect *pToolbox, std::vector<std::shared_ptr<CLayerTiles>> &vpLayers, std::vector<int> &vLayerIndices)
|
||||
{
|
||||
if(State.m_Modified)
|
||||
{
|
||||
|
@ -957,22 +1077,77 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderCommonProperties(SCommonPropSta
|
|||
static int s_CommitButton = 0;
|
||||
if(pEditor->DoButton_Editor(&s_CommitButton, "Commit", 0, &Commit, 0, "Applies the changes"))
|
||||
{
|
||||
bool HasModifiedSize = (State.m_Modified & SCommonPropState::MODIFIED_SIZE) != 0;
|
||||
bool HasModifiedColor = (State.m_Modified & SCommonPropState::MODIFIED_COLOR) != 0;
|
||||
|
||||
std::vector<std::shared_ptr<IEditorAction>> vpActions;
|
||||
int j = 0;
|
||||
int GroupIndex = pEditor->m_SelectedGroup;
|
||||
for(auto &pLayer : vpLayers)
|
||||
{
|
||||
if((State.m_Modified & SCommonPropState::MODIFIED_SIZE) != 0)
|
||||
int LayerIndex = vLayerIndices[j++];
|
||||
if(HasModifiedSize)
|
||||
{
|
||||
std::map<int, std::shared_ptr<CLayer>> SavedLayers;
|
||||
SavedLayers[LAYERTYPE_TILES] = pLayer->Duplicate();
|
||||
if(pLayer->m_Game || pLayer->m_Front || pLayer->m_Switch || pLayer->m_Speedup || pLayer->m_Tune || pLayer->m_Tele)
|
||||
{ // Need to save all entities layers when any entity layer
|
||||
if(pEditor->m_Map.m_pFrontLayer && !pLayer->m_Front)
|
||||
SavedLayers[LAYERTYPE_FRONT] = pEditor->m_Map.m_pFrontLayer->Duplicate();
|
||||
if(pEditor->m_Map.m_pTeleLayer && !pLayer->m_Tele)
|
||||
SavedLayers[LAYERTYPE_TELE] = pEditor->m_Map.m_pTeleLayer->Duplicate();
|
||||
if(pEditor->m_Map.m_pSwitchLayer && !pLayer->m_Switch)
|
||||
SavedLayers[LAYERTYPE_SWITCH] = pEditor->m_Map.m_pSwitchLayer->Duplicate();
|
||||
if(pEditor->m_Map.m_pSpeedupLayer && !pLayer->m_Speedup)
|
||||
SavedLayers[LAYERTYPE_SPEEDUP] = pEditor->m_Map.m_pSpeedupLayer->Duplicate();
|
||||
if(pEditor->m_Map.m_pTuneLayer && !pLayer->m_Tune)
|
||||
SavedLayers[LAYERTYPE_TUNE] = pEditor->m_Map.m_pTuneLayer->Duplicate();
|
||||
if(!pLayer->m_Game)
|
||||
SavedLayers[LAYERTYPE_GAME] = pEditor->m_Map.m_pGameLayer->Duplicate();
|
||||
}
|
||||
|
||||
int PrevW = pLayer->m_Width;
|
||||
int PrevH = pLayer->m_Height;
|
||||
pLayer->Resize(State.m_Width, State.m_Height);
|
||||
|
||||
if((State.m_Modified & SCommonPropState::MODIFIED_COLOR) != 0)
|
||||
if(PrevW != State.m_Width)
|
||||
{
|
||||
std::shared_ptr<CEditorActionEditLayerTilesProp> pAction;
|
||||
vpActions.push_back(pAction = std::make_shared<CEditorActionEditLayerTilesProp>(pEditor, GroupIndex, LayerIndex, ETilesProp::PROP_WIDTH, PrevW, State.m_Width));
|
||||
pAction->SetSavedLayers(SavedLayers);
|
||||
}
|
||||
|
||||
if(PrevH != State.m_Height)
|
||||
{
|
||||
std::shared_ptr<CEditorActionEditLayerTilesProp> pAction;
|
||||
vpActions.push_back(pAction = std::make_shared<CEditorActionEditLayerTilesProp>(pEditor, GroupIndex, LayerIndex, ETilesProp::PROP_HEIGHT, PrevH, State.m_Height));
|
||||
pAction->SetSavedLayers(SavedLayers);
|
||||
}
|
||||
}
|
||||
|
||||
if(HasModifiedColor)
|
||||
{
|
||||
int Color = 0;
|
||||
Color |= pLayer->m_Color.r << 24;
|
||||
Color |= pLayer->m_Color.g << 16;
|
||||
Color |= pLayer->m_Color.b << 8;
|
||||
Color |= pLayer->m_Color.a;
|
||||
|
||||
pLayer->m_Color.r = (State.m_Color >> 24) & 0xff;
|
||||
pLayer->m_Color.g = (State.m_Color >> 16) & 0xff;
|
||||
pLayer->m_Color.b = (State.m_Color >> 8) & 0xff;
|
||||
pLayer->m_Color.a = State.m_Color & 0xff;
|
||||
|
||||
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(pEditor, GroupIndex, LayerIndex, ETilesProp::PROP_COLOR, Color, State.m_Color));
|
||||
}
|
||||
|
||||
pLayer->FlagModified(0, 0, pLayer->m_Width, pLayer->m_Height);
|
||||
}
|
||||
State.m_Modified = 0;
|
||||
|
||||
char aDisplay[256];
|
||||
str_format(aDisplay, sizeof(aDisplay), "Edit %d layers common properties: %s", (int)vpLayers.size(), HasModifiedColor && HasModifiedSize ? "color, size" : (HasModifiedColor ? "color" : "size"));
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(pEditor, vpActions, aDisplay));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -999,16 +1174,6 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderCommonProperties(SCommonPropSta
|
|||
pToolbox->HSplitTop(2.0f, nullptr, pToolbox);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_WIDTH = 0,
|
||||
PROP_HEIGHT,
|
||||
PROP_SHIFT,
|
||||
PROP_SHIFT_BY,
|
||||
PROP_COLOR,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
CProperty aProps[] = {
|
||||
{"Width", State.m_Width, PROPTYPE_INT_SCROLL, 1, 100000},
|
||||
{"Height", State.m_Height, PROPTYPE_INT_SCROLL, 1, 100000},
|
||||
|
@ -1018,11 +1183,17 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderCommonProperties(SCommonPropSta
|
|||
{nullptr},
|
||||
};
|
||||
|
||||
static int s_aIds[NUM_PROPS] = {0};
|
||||
static int s_aIds[(int)ETilesCommonProp::NUM_PROPS] = {0};
|
||||
int NewVal = 0;
|
||||
int Prop = pEditor->DoProperties(pToolbox, aProps, s_aIds, &NewVal);
|
||||
auto [PropState, Prop] = pEditor->DoPropertiesWithState<ETilesCommonProp>(pToolbox, aProps, s_aIds, &NewVal);
|
||||
|
||||
if(Prop == PROP_WIDTH && NewVal > 1)
|
||||
static CLayerTilesCommonPropTracker s_Tracker(pEditor);
|
||||
s_Tracker.m_vpLayers = vpLayers;
|
||||
s_Tracker.m_vLayerIndices = vLayerIndices;
|
||||
|
||||
s_Tracker.Begin(nullptr, Prop, PropState);
|
||||
|
||||
if(Prop == ETilesCommonProp::PROP_WIDTH && NewVal > 1)
|
||||
{
|
||||
if(NewVal > 1000 && !pEditor->m_LargeLayerWasWarned)
|
||||
{
|
||||
|
@ -1032,7 +1203,7 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderCommonProperties(SCommonPropSta
|
|||
}
|
||||
State.m_Width = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_HEIGHT && NewVal > 1)
|
||||
else if(Prop == ETilesCommonProp::PROP_HEIGHT && NewVal > 1)
|
||||
{
|
||||
if(NewVal > 1000 && !pEditor->m_LargeLayerWasWarned)
|
||||
{
|
||||
|
@ -1042,25 +1213,27 @@ CUI::EPopupMenuFunctionResult CLayerTiles::RenderCommonProperties(SCommonPropSta
|
|||
}
|
||||
State.m_Height = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_SHIFT)
|
||||
else if(Prop == ETilesCommonProp::PROP_SHIFT)
|
||||
{
|
||||
for(auto &pLayer : vpLayers)
|
||||
pLayer->Shift(NewVal);
|
||||
}
|
||||
else if(Prop == PROP_SHIFT_BY)
|
||||
else if(Prop == ETilesCommonProp::PROP_SHIFT_BY)
|
||||
{
|
||||
pEditor->m_ShiftBy = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_COLOR)
|
||||
else if(Prop == ETilesCommonProp::PROP_COLOR)
|
||||
{
|
||||
State.m_Color = NewVal;
|
||||
}
|
||||
|
||||
if(Prop == PROP_WIDTH || Prop == PROP_HEIGHT)
|
||||
s_Tracker.End(Prop, PropState);
|
||||
|
||||
if(Prop == ETilesCommonProp::PROP_WIDTH || Prop == ETilesCommonProp::PROP_HEIGHT)
|
||||
{
|
||||
State.m_Modified |= SCommonPropState::MODIFIED_SIZE;
|
||||
}
|
||||
else if(Prop == PROP_COLOR)
|
||||
else if(Prop == ETilesCommonProp::PROP_COLOR)
|
||||
{
|
||||
State.m_Modified |= SCommonPropState::MODIFIED_COLOR;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,21 @@
|
|||
#ifndef GAME_EDITOR_MAPITEMS_LAYER_TILES_H
|
||||
#define GAME_EDITOR_MAPITEMS_LAYER_TILES_H
|
||||
|
||||
#include <game/editor/editor_trackers.h>
|
||||
#include <map>
|
||||
|
||||
#include "layer.h"
|
||||
|
||||
struct STileStateChange
|
||||
{
|
||||
bool m_Changed;
|
||||
CTile m_Previous;
|
||||
CTile m_Current;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using EditorTileStateChangeHistory = std::map<int, std::map<int, T>>;
|
||||
|
||||
enum
|
||||
{
|
||||
DIRECTION_LEFT = 0,
|
||||
|
@ -89,6 +102,7 @@ public:
|
|||
|
||||
virtual CTile GetTile(int x, int y);
|
||||
virtual void SetTile(int x, int y, CTile Tile);
|
||||
void SetTileIgnoreHistory(int x, int y, CTile Tile);
|
||||
|
||||
virtual void Resize(int NewW, int NewH);
|
||||
virtual void Shift(int Direction);
|
||||
|
@ -114,6 +128,7 @@ public:
|
|||
void BrushRotate(float Amount) override;
|
||||
|
||||
std::shared_ptr<CLayer> Duplicate() const override;
|
||||
const char *TypeName() const override;
|
||||
|
||||
virtual void ShowInfo();
|
||||
CUI::EPopupMenuFunctionResult RenderProperties(CUIRect *pToolbox) override;
|
||||
|
@ -130,7 +145,7 @@ public:
|
|||
int m_Height = -1;
|
||||
int m_Color = 0;
|
||||
};
|
||||
static CUI::EPopupMenuFunctionResult RenderCommonProperties(SCommonPropState &State, CEditor *pEditor, CUIRect *pToolbox, std::vector<std::shared_ptr<CLayerTiles>> &vpLayers);
|
||||
static CUI::EPopupMenuFunctionResult RenderCommonProperties(SCommonPropState &State, CEditor *pEditor, CUIRect *pToolbox, std::vector<std::shared_ptr<CLayerTiles>> &vpLayers, std::vector<int> &vLayerIndices);
|
||||
|
||||
void ModifyImageIndex(FIndexModifyFunction pfnFunc) override;
|
||||
void ModifyEnvelopeIndex(FIndexModifyFunction pfnFunc) override;
|
||||
|
@ -166,6 +181,14 @@ public:
|
|||
int m_Switch;
|
||||
int m_Tune;
|
||||
char m_aFileName[IO_MAX_PATH_LENGTH];
|
||||
|
||||
EditorTileStateChangeHistory<STileStateChange> m_TilesHistory;
|
||||
inline virtual void ClearHistory() { m_TilesHistory.clear(); }
|
||||
|
||||
protected:
|
||||
void RecordStateChange(int x, int y, CTile Previous, CTile Tile);
|
||||
|
||||
friend class CAutoMapper;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,6 +12,16 @@ CLayerTune::CLayerTune(CEditor *pEditor, int w, int h) :
|
|||
mem_zero(m_pTuneTile, (size_t)w * h * sizeof(CTuneTile));
|
||||
}
|
||||
|
||||
CLayerTune::CLayerTune(const CLayerTune &Other) :
|
||||
CLayerTiles(Other)
|
||||
{
|
||||
str_copy(m_aName, "Tune copy");
|
||||
m_Tune = 1;
|
||||
|
||||
m_pTuneTile = new CTuneTile[m_Width * m_Height];
|
||||
mem_copy(m_pTuneTile, Other.m_pTuneTile, (size_t)m_Width * m_Height * sizeof(CTuneTile));
|
||||
}
|
||||
|
||||
CLayerTune::~CLayerTune()
|
||||
{
|
||||
delete[] m_pTuneTile;
|
||||
|
@ -82,40 +92,61 @@ void CLayerTune::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy)
|
|||
if(!Destructive && GetTile(fx, fy).m_Index)
|
||||
continue;
|
||||
|
||||
int Index = fy * m_Width + fx;
|
||||
STuneTileStateChange::SData Previous{
|
||||
m_pTuneTile[Index].m_Number,
|
||||
m_pTuneTile[Index].m_Type,
|
||||
m_pTiles[Index].m_Index};
|
||||
|
||||
if((m_pEditor->m_AllowPlaceUnusedTiles || IsValidTuneTile(pTuneLayer->m_pTiles[y * pTuneLayer->m_Width + x].m_Index)) && pTuneLayer->m_pTiles[y * pTuneLayer->m_Width + x].m_Index != TILE_AIR)
|
||||
{
|
||||
if(m_pEditor->m_TuningNum != pTuneLayer->m_TuningNumber)
|
||||
{
|
||||
m_pTuneTile[fy * m_Width + fx].m_Number = m_pEditor->m_TuningNum;
|
||||
m_pTuneTile[Index].m_Number = m_pEditor->m_TuningNum;
|
||||
}
|
||||
else if(pTuneLayer->m_pTuneTile[y * pTuneLayer->m_Width + x].m_Number)
|
||||
m_pTuneTile[fy * m_Width + fx].m_Number = pTuneLayer->m_pTuneTile[y * pTuneLayer->m_Width + x].m_Number;
|
||||
m_pTuneTile[Index].m_Number = pTuneLayer->m_pTuneTile[y * pTuneLayer->m_Width + x].m_Number;
|
||||
else
|
||||
{
|
||||
if(!m_pEditor->m_TuningNum)
|
||||
{
|
||||
m_pTuneTile[fy * m_Width + fx].m_Number = 0;
|
||||
m_pTuneTile[fy * m_Width + fx].m_Type = 0;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = 0;
|
||||
m_pTuneTile[Index].m_Number = 0;
|
||||
m_pTuneTile[Index].m_Type = 0;
|
||||
m_pTiles[Index].m_Index = 0;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
m_pTuneTile[fy * m_Width + fx].m_Number = m_pEditor->m_TuningNum;
|
||||
m_pTuneTile[Index].m_Number = m_pEditor->m_TuningNum;
|
||||
}
|
||||
|
||||
m_pTuneTile[fy * m_Width + fx].m_Type = pTuneLayer->m_pTiles[y * pTuneLayer->m_Width + x].m_Index;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = pTuneLayer->m_pTiles[y * pTuneLayer->m_Width + x].m_Index;
|
||||
m_pTuneTile[Index].m_Type = pTuneLayer->m_pTiles[y * pTuneLayer->m_Width + x].m_Index;
|
||||
m_pTiles[Index].m_Index = pTuneLayer->m_pTiles[y * pTuneLayer->m_Width + x].m_Index;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pTuneTile[fy * m_Width + fx].m_Number = 0;
|
||||
m_pTuneTile[fy * m_Width + fx].m_Type = 0;
|
||||
m_pTiles[fy * m_Width + fx].m_Index = 0;
|
||||
m_pTuneTile[Index].m_Number = 0;
|
||||
m_pTuneTile[Index].m_Type = 0;
|
||||
m_pTiles[Index].m_Index = 0;
|
||||
}
|
||||
|
||||
STuneTileStateChange::SData Current{
|
||||
m_pTuneTile[Index].m_Number,
|
||||
m_pTuneTile[Index].m_Type,
|
||||
m_pTiles[Index].m_Index};
|
||||
|
||||
RecordStateChange(fx, fy, Previous, Current);
|
||||
}
|
||||
FlagModified(sx, sy, pTuneLayer->m_Width, pTuneLayer->m_Height);
|
||||
}
|
||||
|
||||
void CLayerTune::RecordStateChange(int x, int y, STuneTileStateChange::SData Previous, STuneTileStateChange::SData Current)
|
||||
{
|
||||
if(!m_History[y][x].m_Changed)
|
||||
m_History[y][x] = STuneTileStateChange{true, Previous, Current};
|
||||
else
|
||||
m_History[y][x].m_Current = Current;
|
||||
}
|
||||
|
||||
void CLayerTune::BrushFlipX()
|
||||
{
|
||||
CLayerTiles::BrushFlipX();
|
||||
|
@ -194,6 +225,11 @@ void CLayerTune::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRe
|
|||
const int SrcIndex = Empty ? 0 : (y * pLt->m_Width + x % pLt->m_Width) % (pLt->m_Width * pLt->m_Height);
|
||||
const int TgtIndex = fy * m_Width + fx;
|
||||
|
||||
STuneTileStateChange::SData Previous{
|
||||
m_pTuneTile[TgtIndex].m_Number,
|
||||
m_pTuneTile[TgtIndex].m_Type,
|
||||
m_pTiles[TgtIndex].m_Index};
|
||||
|
||||
if(Empty || (!m_pEditor->m_AllowPlaceUnusedTiles && !IsValidTuneTile((pLt->m_pTiles[SrcIndex]).m_Index)))
|
||||
{
|
||||
m_pTiles[TgtIndex].m_Index = 0;
|
||||
|
@ -213,8 +249,25 @@ void CLayerTune::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRe
|
|||
m_pTuneTile[TgtIndex].m_Number = pLt->m_pTuneTile[SrcIndex].m_Number;
|
||||
}
|
||||
}
|
||||
|
||||
STuneTileStateChange::SData Current{
|
||||
m_pTuneTile[TgtIndex].m_Number,
|
||||
m_pTuneTile[TgtIndex].m_Type,
|
||||
m_pTiles[TgtIndex].m_Index};
|
||||
|
||||
RecordStateChange(fx, fy, Previous, Current);
|
||||
}
|
||||
}
|
||||
|
||||
FlagModified(sx, sy, w, h);
|
||||
}
|
||||
|
||||
std::shared_ptr<CLayer> CLayerTune::Duplicate() const
|
||||
{
|
||||
return std::make_shared<CLayerTune>(*this);
|
||||
}
|
||||
|
||||
const char *CLayerTune::TypeName() const
|
||||
{
|
||||
return "tune";
|
||||
}
|
||||
|
|
|
@ -3,10 +3,22 @@
|
|||
|
||||
#include "layer_tiles.h"
|
||||
|
||||
struct STuneTileStateChange
|
||||
{
|
||||
bool m_Changed;
|
||||
struct SData
|
||||
{
|
||||
int m_Number;
|
||||
int m_Type;
|
||||
int m_Index;
|
||||
} m_Previous, m_Current;
|
||||
};
|
||||
|
||||
class CLayerTune : public CLayerTiles
|
||||
{
|
||||
public:
|
||||
CLayerTune(CEditor *pEditor, int w, int h);
|
||||
CLayerTune(const CLayerTune &Other);
|
||||
~CLayerTune();
|
||||
|
||||
CTuneTile *m_pTuneTile;
|
||||
|
@ -20,6 +32,19 @@ public:
|
|||
void BrushFlipY() override;
|
||||
void BrushRotate(float Amount) override;
|
||||
void FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRect Rect) override;
|
||||
|
||||
EditorTileStateChangeHistory<STuneTileStateChange> m_History;
|
||||
inline void ClearHistory() override
|
||||
{
|
||||
CLayerTiles::ClearHistory();
|
||||
m_History.clear();
|
||||
}
|
||||
|
||||
std::shared_ptr<CLayer> Duplicate() const override;
|
||||
const char *TypeName() const override;
|
||||
|
||||
private:
|
||||
void RecordStateChange(int x, int y, STuneTileStateChange::SData Previous, STuneTileStateChange::SData Current);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <game/editor/mapitems/sound.h>
|
||||
|
||||
#include "editor.h"
|
||||
#include "editor_actions.h"
|
||||
|
||||
CUI::EPopupMenuFunctionResult CEditor::PopupMenuFile(void *pContext, CUIRect View, bool Active)
|
||||
{
|
||||
|
@ -344,6 +345,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
{
|
||||
if(pEditor->DoButton_Editor(&s_DeleteButton, "Delete group", 0, &Button, 0, "Delete group"))
|
||||
{
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionGroup>(pEditor, pEditor->m_SelectedGroup, true));
|
||||
pEditor->m_Map.DeleteGroup(pEditor->m_SelectedGroup);
|
||||
pEditor->m_SelectedGroup = maximum(0, pEditor->m_SelectedGroup - 1);
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
|
@ -403,8 +405,10 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
std::shared_ptr<CLayer> pTeleLayer = std::make_shared<CLayerTele>(pEditor, pEditor->m_Map.m_pGameLayer->m_Width, pEditor->m_Map.m_pGameLayer->m_Height);
|
||||
pEditor->m_Map.MakeTeleLayer(pTeleLayer);
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->AddLayer(pTeleLayer);
|
||||
pEditor->SelectLayer(pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1);
|
||||
int LayerIndex = pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1;
|
||||
pEditor->SelectLayer(LayerIndex);
|
||||
pEditor->m_pBrush->Clear();
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAddLayer>(pEditor, pEditor->m_SelectedGroup, LayerIndex));
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
}
|
||||
|
@ -420,8 +424,10 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
std::shared_ptr<CLayer> pSpeedupLayer = std::make_shared<CLayerSpeedup>(pEditor, pEditor->m_Map.m_pGameLayer->m_Width, pEditor->m_Map.m_pGameLayer->m_Height);
|
||||
pEditor->m_Map.MakeSpeedupLayer(pSpeedupLayer);
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->AddLayer(pSpeedupLayer);
|
||||
pEditor->SelectLayer(pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1);
|
||||
int LayerIndex = pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1;
|
||||
pEditor->SelectLayer(LayerIndex);
|
||||
pEditor->m_pBrush->Clear();
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAddLayer>(pEditor, pEditor->m_SelectedGroup, LayerIndex));
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
}
|
||||
|
@ -437,8 +443,10 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
std::shared_ptr<CLayer> pTuneLayer = std::make_shared<CLayerTune>(pEditor, pEditor->m_Map.m_pGameLayer->m_Width, pEditor->m_Map.m_pGameLayer->m_Height);
|
||||
pEditor->m_Map.MakeTuneLayer(pTuneLayer);
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->AddLayer(pTuneLayer);
|
||||
pEditor->SelectLayer(pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1);
|
||||
int LayerIndex = pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1;
|
||||
pEditor->SelectLayer(LayerIndex);
|
||||
pEditor->m_pBrush->Clear();
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAddLayer>(pEditor, pEditor->m_SelectedGroup, LayerIndex));
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
}
|
||||
|
@ -454,8 +462,10 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
std::shared_ptr<CLayer> pFrontLayer = std::make_shared<CLayerFront>(pEditor, pEditor->m_Map.m_pGameLayer->m_Width, pEditor->m_Map.m_pGameLayer->m_Height);
|
||||
pEditor->m_Map.MakeFrontLayer(pFrontLayer);
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->AddLayer(pFrontLayer);
|
||||
pEditor->SelectLayer(pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1);
|
||||
int LayerIndex = pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1;
|
||||
pEditor->SelectLayer(LayerIndex);
|
||||
pEditor->m_pBrush->Clear();
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAddLayer>(pEditor, pEditor->m_SelectedGroup, LayerIndex));
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
}
|
||||
|
@ -471,8 +481,10 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
std::shared_ptr<CLayer> pSwitchLayer = std::make_shared<CLayerSwitch>(pEditor, pEditor->m_Map.m_pGameLayer->m_Width, pEditor->m_Map.m_pGameLayer->m_Height);
|
||||
pEditor->m_Map.MakeSwitchLayer(pSwitchLayer);
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->AddLayer(pSwitchLayer);
|
||||
pEditor->SelectLayer(pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1);
|
||||
int LayerIndex = pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1;
|
||||
pEditor->SelectLayer(LayerIndex);
|
||||
pEditor->m_pBrush->Clear();
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAddLayer>(pEditor, pEditor->m_SelectedGroup, LayerIndex));
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
}
|
||||
|
@ -485,8 +497,10 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
{
|
||||
std::shared_ptr<CLayer> pQuadLayer = std::make_shared<CLayerQuads>(pEditor);
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->AddLayer(pQuadLayer);
|
||||
pEditor->SelectLayer(pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1);
|
||||
int LayerIndex = pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1;
|
||||
pEditor->SelectLayer(LayerIndex);
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_Collapse = false;
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAddLayer>(pEditor, pEditor->m_SelectedGroup, LayerIndex));
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
||||
|
@ -499,8 +513,10 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
std::shared_ptr<CLayer> pTileLayer = std::make_shared<CLayerTiles>(pEditor, pEditor->m_Map.m_pGameLayer->m_Width, pEditor->m_Map.m_pGameLayer->m_Height);
|
||||
pTileLayer->m_pEditor = pEditor;
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->AddLayer(pTileLayer);
|
||||
pEditor->SelectLayer(pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1);
|
||||
int LayerIndex = pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1;
|
||||
pEditor->SelectLayer(LayerIndex);
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_Collapse = false;
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAddLayer>(pEditor, pEditor->m_SelectedGroup, LayerIndex));
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
||||
|
@ -512,8 +528,10 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
{
|
||||
std::shared_ptr<CLayer> pSoundLayer = std::make_shared<CLayerSounds>(pEditor);
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->AddLayer(pSoundLayer);
|
||||
pEditor->SelectLayer(pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1);
|
||||
int LayerIndex = pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1;
|
||||
pEditor->SelectLayer(LayerIndex);
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_Collapse = false;
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAddLayer>(pEditor, pEditor->m_SelectedGroup, LayerIndex));
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
||||
|
@ -530,21 +548,6 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
pEditor->m_Map.OnModify();
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_ORDER = 0,
|
||||
PROP_POS_X,
|
||||
PROP_POS_Y,
|
||||
PROP_PARA_X,
|
||||
PROP_PARA_Y,
|
||||
PROP_USE_CLIPPING,
|
||||
PROP_CLIP_X,
|
||||
PROP_CLIP_Y,
|
||||
PROP_CLIP_W,
|
||||
PROP_CLIP_H,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
CProperty aProps[] = {
|
||||
{"Order", pEditor->m_SelectedGroup, PROPTYPE_INT_STEP, 0, (int)pEditor->m_Map.m_vpGroups.size() - 1},
|
||||
{"Pos X", -pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_OffsetX, PROPTYPE_INT_SCROLL, -1000000, 1000000},
|
||||
|
@ -561,17 +564,20 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
|
||||
// cut the properties that aren't needed
|
||||
if(pEditor->GetSelectedGroup()->m_GameGroup)
|
||||
aProps[PROP_POS_X].m_pName = nullptr;
|
||||
aProps[(int)EGroupProp::PROP_POS_X].m_pName = nullptr;
|
||||
|
||||
static int s_aIds[NUM_PROPS] = {0};
|
||||
static int s_aIds[(int)EGroupProp::NUM_PROPS] = {0};
|
||||
int NewVal = 0;
|
||||
int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal);
|
||||
if(Prop != -1)
|
||||
auto [State, Prop] = pEditor->DoPropertiesWithState<EGroupProp>(&View, aProps, s_aIds, &NewVal);
|
||||
if(Prop != EGroupProp::PROP_NONE)
|
||||
{
|
||||
pEditor->m_Map.OnModify();
|
||||
}
|
||||
|
||||
if(Prop == PROP_ORDER)
|
||||
static CLayerGroupPropTracker s_Tracker(pEditor);
|
||||
s_Tracker.Begin(pEditor->GetSelectedGroup().get(), Prop, State);
|
||||
|
||||
if(Prop == EGroupProp::PROP_ORDER)
|
||||
{
|
||||
pEditor->m_SelectedGroup = pEditor->m_Map.SwapGroups(pEditor->m_SelectedGroup, NewVal);
|
||||
}
|
||||
|
@ -579,44 +585,46 @@ CUI::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
// these can not be changed on the game group
|
||||
if(!pEditor->GetSelectedGroup()->m_GameGroup)
|
||||
{
|
||||
if(Prop == PROP_PARA_X)
|
||||
if(Prop == EGroupProp::PROP_PARA_X)
|
||||
{
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ParallaxX = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_PARA_Y)
|
||||
else if(Prop == EGroupProp::PROP_PARA_Y)
|
||||
{
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ParallaxY = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_POS_X)
|
||||
else if(Prop == EGroupProp::PROP_POS_X)
|
||||
{
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_OffsetX = -NewVal;
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_OffsetX = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_POS_Y)
|
||||
else if(Prop == EGroupProp::PROP_POS_Y)
|
||||
{
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_OffsetY = -NewVal;
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_OffsetY = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_USE_CLIPPING)
|
||||
else if(Prop == EGroupProp::PROP_USE_CLIPPING)
|
||||
{
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_UseClipping = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_CLIP_X)
|
||||
else if(Prop == EGroupProp::PROP_CLIP_X)
|
||||
{
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ClipX = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_CLIP_Y)
|
||||
else if(Prop == EGroupProp::PROP_CLIP_Y)
|
||||
{
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ClipY = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_CLIP_W)
|
||||
else if(Prop == EGroupProp::PROP_CLIP_W)
|
||||
{
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ClipW = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_CLIP_H)
|
||||
else if(Prop == EGroupProp::PROP_CLIP_H)
|
||||
{
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_ClipH = NewVal;
|
||||
}
|
||||
}
|
||||
|
||||
s_Tracker.End(Prop, State);
|
||||
|
||||
return CUI::POPUP_KEEP_OPEN;
|
||||
}
|
||||
|
||||
|
@ -630,7 +638,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupLayer(void *pContext, CUIRect View,
|
|||
|
||||
if(pPopup->m_vpLayers.size() > 1)
|
||||
{
|
||||
return CLayerTiles::RenderCommonProperties(pPopup->m_CommonPropState, pEditor, &View, pPopup->m_vpLayers);
|
||||
return CLayerTiles::RenderCommonProperties(pPopup->m_CommonPropState, pEditor, &View, pPopup->m_vpLayers, pPopup->m_vLayerIndices);
|
||||
}
|
||||
|
||||
const bool EntitiesLayer = pCurrentLayer->IsEntitiesLayer();
|
||||
|
@ -643,6 +651,8 @@ CUI::EPopupMenuFunctionResult CEditor::PopupLayer(void *pContext, CUIRect View,
|
|||
static int s_DeleteButton = 0;
|
||||
if(pEditor->DoButton_Editor(&s_DeleteButton, "Delete layer", 0, &DeleteButton, 0, "Deletes the layer"))
|
||||
{
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionDeleteLayer>(pEditor, pEditor->m_SelectedGroup, pEditor->m_vSelectedLayers[0]));
|
||||
|
||||
if(pCurrentLayer == pEditor->m_Map.m_pFrontLayer)
|
||||
pEditor->m_Map.m_pFrontLayer = nullptr;
|
||||
if(pCurrentLayer == pEditor->m_Map.m_pTeleLayer)
|
||||
|
@ -654,6 +664,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupLayer(void *pContext, CUIRect View,
|
|||
if(pCurrentLayer == pEditor->m_Map.m_pTuneLayer)
|
||||
pEditor->m_Map.m_pTuneLayer = nullptr;
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->DeleteLayer(pEditor->m_vSelectedLayers[0]);
|
||||
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
}
|
||||
|
@ -668,6 +679,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupLayer(void *pContext, CUIRect View,
|
|||
if(pEditor->DoButton_Editor(&s_DuplicationButton, "Duplicate layer", 0, &DuplicateButton, 0, "Duplicates the layer"))
|
||||
{
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->DuplicateLayer(pEditor->m_vSelectedLayers[0]);
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAddLayer>(pEditor, pEditor->m_SelectedGroup, pEditor->m_vSelectedLayers[0] + 1, true));
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
}
|
||||
|
@ -690,14 +702,6 @@ CUI::EPopupMenuFunctionResult CEditor::PopupLayer(void *pContext, CUIRect View,
|
|||
if(!EntitiesLayer || pEditor->m_Map.m_pGameLayer != pCurrentLayer)
|
||||
View.HSplitBottom(10.0f, &View, nullptr);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_GROUP = 0,
|
||||
PROP_ORDER,
|
||||
PROP_HQ,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
CProperty aProps[] = {
|
||||
{"Group", pEditor->m_SelectedGroup, PROPTYPE_INT_STEP, 0, (int)pEditor->m_Map.m_vpGroups.size() - 1},
|
||||
{"Order", pEditor->m_vSelectedLayers[0], PROPTYPE_INT_STEP, 0, (int)pCurrentGroup->m_vpLayers.size() - 1},
|
||||
|
@ -718,19 +722,23 @@ CUI::EPopupMenuFunctionResult CEditor::PopupLayer(void *pContext, CUIRect View,
|
|||
aProps[2].m_Type = PROPTYPE_NULL;
|
||||
}
|
||||
|
||||
static int s_aIds[NUM_PROPS] = {0};
|
||||
static int s_aIds[(int)ELayerProp::NUM_PROPS] = {0};
|
||||
int NewVal = 0;
|
||||
int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal);
|
||||
if(Prop != -1)
|
||||
auto [State, Prop] = pEditor->DoPropertiesWithState<ELayerProp>(&View, aProps, s_aIds, &NewVal);
|
||||
if(Prop != ELayerProp::PROP_NONE)
|
||||
{
|
||||
pEditor->m_Map.OnModify();
|
||||
}
|
||||
|
||||
if(Prop == PROP_ORDER)
|
||||
static CLayerPropTracker s_Tracker(pEditor);
|
||||
s_Tracker.Begin(pCurrentLayer.get(), Prop, State);
|
||||
|
||||
if(Prop == ELayerProp::PROP_ORDER)
|
||||
{
|
||||
pEditor->SelectLayer(pCurrentGroup->SwapLayers(pEditor->m_vSelectedLayers[0], NewVal));
|
||||
int NewIndex = pCurrentGroup->SwapLayers(pEditor->m_vSelectedLayers[0], NewVal);
|
||||
pEditor->SelectLayer(NewIndex);
|
||||
}
|
||||
else if(Prop == PROP_GROUP)
|
||||
else if(Prop == ELayerProp::PROP_GROUP)
|
||||
{
|
||||
if(NewVal >= 0 && (size_t)NewVal < pEditor->m_Map.m_vpGroups.size())
|
||||
{
|
||||
|
@ -742,13 +750,15 @@ CUI::EPopupMenuFunctionResult CEditor::PopupLayer(void *pContext, CUIRect View,
|
|||
pEditor->SelectLayer(pEditor->m_Map.m_vpGroups[NewVal]->m_vpLayers.size() - 1);
|
||||
}
|
||||
}
|
||||
else if(Prop == PROP_HQ)
|
||||
else if(Prop == ELayerProp::PROP_HQ)
|
||||
{
|
||||
pCurrentLayer->m_Flags &= ~LAYERFLAG_DETAIL;
|
||||
if(NewVal)
|
||||
pCurrentLayer->m_Flags |= LAYERFLAG_DETAIL;
|
||||
}
|
||||
|
||||
s_Tracker.End(Prop, State);
|
||||
|
||||
return pCurrentLayer->RenderProperties(&View);
|
||||
}
|
||||
|
||||
|
@ -782,6 +792,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupQuad(void *pContext, CUIRect View, b
|
|||
static int s_AspectRatioButton = 0;
|
||||
if(pEditor->DoButton_Editor(&s_AspectRatioButton, "Aspect ratio", 0, &Button, 0, "Resizes the current Quad based on the aspect ratio of the image"))
|
||||
{
|
||||
pEditor->m_QuadTracker.BeginQuadTrack(pLayer, pEditor->m_vSelectedQuads);
|
||||
for(auto &pQuad : vpQuads)
|
||||
{
|
||||
int Top = pQuad->m_aPoints[0].y;
|
||||
|
@ -810,6 +821,8 @@ CUI::EPopupMenuFunctionResult CEditor::PopupQuad(void *pContext, CUIRect View, b
|
|||
pQuad->m_aPoints[3].y = Top + Height;
|
||||
pEditor->m_Map.OnModify();
|
||||
}
|
||||
pEditor->m_QuadTracker.EndQuadTrack();
|
||||
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
}
|
||||
|
@ -820,6 +833,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupQuad(void *pContext, CUIRect View, b
|
|||
static int s_AlignButton = 0;
|
||||
if(pEditor->DoButton_Editor(&s_AlignButton, "Align", 0, &Button, 0, "Aligns coordinates of the quad points"))
|
||||
{
|
||||
pEditor->m_QuadTracker.BeginQuadTrack(pLayer, pEditor->m_vSelectedQuads);
|
||||
for(auto &pQuad : vpQuads)
|
||||
{
|
||||
for(int k = 1; k < 4; k++)
|
||||
|
@ -829,6 +843,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupQuad(void *pContext, CUIRect View, b
|
|||
}
|
||||
pEditor->m_Map.OnModify();
|
||||
}
|
||||
pEditor->m_QuadTracker.EndQuadTrack();
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
||||
|
@ -838,6 +853,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupQuad(void *pContext, CUIRect View, b
|
|||
static int s_Button = 0;
|
||||
if(pEditor->DoButton_Editor(&s_Button, "Square", 0, &Button, 0, "Squares the current quad"))
|
||||
{
|
||||
pEditor->m_QuadTracker.BeginQuadTrack(pLayer, pEditor->m_vSelectedQuads);
|
||||
for(auto &pQuad : vpQuads)
|
||||
{
|
||||
int Top = pQuad->m_aPoints[0].y;
|
||||
|
@ -867,6 +883,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupQuad(void *pContext, CUIRect View, b
|
|||
pQuad->m_aPoints[3].y = Bottom;
|
||||
pEditor->m_Map.OnModify();
|
||||
}
|
||||
pEditor->m_QuadTracker.EndQuadTrack();
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
||||
|
@ -881,18 +898,6 @@ CUI::EPopupMenuFunctionResult CEditor::PopupQuad(void *pContext, CUIRect View, b
|
|||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_ORDER = 0,
|
||||
PROP_POS_X,
|
||||
PROP_POS_Y,
|
||||
PROP_POS_ENV,
|
||||
PROP_POS_ENV_OFFSET,
|
||||
PROP_COLOR_ENV,
|
||||
PROP_COLOR_ENV_OFFSET,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
const int NumQuads = pLayer ? (int)pLayer->m_vQuads.size() : 0;
|
||||
CProperty aProps[] = {
|
||||
{"Order", pEditor->m_vSelectedQuads[pEditor->m_SelectedQuadIndex], PROPTYPE_INT_STEP, 0, NumQuads},
|
||||
|
@ -905,18 +910,23 @@ CUI::EPopupMenuFunctionResult CEditor::PopupQuad(void *pContext, CUIRect View, b
|
|||
{nullptr},
|
||||
};
|
||||
|
||||
static int s_aIds[NUM_PROPS] = {0};
|
||||
static int s_aIds[(int)EQuadProp::NUM_PROPS] = {0};
|
||||
int NewVal = 0;
|
||||
int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal);
|
||||
if(Prop != -1)
|
||||
auto PropRes = pEditor->DoPropertiesWithState<EQuadProp>(&View, aProps, s_aIds, &NewVal);
|
||||
EQuadProp Prop = PropRes.m_Value;
|
||||
if(Prop != EQuadProp::PROP_NONE)
|
||||
{
|
||||
pEditor->m_Map.OnModify();
|
||||
if(PropRes.m_State == EEditState::START || PropRes.m_State == EEditState::ONE_GO)
|
||||
{
|
||||
pEditor->m_QuadTracker.BeginQuadPropTrack(pLayer, pEditor->m_vSelectedQuads, Prop);
|
||||
}
|
||||
}
|
||||
|
||||
const float OffsetX = i2fx(NewVal) - pCurrentQuad->m_aPoints[4].x;
|
||||
const float OffsetY = i2fx(NewVal) - pCurrentQuad->m_aPoints[4].y;
|
||||
|
||||
if(Prop == PROP_ORDER && pLayer)
|
||||
if(Prop == EQuadProp::PROP_ORDER && pLayer)
|
||||
{
|
||||
const int QuadIndex = pLayer->SwapQuads(pEditor->m_vSelectedQuads[pEditor->m_SelectedQuadIndex], NewVal);
|
||||
pEditor->m_vSelectedQuads[pEditor->m_SelectedQuadIndex] = QuadIndex;
|
||||
|
@ -924,17 +934,17 @@ CUI::EPopupMenuFunctionResult CEditor::PopupQuad(void *pContext, CUIRect View, b
|
|||
|
||||
for(auto &pQuad : vpQuads)
|
||||
{
|
||||
if(Prop == PROP_POS_X)
|
||||
if(Prop == EQuadProp::PROP_POS_X)
|
||||
{
|
||||
for(auto &Point : pQuad->m_aPoints)
|
||||
Point.x += OffsetX;
|
||||
}
|
||||
else if(Prop == PROP_POS_Y)
|
||||
else if(Prop == EQuadProp::PROP_POS_Y)
|
||||
{
|
||||
for(auto &Point : pQuad->m_aPoints)
|
||||
Point.y += OffsetY;
|
||||
}
|
||||
else if(Prop == PROP_POS_ENV)
|
||||
else if(Prop == EQuadProp::PROP_POS_ENV)
|
||||
{
|
||||
int Index = clamp(NewVal - 1, -1, (int)pEditor->m_Map.m_vpEnvelopes.size() - 1);
|
||||
int StepDirection = Index < pQuad->m_PosEnv ? -1 : 1;
|
||||
|
@ -950,11 +960,11 @@ CUI::EPopupMenuFunctionResult CEditor::PopupQuad(void *pContext, CUIRect View, b
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(Prop == PROP_POS_ENV_OFFSET)
|
||||
else if(Prop == EQuadProp::PROP_POS_ENV_OFFSET)
|
||||
{
|
||||
pQuad->m_PosEnvOffset = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_COLOR_ENV)
|
||||
else if(Prop == EQuadProp::PROP_COLOR_ENV)
|
||||
{
|
||||
int Index = clamp(NewVal - 1, -1, (int)pEditor->m_Map.m_vpEnvelopes.size() - 1);
|
||||
int StepDirection = Index < pQuad->m_ColorEnv ? -1 : 1;
|
||||
|
@ -970,12 +980,20 @@ CUI::EPopupMenuFunctionResult CEditor::PopupQuad(void *pContext, CUIRect View, b
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(Prop == PROP_COLOR_ENV_OFFSET)
|
||||
else if(Prop == EQuadProp::PROP_COLOR_ENV_OFFSET)
|
||||
{
|
||||
pQuad->m_ColorEnvOffset = NewVal;
|
||||
}
|
||||
}
|
||||
|
||||
if(Prop != EQuadProp::PROP_NONE)
|
||||
{
|
||||
if(PropRes.m_State == EEditState::END || PropRes.m_State == EEditState::ONE_GO)
|
||||
{
|
||||
pEditor->m_QuadTracker.EndQuadPropTrack(Prop);
|
||||
}
|
||||
}
|
||||
|
||||
return CUI::POPUP_KEEP_OPEN;
|
||||
}
|
||||
|
||||
|
@ -983,6 +1001,8 @@ CUI::EPopupMenuFunctionResult CEditor::PopupSource(void *pContext, CUIRect View,
|
|||
{
|
||||
CEditor *pEditor = static_cast<CEditor *>(pContext);
|
||||
CSoundSource *pSource = pEditor->GetSelectedSource();
|
||||
if(!pSource)
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
|
||||
CUIRect Button;
|
||||
|
||||
|
@ -994,9 +1014,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupSource(void *pContext, CUIRect View,
|
|||
std::shared_ptr<CLayerSounds> pLayer = std::static_pointer_cast<CLayerSounds>(pEditor->GetSelectedLayerType(0, LAYERTYPE_SOUNDS));
|
||||
if(pLayer)
|
||||
{
|
||||
pEditor->m_Map.OnModify();
|
||||
pLayer->m_vSources.erase(pLayer->m_vSources.begin() + pEditor->m_SelectedSource);
|
||||
pEditor->m_SelectedSource--;
|
||||
pEditor->m_EditorHistory.Execute(std::make_shared<CEditorActionDeleteSoundSource>(pEditor, pEditor->m_SelectedGroup, pEditor->m_vSelectedLayers[0], pEditor->m_SelectedSource));
|
||||
}
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
@ -1015,40 +1033,9 @@ CUI::EPopupMenuFunctionResult CEditor::PopupSource(void *pContext, CUIRect View,
|
|||
static int s_ShapeTypeButton = 0;
|
||||
if(pEditor->DoButton_Editor(&s_ShapeTypeButton, s_apShapeNames[pSource->m_Shape.m_Type], 0, &ShapeButton, 0, "Change shape"))
|
||||
{
|
||||
pSource->m_Shape.m_Type = (pSource->m_Shape.m_Type + 1) % CSoundShape::NUM_SHAPES;
|
||||
|
||||
// set default values
|
||||
switch(pSource->m_Shape.m_Type)
|
||||
{
|
||||
case CSoundShape::SHAPE_CIRCLE:
|
||||
{
|
||||
pSource->m_Shape.m_Circle.m_Radius = 1000.0f;
|
||||
break;
|
||||
}
|
||||
case CSoundShape::SHAPE_RECTANGLE:
|
||||
{
|
||||
pSource->m_Shape.m_Rectangle.m_Width = f2fx(1000.0f);
|
||||
pSource->m_Shape.m_Rectangle.m_Height = f2fx(800.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pEditor->m_EditorHistory.Execute(std::make_shared<CEditorActionEditSoundSource>(pEditor, pEditor->m_SelectedGroup, pEditor->m_vSelectedLayers[0], pEditor->m_SelectedSource, CEditorActionEditSoundSource::EEditType::SHAPE, (pSource->m_Shape.m_Type + 1) % CSoundShape::NUM_SHAPES));
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_POS_X = 0,
|
||||
PROP_POS_Y,
|
||||
PROP_LOOP,
|
||||
PROP_PAN,
|
||||
PROP_TIME_DELAY,
|
||||
PROP_FALLOFF,
|
||||
PROP_POS_ENV,
|
||||
PROP_POS_ENV_OFFSET,
|
||||
PROP_SOUND_ENV,
|
||||
PROP_SOUND_ENV_OFFSET,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
CProperty aProps[] = {
|
||||
{"Pos X", pSource->m_Position.x / 1000, PROPTYPE_INT_SCROLL, -1000000, 1000000},
|
||||
{"Pos Y", pSource->m_Position.y / 1000, PROPTYPE_INT_SCROLL, -1000000, 1000000},
|
||||
|
@ -1063,39 +1050,42 @@ CUI::EPopupMenuFunctionResult CEditor::PopupSource(void *pContext, CUIRect View,
|
|||
{nullptr},
|
||||
};
|
||||
|
||||
static int s_aIds[NUM_PROPS] = {0};
|
||||
static int s_aIds[(int)ESoundProp::NUM_PROPS] = {0};
|
||||
int NewVal = 0;
|
||||
int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal);
|
||||
if(Prop != -1)
|
||||
auto [State, Prop] = pEditor->DoPropertiesWithState<ESoundProp>(&View, aProps, s_aIds, &NewVal);
|
||||
if(Prop != ESoundProp::PROP_NONE)
|
||||
{
|
||||
pEditor->m_Map.OnModify();
|
||||
}
|
||||
|
||||
if(Prop == PROP_POS_X)
|
||||
static CSoundSourcePropTracker s_Tracker(pEditor);
|
||||
s_Tracker.Begin(pSource, Prop, State);
|
||||
|
||||
if(Prop == ESoundProp::PROP_POS_X)
|
||||
{
|
||||
pSource->m_Position.x = NewVal * 1000;
|
||||
}
|
||||
else if(Prop == PROP_POS_Y)
|
||||
else if(Prop == ESoundProp::PROP_POS_Y)
|
||||
{
|
||||
pSource->m_Position.y = NewVal * 1000;
|
||||
}
|
||||
else if(Prop == PROP_LOOP)
|
||||
else if(Prop == ESoundProp::PROP_LOOP)
|
||||
{
|
||||
pSource->m_Loop = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_PAN)
|
||||
else if(Prop == ESoundProp::PROP_PAN)
|
||||
{
|
||||
pSource->m_Pan = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_TIME_DELAY)
|
||||
else if(Prop == ESoundProp::PROP_TIME_DELAY)
|
||||
{
|
||||
pSource->m_TimeDelay = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_FALLOFF)
|
||||
else if(Prop == ESoundProp::PROP_FALLOFF)
|
||||
{
|
||||
pSource->m_Falloff = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_POS_ENV)
|
||||
else if(Prop == ESoundProp::PROP_POS_ENV)
|
||||
{
|
||||
int Index = clamp(NewVal - 1, -1, (int)pEditor->m_Map.m_vpEnvelopes.size() - 1);
|
||||
const int StepDirection = Index < pSource->m_PosEnv ? -1 : 1;
|
||||
|
@ -1108,11 +1098,11 @@ CUI::EPopupMenuFunctionResult CEditor::PopupSource(void *pContext, CUIRect View,
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(Prop == PROP_POS_ENV_OFFSET)
|
||||
else if(Prop == ESoundProp::PROP_POS_ENV_OFFSET)
|
||||
{
|
||||
pSource->m_PosEnvOffset = NewVal;
|
||||
}
|
||||
else if(Prop == PROP_SOUND_ENV)
|
||||
else if(Prop == ESoundProp::PROP_SOUND_ENV)
|
||||
{
|
||||
int Index = clamp(NewVal - 1, -1, (int)pEditor->m_Map.m_vpEnvelopes.size() - 1);
|
||||
const int StepDirection = Index < pSource->m_SoundEnv ? -1 : 1;
|
||||
|
@ -1125,75 +1115,72 @@ CUI::EPopupMenuFunctionResult CEditor::PopupSource(void *pContext, CUIRect View,
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(Prop == PROP_SOUND_ENV_OFFSET)
|
||||
else if(Prop == ESoundProp::PROP_SOUND_ENV_OFFSET)
|
||||
{
|
||||
pSource->m_SoundEnvOffset = NewVal;
|
||||
}
|
||||
|
||||
s_Tracker.End(Prop, State);
|
||||
|
||||
// source shape properties
|
||||
switch(pSource->m_Shape.m_Type)
|
||||
{
|
||||
case CSoundShape::SHAPE_CIRCLE:
|
||||
{
|
||||
enum
|
||||
{
|
||||
PROP_CIRCLE_RADIUS = 0,
|
||||
NUM_CIRCLE_PROPS,
|
||||
};
|
||||
|
||||
CProperty aCircleProps[] = {
|
||||
{"Radius", pSource->m_Shape.m_Circle.m_Radius, PROPTYPE_INT_SCROLL, 0, 1000000},
|
||||
{nullptr},
|
||||
};
|
||||
|
||||
static int s_aCircleIds[NUM_CIRCLE_PROPS] = {0};
|
||||
static int s_aCircleIds[(int)ECircleShapeProp::NUM_CIRCLE_PROPS] = {0};
|
||||
NewVal = 0;
|
||||
Prop = pEditor->DoProperties(&View, aCircleProps, s_aCircleIds, &NewVal);
|
||||
if(Prop != -1)
|
||||
auto [LocalState, LocalProp] = pEditor->DoPropertiesWithState<ECircleShapeProp>(&View, aCircleProps, s_aCircleIds, &NewVal);
|
||||
if(LocalProp != ECircleShapeProp::PROP_NONE)
|
||||
{
|
||||
pEditor->m_Map.OnModify();
|
||||
}
|
||||
|
||||
if(Prop == PROP_CIRCLE_RADIUS)
|
||||
static CSoundSourceCircleShapePropTracker s_ShapeTracker(pEditor);
|
||||
s_ShapeTracker.Begin(pSource, LocalProp, LocalState);
|
||||
|
||||
if(LocalProp == ECircleShapeProp::PROP_CIRCLE_RADIUS)
|
||||
{
|
||||
pSource->m_Shape.m_Circle.m_Radius = NewVal;
|
||||
}
|
||||
|
||||
s_ShapeTracker.End(LocalProp, LocalState);
|
||||
break;
|
||||
}
|
||||
|
||||
case CSoundShape::SHAPE_RECTANGLE:
|
||||
{
|
||||
enum
|
||||
{
|
||||
PROP_RECTANGLE_WIDTH = 0,
|
||||
PROP_RECTANGLE_HEIGHT,
|
||||
NUM_RECTANGLE_PROPS,
|
||||
};
|
||||
|
||||
CProperty aRectangleProps[] = {
|
||||
{"Width", pSource->m_Shape.m_Rectangle.m_Width / 1024, PROPTYPE_INT_SCROLL, 0, 1000000},
|
||||
{"Height", pSource->m_Shape.m_Rectangle.m_Height / 1024, PROPTYPE_INT_SCROLL, 0, 1000000},
|
||||
{nullptr},
|
||||
};
|
||||
|
||||
static int s_aRectangleIds[NUM_RECTANGLE_PROPS] = {0};
|
||||
static int s_aRectangleIds[(int)ERectangleShapeProp::NUM_RECTANGLE_PROPS] = {0};
|
||||
NewVal = 0;
|
||||
Prop = pEditor->DoProperties(&View, aRectangleProps, s_aRectangleIds, &NewVal);
|
||||
if(Prop != -1)
|
||||
auto [LocalState, LocalProp] = pEditor->DoPropertiesWithState<ERectangleShapeProp>(&View, aRectangleProps, s_aRectangleIds, &NewVal);
|
||||
if(LocalProp != ERectangleShapeProp::PROP_NONE)
|
||||
{
|
||||
pEditor->m_Map.OnModify();
|
||||
}
|
||||
|
||||
if(Prop == PROP_RECTANGLE_WIDTH)
|
||||
static CSoundSourceRectShapePropTracker s_ShapeTracker(pEditor);
|
||||
s_ShapeTracker.Begin(pSource, LocalProp, LocalState);
|
||||
|
||||
if(LocalProp == ERectangleShapeProp::PROP_RECTANGLE_WIDTH)
|
||||
{
|
||||
pSource->m_Shape.m_Rectangle.m_Width = NewVal * 1024;
|
||||
}
|
||||
else if(Prop == PROP_RECTANGLE_HEIGHT)
|
||||
else if(LocalProp == ERectangleShapeProp::PROP_RECTANGLE_HEIGHT)
|
||||
{
|
||||
pSource->m_Shape.m_Rectangle.m_Height = NewVal * 1024;
|
||||
}
|
||||
|
||||
s_ShapeTracker.End(LocalProp, LocalState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1208,22 +1195,9 @@ CUI::EPopupMenuFunctionResult CEditor::PopupPoint(void *pContext, CUIRect View,
|
|||
if(!in_range<int>(pEditor->m_SelectedQuadIndex, 0, vpQuads.size() - 1))
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
CQuad *pCurrentQuad = vpQuads[pEditor->m_SelectedQuadIndex];
|
||||
std::shared_ptr<CLayerQuads> pLayer = std::static_pointer_cast<CLayerQuads>(pEditor->GetSelectedLayerType(0, LAYERTYPE_QUADS));
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_POS_X = 0,
|
||||
PROP_POS_Y,
|
||||
PROP_COLOR,
|
||||
PROP_TEX_U,
|
||||
PROP_TEX_V,
|
||||
NUM_PROPS,
|
||||
};
|
||||
|
||||
int Color = 0;
|
||||
Color |= pCurrentQuad->m_aColors[pEditor->m_SelectedQuadPoint].r << 24;
|
||||
Color |= pCurrentQuad->m_aColors[pEditor->m_SelectedQuadPoint].g << 16;
|
||||
Color |= pCurrentQuad->m_aColors[pEditor->m_SelectedQuadPoint].b << 8;
|
||||
Color |= pCurrentQuad->m_aColors[pEditor->m_SelectedQuadPoint].a;
|
||||
int Color = PackColor(pCurrentQuad->m_aColors[pEditor->m_SelectedQuadPoint]);
|
||||
|
||||
const int X = fx2i(pCurrentQuad->m_aPoints[pEditor->m_SelectedQuadPoint].x);
|
||||
const int Y = fx2i(pCurrentQuad->m_aPoints[pEditor->m_SelectedQuadPoint].y);
|
||||
|
@ -1239,29 +1213,35 @@ CUI::EPopupMenuFunctionResult CEditor::PopupPoint(void *pContext, CUIRect View,
|
|||
{nullptr},
|
||||
};
|
||||
|
||||
static int s_aIds[NUM_PROPS] = {0};
|
||||
static int s_aIds[(int)EQuadPointProp::NUM_PROPS] = {0};
|
||||
int NewVal = 0;
|
||||
int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal);
|
||||
if(Prop != -1)
|
||||
auto PropRes = pEditor->DoPropertiesWithState<EQuadPointProp>(&View, aProps, s_aIds, &NewVal);
|
||||
EQuadPointProp Prop = PropRes.m_Value;
|
||||
if(Prop != EQuadPointProp::PROP_NONE)
|
||||
{
|
||||
pEditor->m_Map.OnModify();
|
||||
if(PropRes.m_State == EEditState::START || PropRes.m_State == EEditState::ONE_GO)
|
||||
{
|
||||
pEditor->m_QuadTracker.BeginQuadPointPropTrack(pLayer, pEditor->m_vSelectedQuads, pEditor->m_SelectedQuadPoints);
|
||||
pEditor->m_QuadTracker.AddQuadPointPropTrack(Prop);
|
||||
}
|
||||
}
|
||||
|
||||
for(CQuad *pQuad : vpQuads)
|
||||
{
|
||||
if(Prop == PROP_POS_X)
|
||||
if(Prop == EQuadPointProp::PROP_POS_X)
|
||||
{
|
||||
for(int v = 0; v < 4; v++)
|
||||
if(pEditor->IsQuadCornerSelected(v))
|
||||
pQuad->m_aPoints[v].x = i2fx(fx2i(pQuad->m_aPoints[v].x) + NewVal - X);
|
||||
}
|
||||
else if(Prop == PROP_POS_Y)
|
||||
else if(Prop == EQuadPointProp::PROP_POS_Y)
|
||||
{
|
||||
for(int v = 0; v < 4; v++)
|
||||
if(pEditor->IsQuadCornerSelected(v))
|
||||
pQuad->m_aPoints[v].y = i2fx(fx2i(pQuad->m_aPoints[v].y) + NewVal - Y);
|
||||
}
|
||||
else if(Prop == PROP_COLOR)
|
||||
else if(Prop == EQuadPointProp::PROP_COLOR)
|
||||
{
|
||||
for(int v = 0; v < 4; v++)
|
||||
{
|
||||
|
@ -1274,13 +1254,13 @@ CUI::EPopupMenuFunctionResult CEditor::PopupPoint(void *pContext, CUIRect View,
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(Prop == PROP_TEX_U)
|
||||
else if(Prop == EQuadPointProp::PROP_TEX_U)
|
||||
{
|
||||
for(int v = 0; v < 4; v++)
|
||||
if(pEditor->IsQuadCornerSelected(v))
|
||||
pQuad->m_aTexcoords[v].x = f2fx(fx2f(pQuad->m_aTexcoords[v].x) + (NewVal - TextureU) / 1024.0f);
|
||||
}
|
||||
else if(Prop == PROP_TEX_V)
|
||||
else if(Prop == EQuadPointProp::PROP_TEX_V)
|
||||
{
|
||||
for(int v = 0; v < 4; v++)
|
||||
if(pEditor->IsQuadCornerSelected(v))
|
||||
|
@ -1288,12 +1268,24 @@ CUI::EPopupMenuFunctionResult CEditor::PopupPoint(void *pContext, CUIRect View,
|
|||
}
|
||||
}
|
||||
|
||||
if(Prop != EQuadPointProp::PROP_NONE)
|
||||
{
|
||||
pEditor->m_Map.OnModify();
|
||||
if(PropRes.m_State == EEditState::END || PropRes.m_State == EEditState::ONE_GO)
|
||||
{
|
||||
pEditor->m_QuadTracker.EndQuadPointPropTrack(Prop);
|
||||
}
|
||||
}
|
||||
|
||||
return CUI::POPUP_KEEP_OPEN;
|
||||
}
|
||||
|
||||
CUI::EPopupMenuFunctionResult CEditor::PopupEnvPoint(void *pContext, CUIRect View, bool Active)
|
||||
{
|
||||
CEditor *pEditor = static_cast<CEditor *>(pContext);
|
||||
if(pEditor->m_SelectedEnvelope < 0 || pEditor->m_SelectedEnvelope >= (int)pEditor->m_Map.m_vpEnvelopes.size())
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
|
||||
const float RowHeight = 12.0f;
|
||||
CUIRect Row, Label, EditBox;
|
||||
|
||||
|
@ -1309,14 +1301,41 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEnvPoint(void *pContext, CUIRect Vie
|
|||
Row.VSplitLeft(10.0f, nullptr, &EditBox);
|
||||
pEditor->UI()->DoLabel(&Label, "Color:", RowHeight - 2.0f, TEXTALIGN_ML);
|
||||
|
||||
const auto [SelectedIndex, _] = pEditor->m_vSelectedEnvelopePoints.front();
|
||||
const auto SelectedPoint = pEditor->m_vSelectedEnvelopePoints.front();
|
||||
const int SelectedIndex = SelectedPoint.first;
|
||||
auto *pValues = pEnvelope->m_vPoints[SelectedIndex].m_aValues;
|
||||
const ColorRGBA Color = ColorRGBA(fx2f(pValues[0]), fx2f(pValues[1]), fx2f(pValues[2]), fx2f(pValues[3]));
|
||||
const auto &&SetColor = [&](ColorRGBA NewColor) {
|
||||
if(Color == NewColor)
|
||||
if(Color == NewColor && pEditor->m_ColorPickerPopupContext.m_State == EEditState::EDITING)
|
||||
return;
|
||||
|
||||
static int s_Values[4];
|
||||
|
||||
if(pEditor->m_ColorPickerPopupContext.m_State == EEditState::START || pEditor->m_ColorPickerPopupContext.m_State == EEditState::ONE_GO)
|
||||
{
|
||||
for(int Channel = 0; Channel < 4; ++Channel)
|
||||
s_Values[Channel] = pValues[Channel];
|
||||
}
|
||||
|
||||
for(int Channel = 0; Channel < 4; ++Channel)
|
||||
{
|
||||
pValues[Channel] = f2fx(NewColor[Channel]);
|
||||
}
|
||||
|
||||
if(pEditor->m_ColorPickerPopupContext.m_State == EEditState::END || pEditor->m_ColorPickerPopupContext.m_State == EEditState::ONE_GO)
|
||||
{
|
||||
std::vector<std::shared_ptr<IEditorAction>> vpActions(4);
|
||||
|
||||
for(int Channel = 0; Channel < 4; ++Channel)
|
||||
{
|
||||
vpActions[Channel] = std::make_shared<CEditorActionEnvelopeEditPoint>(pEditor, pEditor->m_SelectedEnvelope, SelectedIndex, Channel, CEditorActionEnvelopeEditPoint::EEditType::VALUE, s_Values[Channel], f2fx(NewColor[Channel]));
|
||||
}
|
||||
|
||||
char aDisplay[256];
|
||||
str_format(aDisplay, sizeof(aDisplay), "Edit color of point %d of envelope %d", SelectedIndex, pEditor->m_SelectedEnvelope);
|
||||
pEditor->m_EnvelopeEditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(pEditor, vpActions, aDisplay));
|
||||
}
|
||||
|
||||
pEditor->m_UpdateEnvPointInfo = true;
|
||||
pEditor->m_Map.OnModify();
|
||||
};
|
||||
|
@ -1327,37 +1346,23 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEnvPoint(void *pContext, CUIRect Vie
|
|||
static CLineInputNumber s_CurValueInput;
|
||||
static CLineInputNumber s_CurTimeInput;
|
||||
|
||||
static float s_CurrentTime = 0;
|
||||
static float s_CurrentValue = 0;
|
||||
|
||||
if(pEditor->m_UpdateEnvPointInfo)
|
||||
{
|
||||
pEditor->m_UpdateEnvPointInfo = false;
|
||||
|
||||
int CurrentTime;
|
||||
int CurrentValue;
|
||||
if(pEditor->IsTangentInSelected())
|
||||
{
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentInPoint;
|
||||
|
||||
CurrentTime = pEnvelope->m_vPoints[SelectedIndex].m_Time + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaX[SelectedChannel];
|
||||
CurrentValue = pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel] + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaY[SelectedChannel];
|
||||
}
|
||||
else if(pEditor->IsTangentOutSelected())
|
||||
{
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentOutPoint;
|
||||
|
||||
CurrentTime = pEnvelope->m_vPoints[SelectedIndex].m_Time + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaX[SelectedChannel];
|
||||
CurrentValue = pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel] + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaY[SelectedChannel];
|
||||
}
|
||||
else
|
||||
{
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_vSelectedEnvelopePoints.front();
|
||||
|
||||
CurrentTime = pEnvelope->m_vPoints[SelectedIndex].m_Time;
|
||||
CurrentValue = pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel];
|
||||
}
|
||||
auto TimeAndValue = pEditor->EnvGetSelectedTimeAndValue();
|
||||
int CurrentTime = TimeAndValue.first;
|
||||
int CurrentValue = TimeAndValue.second;
|
||||
|
||||
// update displayed text
|
||||
s_CurValueInput.SetFloat(fx2f(CurrentValue));
|
||||
s_CurTimeInput.SetFloat(CurrentTime / 1000.0f);
|
||||
|
||||
s_CurrentTime = s_CurTimeInput.GetFloat();
|
||||
s_CurrentValue = s_CurValueInput.GetFloat();
|
||||
}
|
||||
|
||||
View.HSplitTop(RowHeight, &Row, &View);
|
||||
|
@ -1377,53 +1382,46 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEnvPoint(void *pContext, CUIRect Vie
|
|||
{
|
||||
float CurrentTime = s_CurTimeInput.GetFloat();
|
||||
float CurrentValue = s_CurValueInput.GetFloat();
|
||||
if(pEditor->IsTangentInSelected())
|
||||
if(!(absolute(CurrentTime - s_CurrentTime) < 0.0001f && absolute(CurrentValue - s_CurrentValue) < 0.0001f))
|
||||
{
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentInPoint;
|
||||
auto [OldTime, OldValue] = pEditor->EnvGetSelectedTimeAndValue();
|
||||
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaX[SelectedChannel] = minimum<int>(CurrentTime * 1000.0f - pEnvelope->m_vPoints[SelectedIndex].m_Time, 0);
|
||||
CurrentTime = (pEnvelope->m_vPoints[SelectedIndex].m_Time + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaX[SelectedChannel]) / 1000.0f;
|
||||
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaY[SelectedChannel] = f2fx(CurrentValue) - pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel];
|
||||
}
|
||||
else if(pEditor->IsTangentOutSelected())
|
||||
{
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentOutPoint;
|
||||
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaX[SelectedChannel] = maximum<int>(CurrentTime * 1000.0f - pEnvelope->m_vPoints[SelectedIndex].m_Time, 0);
|
||||
CurrentTime = (pEnvelope->m_vPoints[SelectedIndex].m_Time + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaX[SelectedChannel]) / 1000.0f;
|
||||
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaY[SelectedChannel] = f2fx(CurrentValue) - pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel];
|
||||
}
|
||||
else
|
||||
{
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_vSelectedEnvelopePoints.front();
|
||||
if(pEnvelope->GetChannels() == 4)
|
||||
CurrentValue = clamp(CurrentValue, 0.0f, 1.0f);
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_aValues[SelectedChannel] = f2fx(CurrentValue);
|
||||
|
||||
if(SelectedIndex != 0)
|
||||
if(pEditor->IsTangentInSelected())
|
||||
{
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Time = CurrentTime * 1000.0f;
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentInPoint;
|
||||
|
||||
if(pEnvelope->m_vPoints[SelectedIndex].m_Time < pEnvelope->m_vPoints[SelectedIndex - 1].m_Time)
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Time = pEnvelope->m_vPoints[SelectedIndex - 1].m_Time + 1;
|
||||
if(static_cast<size_t>(SelectedIndex) + 1 != pEnvelope->m_vPoints.size() && pEnvelope->m_vPoints[SelectedIndex].m_Time > pEnvelope->m_vPoints[SelectedIndex + 1].m_Time)
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Time = pEnvelope->m_vPoints[SelectedIndex + 1].m_Time - 1;
|
||||
pEditor->m_EnvelopeEditorHistory.Execute(std::make_shared<CEditorActionEditEnvelopePointValue>(pEditor, pEditor->m_SelectedEnvelope, SelectedIndex, SelectedChannel, CEditorActionEditEnvelopePointValue::EType::TANGENT_IN, static_cast<int>(OldTime * 1000.0f), f2fx(OldValue), static_cast<int>(CurrentTime * 1000.0f), f2fx(CurrentValue)));
|
||||
CurrentTime = (pEnvelope->m_vPoints[SelectedIndex].m_Time + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaX[SelectedChannel]) / 1000.0f;
|
||||
}
|
||||
else if(pEditor->IsTangentOutSelected())
|
||||
{
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentOutPoint;
|
||||
|
||||
CurrentTime = pEnvelope->m_vPoints[SelectedIndex].m_Time / 1000.0f;
|
||||
pEditor->m_EnvelopeEditorHistory.Execute(std::make_shared<CEditorActionEditEnvelopePointValue>(pEditor, pEditor->m_SelectedEnvelope, SelectedIndex, SelectedChannel, CEditorActionEditEnvelopePointValue::EType::TANGENT_OUT, static_cast<int>(OldTime * 1000.0f), f2fx(OldValue), static_cast<int>(CurrentTime * 1000.0f), f2fx(CurrentValue)));
|
||||
CurrentTime = (pEnvelope->m_vPoints[SelectedIndex].m_Time + pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaX[SelectedChannel]) / 1000.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentTime = 0.0f;
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Time = 0.0f;
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_vSelectedEnvelopePoints.front();
|
||||
pEditor->m_EnvelopeEditorHistory.Execute(std::make_shared<CEditorActionEditEnvelopePointValue>(pEditor, pEditor->m_SelectedEnvelope, SelectedIndex, SelectedChannel, CEditorActionEditEnvelopePointValue::EType::POINT, static_cast<int>(OldTime * 1000.0f), f2fx(OldValue), static_cast<int>(CurrentTime * 1000.0f), f2fx(CurrentValue)));
|
||||
|
||||
if(SelectedIndex != 0)
|
||||
{
|
||||
CurrentTime = pEnvelope->m_vPoints[SelectedIndex].m_Time / 1000.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentTime = 0.0f;
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Time = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
s_CurTimeInput.SetFloat(static_cast<int>(CurrentTime * 1000.0f) / 1000.0f);
|
||||
s_CurValueInput.SetFloat(fx2f(f2fx(CurrentValue)));
|
||||
|
||||
s_CurrentTime = s_CurTimeInput.GetFloat();
|
||||
s_CurrentValue = s_CurValueInput.GetFloat();
|
||||
}
|
||||
|
||||
s_CurTimeInput.SetFloat(static_cast<int>(CurrentTime * 1000.0f) / 1000.0f);
|
||||
s_CurValueInput.SetFloat(fx2f(f2fx(CurrentValue)));
|
||||
|
||||
pEditor->m_Map.OnModify();
|
||||
}
|
||||
|
||||
View.HSplitTop(6.0f, nullptr, &View);
|
||||
|
@ -1436,24 +1434,18 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEnvPoint(void *pContext, CUIRect Vie
|
|||
if(pEditor->IsTangentInSelected())
|
||||
{
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentInPoint;
|
||||
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaX[SelectedChannel] = 0.0f;
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aInTangentDeltaY[SelectedChannel] = 0.0f;
|
||||
pEditor->m_EnvelopeEditorHistory.Execute(std::make_shared<CEditorActionResetEnvelopePointTangent>(pEditor, pEditor->m_SelectedEnvelope, SelectedIndex, SelectedChannel, true));
|
||||
}
|
||||
else if(pEditor->IsTangentOutSelected())
|
||||
{
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_SelectedTangentOutPoint;
|
||||
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaX[SelectedChannel] = 0.0f;
|
||||
pEnvelope->m_vPoints[SelectedIndex].m_Bezier.m_aOutTangentDeltaY[SelectedChannel] = 0.0f;
|
||||
pEditor->m_EnvelopeEditorHistory.Execute(std::make_shared<CEditorActionResetEnvelopePointTangent>(pEditor, pEditor->m_SelectedEnvelope, SelectedIndex, SelectedChannel, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto [SelectedIndex, SelectedChannel] = pEditor->m_vSelectedEnvelopePoints.front();
|
||||
|
||||
pEnvelope->m_vPoints.erase(pEnvelope->m_vPoints.begin() + SelectedIndex);
|
||||
pEditor->m_EnvelopeEditorHistory.Execute(std::make_shared<CEditorActionDeleteEnvelopePoint>(pEditor, pEditor->m_SelectedEnvelope, SelectedIndex));
|
||||
}
|
||||
pEditor->m_Map.OnModify();
|
||||
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
@ -1515,6 +1507,8 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEnvPointCurveType(void *pContext, CU
|
|||
if(pEditor->DoButton_MenuItem(&s_ButtonSmoothID, "Smooth", 0, &ButtonSmooth))
|
||||
CurveType = CURVETYPE_SMOOTH;
|
||||
|
||||
std::vector<std::shared_ptr<IEditorAction>> vpActions;
|
||||
|
||||
if(CurveType >= 0)
|
||||
{
|
||||
std::shared_ptr<CEnvelope> pEnvelope = pEditor->m_Map.m_vpEnvelopes.at(pEditor->m_SelectedEnvelope);
|
||||
|
@ -1551,13 +1545,20 @@ CUI::EPopupMenuFunctionResult CEditor::PopupEnvPointCurveType(void *pContext, CU
|
|||
CEnvPoint &CurrentPoint = pEnvelope->m_vPoints[SelectedIndex];
|
||||
ColorRGBA Channels;
|
||||
HelperEnvelope.Eval(CurrentPoint.m_Time / 1000.0f, Channels);
|
||||
int PrevValue = CurrentPoint.m_aValues[c];
|
||||
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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!vpActions.empty())
|
||||
{
|
||||
pEditor->m_EnvelopeEditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(pEditor, vpActions, "Project points"));
|
||||
}
|
||||
|
||||
pEditor->m_Map.OnModify();
|
||||
return CUI::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "editor.h"
|
||||
#include "editor_actions.h"
|
||||
|
||||
#include <game/editor/mapitems/image.h>
|
||||
|
||||
|
@ -184,10 +185,15 @@ static void SetTilelayerIndices(const std::shared_ptr<CLayerTiles> &pLayer, cons
|
|||
}
|
||||
}
|
||||
|
||||
void CEditor::AddTileart()
|
||||
void CEditor::AddTileart(bool IgnoreHistory)
|
||||
{
|
||||
char aTileArtFileName[IO_MAX_PATH_LENGTH];
|
||||
IStorage::StripPathAndExtension(m_aTileartFilename, aTileArtFileName, sizeof(aTileArtFileName));
|
||||
|
||||
std::shared_ptr<CLayerGroup> pGroup = m_Map.NewGroup();
|
||||
str_copy(pGroup->m_aName, m_aTileartFilename);
|
||||
str_copy(pGroup->m_aName, aTileArtFileName);
|
||||
|
||||
int ImageCount = m_Map.m_vpImages.size();
|
||||
|
||||
auto vUniqueColors = GetUniqueColors(m_TileartImageInfo);
|
||||
auto vaColorGroups = GroupColors(vUniqueColors);
|
||||
|
@ -195,11 +201,16 @@ void CEditor::AddTileart()
|
|||
char aImageName[IO_MAX_PATH_LENGTH];
|
||||
for(size_t i = 0; i < vColorImages.size(); i++)
|
||||
{
|
||||
str_format(aImageName, sizeof(aImageName), "%s %" PRIzu, m_aTileartFilename, i + 1);
|
||||
str_format(aImageName, sizeof(aImageName), "%s %" PRIzu, aTileArtFileName, i + 1);
|
||||
std::shared_ptr<CLayerTiles> pLayer = AddLayerWithImage(this, pGroup, m_TileartImageInfo.m_Width, m_TileartImageInfo.m_Height, vColorImages[i], aImageName);
|
||||
SetTilelayerIndices(pLayer, vaColorGroups[i], m_TileartImageInfo);
|
||||
}
|
||||
SortImages();
|
||||
auto IndexMap = SortImages();
|
||||
|
||||
if(!IgnoreHistory)
|
||||
{
|
||||
m_EditorHistory.RecordAction(std::make_shared<CEditorActionTileArt>(this, ImageCount, m_aTileartFilename, IndexMap));
|
||||
}
|
||||
|
||||
free(m_TileartImageInfo.m_pData);
|
||||
m_TileartImageInfo.m_pData = nullptr;
|
||||
|
@ -237,7 +248,7 @@ bool CEditor::CallbackAddTileart(const char *pFilepath, int StorageType, void *p
|
|||
return false;
|
||||
}
|
||||
|
||||
IStorage::StripPathAndExtension(pFilepath, pEditor->m_aTileartFilename, sizeof(pEditor->m_aTileartFilename));
|
||||
str_copy(pEditor->m_aTileartFilename, pFilepath);
|
||||
if(pEditor->m_TileartImageInfo.m_Width * pEditor->m_TileartImageInfo.m_Height > 10'000)
|
||||
{
|
||||
pEditor->m_PopupEventType = CEditor::POPEVENT_PIXELART_BIG_IMAGE;
|
||||
|
|
|
@ -150,3 +150,13 @@ bool IsCreditsTile(int TileIndex)
|
|||
(TILE_CREDITS_7 == TileIndex) ||
|
||||
(TILE_CREDITS_8 == TileIndex));
|
||||
}
|
||||
|
||||
int PackColor(CColor Color)
|
||||
{
|
||||
int Res = 0;
|
||||
Res |= Color.r << 24;
|
||||
Res |= Color.g << 16;
|
||||
Res |= Color.b << 8;
|
||||
Res |= Color.a;
|
||||
return Res;
|
||||
}
|
||||
|
|
|
@ -578,5 +578,6 @@ bool IsValidTuneTile(int Index);
|
|||
bool IsValidEntity(int Index);
|
||||
bool IsRotatableTile(int Index);
|
||||
bool IsCreditsTile(int TileIndex);
|
||||
int PackColor(CColor Color);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue