From 0c6f187e3bc3bb617a1985b41e6fc9e4acad2319 Mon Sep 17 00:00:00 2001 From: Choupom Date: Tue, 19 Apr 2011 10:34:51 +0200 Subject: renamed editor files --- src/game/editor/ed_editor.cpp | 3428 ------------------------------------ src/game/editor/ed_editor.h | 741 -------- src/game/editor/ed_io.cpp | 638 ------- src/game/editor/ed_layer_game.cpp | 22 - src/game/editor/ed_layer_quads.cpp | 263 --- src/game/editor/ed_layer_tiles.cpp | 460 ----- src/game/editor/ed_popups.cpp | 739 -------- src/game/editor/editor.cpp | 3428 ++++++++++++++++++++++++++++++++++++ src/game/editor/editor.h | 741 ++++++++ src/game/editor/io.cpp | 638 +++++++ src/game/editor/layer_game.cpp | 22 + src/game/editor/layer_quads.cpp | 263 +++ src/game/editor/layer_tiles.cpp | 460 +++++ src/game/editor/popups.cpp | 739 ++++++++ 14 files changed, 6291 insertions(+), 6291 deletions(-) delete mode 100644 src/game/editor/ed_editor.cpp delete mode 100644 src/game/editor/ed_editor.h delete mode 100644 src/game/editor/ed_io.cpp delete mode 100644 src/game/editor/ed_layer_game.cpp delete mode 100644 src/game/editor/ed_layer_quads.cpp delete mode 100644 src/game/editor/ed_layer_tiles.cpp delete mode 100644 src/game/editor/ed_popups.cpp create mode 100644 src/game/editor/editor.cpp create mode 100644 src/game/editor/editor.h create mode 100644 src/game/editor/io.cpp create mode 100644 src/game/editor/layer_game.cpp create mode 100644 src/game/editor/layer_quads.cpp create mode 100644 src/game/editor/layer_tiles.cpp create mode 100644 src/game/editor/popups.cpp diff --git a/src/game/editor/ed_editor.cpp b/src/game/editor/ed_editor.cpp deleted file mode 100644 index 2be4da76..00000000 --- a/src/game/editor/ed_editor.cpp +++ /dev/null @@ -1,3428 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "ed_editor.h" -#include - -#include - -int CEditor::ms_CheckerTexture; -int CEditor::ms_BackgroundTexture; -int CEditor::ms_CursorTexture; -int CEditor::ms_EntitiesTexture; -const void* CEditor::ms_pUiGotContext; - -enum -{ - BUTTON_CONTEXT=1, -}; - -CEditorImage::~CEditorImage() -{ - m_pEditor->Graphics()->UnloadTexture(m_TexID); -} - -CLayerGroup::CLayerGroup() -{ - m_pName = ""; - m_Visible = true; - m_SaveToMap = true; - m_GameGroup = false; - m_OffsetX = 0; - m_OffsetY = 0; - m_ParallaxX = 100; - m_ParallaxY = 100; - - m_UseClipping = 0; - m_ClipX = 0; - m_ClipY = 0; - m_ClipW = 0; - m_ClipH = 0; -} - -CLayerGroup::~CLayerGroup() -{ - Clear(); -} - -void CLayerGroup::Convert(CUIRect *pRect) -{ - pRect->x += m_OffsetX; - pRect->y += m_OffsetY; -} - -void CLayerGroup::Mapping(float *pPoints) -{ - m_pMap->m_pEditor->RenderTools()->MapscreenToWorld( - m_pMap->m_pEditor->m_WorldOffsetX, m_pMap->m_pEditor->m_WorldOffsetY, - m_ParallaxX/100.0f, m_ParallaxY/100.0f, - m_OffsetX, m_OffsetY, - m_pMap->m_pEditor->Graphics()->ScreenAspect(), m_pMap->m_pEditor->m_WorldZoom, pPoints); - - pPoints[0] += m_pMap->m_pEditor->m_EditorOffsetX; - pPoints[1] += m_pMap->m_pEditor->m_EditorOffsetY; - pPoints[2] += m_pMap->m_pEditor->m_EditorOffsetX; - pPoints[3] += m_pMap->m_pEditor->m_EditorOffsetY; -} - -void CLayerGroup::MapScreen() -{ - float aPoints[4]; - Mapping(aPoints); - m_pMap->m_pEditor->Graphics()->MapScreen(aPoints[0], aPoints[1], aPoints[2], aPoints[3]); -} - -void CLayerGroup::Render() -{ - MapScreen(); - IGraphics *pGraphics = m_pMap->m_pEditor->Graphics(); - - if(m_UseClipping) - { - float aPoints[4]; - m_pMap->m_pGameGroup->Mapping(aPoints); - float x0 = (m_ClipX - aPoints[0]) / (aPoints[2]-aPoints[0]); - float y0 = (m_ClipY - aPoints[1]) / (aPoints[3]-aPoints[1]); - float x1 = ((m_ClipX+m_ClipW) - aPoints[0]) / (aPoints[2]-aPoints[0]); - float y1 = ((m_ClipY+m_ClipH) - aPoints[1]) / (aPoints[3]-aPoints[1]); - - pGraphics->ClipEnable((int)(x0*pGraphics->ScreenWidth()), (int)(y0*pGraphics->ScreenHeight()), - (int)((x1-x0)*pGraphics->ScreenWidth()), (int)((y1-y0)*pGraphics->ScreenHeight())); - } - - for(int i = 0; i < m_lLayers.size(); i++) - { - if(m_lLayers[i]->m_Visible && m_lLayers[i] != m_pMap->m_pGameLayer) - { - if(m_pMap->m_pEditor->m_ShowDetail || !(m_lLayers[i]->m_Flags&LAYERFLAG_DETAIL)) - m_lLayers[i]->Render(); - } - } - - pGraphics->ClipDisable(); -} - -void CLayerGroup::AddLayer(CLayer *l) -{ - m_pMap->m_Modified = true; - m_lLayers.add(l); -} - -void CLayerGroup::DeleteLayer(int Index) -{ - if(Index < 0 || Index >= m_lLayers.size()) return; - delete m_lLayers[Index]; - m_lLayers.remove_index(Index); - m_pMap->m_Modified = true; -} - -void CLayerGroup::GetSize(float *w, float *h) -{ - *w = 0; *h = 0; - for(int i = 0; i < m_lLayers.size(); i++) - { - float lw, lh; - m_lLayers[i]->GetSize(&lw, &lh); - *w = max(*w, lw); - *h = max(*h, lh); - } -} - - -int CLayerGroup::SwapLayers(int Index0, int Index1) -{ - if(Index0 < 0 || Index0 >= m_lLayers.size()) return Index0; - if(Index1 < 0 || Index1 >= m_lLayers.size()) return Index0; - if(Index0 == Index1) return Index0; - m_pMap->m_Modified = true; - swap(m_lLayers[Index0], m_lLayers[Index1]); - return Index1; -} - -void CEditorImage::AnalyseTileFlags() -{ - mem_zero(m_aTileFlags, sizeof(m_aTileFlags)); - - int tw = m_Width/16; // tilesizes - int th = m_Height/16; - if ( tw == th ) - { - unsigned char *pPixelData = (unsigned char *)m_pData; - - int TileID = 0; - for(int ty = 0; ty < 16; ty++) - for(int tx = 0; tx < 16; tx++, TileID++) - { - bool Opaque = true; - for(int x = 0; x < tw; x++) - for(int y = 0; y < th; y++) - { - int p = (ty*tw+y)*m_Width + tx*tw+x; - if(pPixelData[p*4+3] < 250) - { - Opaque = false; - break; - } - } - - if(Opaque) - m_aTileFlags[TileID] |= TILEFLAG_OPAQUE; - } - } - -} - -/******************************************************** - OTHER -*********************************************************/ - -// copied from gc_menu.cpp, should be more generalized -//extern int ui_do_edit_box(void *id, const CUIRect *rect, char *str, int str_size, float font_size, bool hidden=false); - -int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden) -{ - int Inside = UI()->MouseInside(pRect); - bool ReturnValue = false; - static int s_AtIndex = 0; - - if(UI()->LastActiveItem() == pID) - { - int Len = str_length(pStr); - - if(Inside && UI()->MouseButton(0)) - { - int MxRel = (int)(UI()->MouseX() - pRect->x); - - for (int i = 1; i <= Len; i++) - { - if (TextRender()->TextWidth(0, FontSize, pStr, i) + 10 > MxRel) - { - s_AtIndex = i - 1; - break; - } - - if (i == Len) - s_AtIndex = Len; - } - } - - for(int i = 0; i < Input()->NumEvents(); i++) - { - Len = str_length(pStr); - ReturnValue |= CLineInput::Manipulate(Input()->GetEvent(i), pStr, StrSize, &Len, &s_AtIndex); - } - } - - bool JustGotActive = false; - - if(UI()->ActiveItem() == pID) - { - if(!UI()->MouseButton(0)) - UI()->SetActiveItem(0); - } - else if(UI()->HotItem() == pID) - { - if(UI()->MouseButton(0)) - { - if (UI()->LastActiveItem() != pID) - JustGotActive = true; - UI()->SetActiveItem(pID); - } - } - - if(Inside) - UI()->SetHotItem(pID); - - CUIRect Textbox = *pRect; - RenderTools()->DrawUIRect(&Textbox, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 3.0f); - Textbox.VMargin(3.0f, &Textbox); - - const char *pDisplayStr = pStr; - char aStars[128]; - - if(Hidden) - { - unsigned s = str_length(pStr); - if(s >= sizeof(aStars)) - s = sizeof(aStars)-1; - for(unsigned int i = 0; i < s; ++i) - aStars[i] = '*'; - aStars[s] = 0; - pDisplayStr = aStars; - } - - UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1); - - //TODO: make it blink - if(UI()->LastActiveItem() == pID && !JustGotActive) - { - float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex); - Textbox = *pRect; - Textbox.VSplitLeft(2.0f, 0, &Textbox); - Textbox.x += w*UI()->Scale(); - Textbox.y -= FontSize/10.f; - - UI()->DoLabel(&Textbox, "|", FontSize*1.1f, -1); - } - - return ReturnValue; -} - -vec4 CEditor::ButtonColorMul(const void *pID) -{ - if(UI()->ActiveItem() == pID) - return vec4(1,1,1,0.5f); - else if(UI()->HotItem() == pID) - return vec4(1,1,1,1.5f); - return vec4(1,1,1,1); -} - -float CEditor::UiDoScrollbarV(const void *pID, const CUIRect *pRect, float Current) -{ - CUIRect Handle; - static float s_OffsetY; - pRect->HSplitTop(33, &Handle, 0); - - Handle.y += (pRect->h-Handle.h)*Current; - - // logic - float Ret = Current; - int Inside = UI()->MouseInside(&Handle); - - if(UI()->ActiveItem() == pID) - { - if(!UI()->MouseButton(0)) - UI()->SetActiveItem(0); - - float Min = pRect->y; - float Max = pRect->h-Handle.h; - float Cur = UI()->MouseY()-s_OffsetY; - Ret = (Cur-Min)/Max; - if(Ret < 0.0f) Ret = 0.0f; - if(Ret > 1.0f) Ret = 1.0f; - } - else if(UI()->HotItem() == pID) - { - if(UI()->MouseButton(0)) - { - UI()->SetActiveItem(pID); - s_OffsetY = UI()->MouseY()-Handle.y; - } - } - - if(Inside) - UI()->SetHotItem(pID); - - // render - CUIRect Rail; - pRect->VMargin(5.0f, &Rail); - RenderTools()->DrawUIRect(&Rail, vec4(1,1,1,0.25f), 0, 0.0f); - - CUIRect Slider = Handle; - Slider.w = Rail.x-Slider.x; - RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f), CUI::CORNER_L, 2.5f); - Slider.x = Rail.x+Rail.w; - RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f), CUI::CORNER_R, 2.5f); - - Slider = Handle; - Slider.Margin(5.0f, &Slider); - RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f)*ButtonColorMul(pID), CUI::CORNER_ALL, 2.5f); - - return Ret; -} - -vec4 CEditor::GetButtonColor(const void *pID, int Checked) -{ - if(Checked < 0) - return vec4(0,0,0,0.5f); - - if(Checked > 0) - { - if(UI()->HotItem() == pID) - return vec4(1,0,0,0.75f); - return vec4(1,0,0,0.5f); - } - - if(UI()->HotItem() == pID) - return vec4(1,1,1,0.75f); - return vec4(1,1,1,0.5f); -} - -int CEditor::DoButton_Editor_Common(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) -{ - if(UI()->MouseInside(pRect)) - { - if(Flags&BUTTON_CONTEXT) - ms_pUiGotContext = pID; - if(m_pTooltip) - m_pTooltip = pToolTip; - } - - if(UI()->HotItem() == pID && pToolTip) - m_pTooltip = (const char *)pToolTip; - - return UI()->DoButtonLogic(pID, pText, Checked, pRect); - - // Draw here - //return UI()->DoButton(id, text, checked, r, draw_func, 0); -} - - -int CEditor::DoButton_Editor(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) -{ - RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_ALL, 3.0f); - CUIRect NewRect = *pRect; - NewRect.y += NewRect.h/2.0f-7.0f; - float tw = min(TextRender()->TextWidth(0, 10.0f, pText, -1), NewRect.w); - CTextCursor Cursor; - TextRender()->SetCursor(&Cursor, NewRect.x + NewRect.w/2-tw/2, NewRect.y - 1.0f, 10.0f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); - Cursor.m_LineWidth = NewRect.w; - TextRender()->TextEx(&Cursor, pText, -1); - return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); -} - -int CEditor::DoButton_File(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) -{ - if(Checked) - RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_ALL, 3.0f); - - CUIRect t = *pRect; - t.VMargin(5.0f, &t); - UI()->DoLabel(&t, pText, 10, -1, -1); - return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); -} - -int CEditor::DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) -{ - CUIRect r = *pRect; - RenderTools()->DrawUIRect(&r, vec4(0.5f, 0.5f, 0.5f, 1.0f), CUI::CORNER_T, 3.0f); - - r = *pRect; - r.VMargin(5.0f, &r); - UI()->DoLabel(&r, pText, 10, -1, -1); - return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); -} - -int CEditor::DoButton_MenuItem(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) -{ - if(UI()->HotItem() == pID || Checked) - RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_ALL, 3.0f); - - CUIRect t = *pRect; - t.VMargin(5.0f, &t); - CTextCursor Cursor; - TextRender()->SetCursor(&Cursor, t.x, t.y - 1.0f, 10.0f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); - Cursor.m_LineWidth = t.w; - TextRender()->TextEx(&Cursor, pText, -1); - return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); -} - -int CEditor::DoButton_Tab(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) -{ - RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_T, 5.0f); - CUIRect NewRect = *pRect; - NewRect.y += NewRect.h/2.0f-7.0f; - UI()->DoLabel(&NewRect, pText, 10, 0, -1); - return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); -} - -int CEditor::DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners) -{ - RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), Corners, 3.0f); - CUIRect NewRect = *pRect; - NewRect.y += NewRect.h/2.0f-7.0f; - UI()->DoLabel(&NewRect, pText, 10, 0, -1); - return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); -} - -int CEditor::DoButton_ButtonInc(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) -{ - RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_R, 3.0f); - UI()->DoLabel(pRect, pText?pText:"+", 10, 0, -1); - return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); -} - -int CEditor::DoButton_ButtonDec(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) -{ - RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_L, 3.0f); - UI()->DoLabel(pRect, pText?pText:"-", 10, 0, -1); - return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); -} - -void CEditor::RenderBackground(CUIRect View, int Texture, float Size, float Brightness) -{ - Graphics()->TextureSet(Texture); - Graphics()->BlendNormal(); - Graphics()->QuadsBegin(); - Graphics()->SetColor(Brightness, Brightness, Brightness, 1.0f); - Graphics()->QuadsSetSubset(0,0, View.w/Size, View.h/Size); - IGraphics::CQuadItem QuadItem(View.x, View.y, View.w, View.h); - Graphics()->QuadsDrawTL(&QuadItem, 1); - Graphics()->QuadsEnd(); -} - -int CEditor::UiDoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, int Current, int Min, int Max, int Step, float Scale, const char *pToolTip) -{ - // logic - static float s_Value; - int Ret = 0; - int Inside = UI()->MouseInside(pRect); - - if(UI()->ActiveItem() == pID) - { - if(!UI()->MouseButton(0)) - { - if(Inside) - Ret = 1; - m_LockMouse = false; - UI()->SetActiveItem(0); - } - else - { - if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) - s_Value += m_MouseDeltaX*0.05f; - else - s_Value += m_MouseDeltaX; - - if(absolute(s_Value) > Scale) - { - int Count = (int)(s_Value/Scale); - s_Value = fmod(s_Value, Scale); - Current += Step*Count; - if(Current < Min) - Current = Min; - if(Current > Max) - Current = Max; - } - } - if(pToolTip) - m_pTooltip = pToolTip; - } - else if(UI()->HotItem() == pID) - { - if(UI()->MouseButton(0)) - { - m_LockMouse = true; - s_Value = 0; - UI()->SetActiveItem(pID); - } - if(pToolTip) - m_pTooltip = pToolTip; - } - - if(Inside) - UI()->SetHotItem(pID); - - // render - char aBuf[128]; - str_format(aBuf, sizeof(aBuf),"%s %d", pLabel, Current); - RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, 0), CUI::CORNER_ALL, 5.0f); - pRect->y += pRect->h/2.0f-7.0f; - UI()->DoLabel(pRect, aBuf, 10, 0, -1); - - return Current; -} - -CLayerGroup *CEditor::GetSelectedGroup() -{ - if(m_SelectedGroup >= 0 && m_SelectedGroup < m_Map.m_lGroups.size()) - return m_Map.m_lGroups[m_SelectedGroup]; - return 0x0; -} - -CLayer *CEditor::GetSelectedLayer(int Index) -{ - CLayerGroup *pGroup = GetSelectedGroup(); - if(!pGroup) - return 0x0; - - if(m_SelectedLayer >= 0 && m_SelectedLayer < m_Map.m_lGroups[m_SelectedGroup]->m_lLayers.size()) - return pGroup->m_lLayers[m_SelectedLayer]; - return 0x0; -} - -CLayer *CEditor::GetSelectedLayerType(int Index, int Type) -{ - CLayer *p = GetSelectedLayer(Index); - if(p && p->m_Type == Type) - return p; - return 0x0; -} - -CQuad *CEditor::GetSelectedQuad() -{ - CLayerQuads *ql = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS); - if(!ql) - return 0; - if(m_SelectedQuad >= 0 && m_SelectedQuad < ql->m_lQuads.size()) - return &ql->m_lQuads[m_SelectedQuad]; - return 0; -} - -void CEditor::CallbackOpenMap(const char *pFileName, int StorageType, void *pUser) -{ - CEditor *pEditor = (CEditor*)pUser; - if(pEditor->Load(pFileName, StorageType)) - { - str_copy(pEditor->m_aFileName, pFileName, 512); - pEditor->m_ValidSaveFilename = StorageType == IStorage::TYPE_SAVE && pEditor->m_pFileDialogPath == pEditor->m_aFileDialogCurrentFolder; - pEditor->SortImages(); - pEditor->m_Dialog = DIALOG_NONE; - pEditor->m_Map.m_Modified = false; - } -} -void CEditor::CallbackAppendMap(const char *pFileName, int StorageType, void *pUser) -{ - CEditor *pEditor = (CEditor*)pUser; - if(pEditor->Append(pFileName, StorageType)) - pEditor->m_aFileName[0] = 0; - else - pEditor->SortImages(); - - pEditor->m_Dialog = DIALOG_NONE; -} -void CEditor::CallbackSaveMap(const char *pFileName, int StorageType, void *pUser) -{ - CEditor *pEditor = static_cast(pUser); - char aBuf[1024]; - const int Length = str_length(pFileName); - // add map extension - if(Length <= 4 || pFileName[Length-4] != '.' || str_comp_nocase(pFileName+Length-3, "map")) - { - str_format(aBuf, sizeof(aBuf), "%s.map", pFileName); - pFileName = aBuf; - } - - if(pEditor->Save(pFileName)) - { - str_copy(pEditor->m_aFileName, pFileName, sizeof(pEditor->m_aFileName)); - pEditor->m_ValidSaveFilename = StorageType == IStorage::TYPE_SAVE && pEditor->m_pFileDialogPath == pEditor->m_aFileDialogCurrentFolder; - pEditor->m_Map.m_Modified = false; - } - - pEditor->m_Dialog = DIALOG_NONE; -} - -void CEditor::DoToolbar(CUIRect ToolBar) -{ - CUIRect TB_Top, TB_Bottom; - CUIRect Button; - - ToolBar.HSplitTop(ToolBar.h/2.0f, &TB_Top, &TB_Bottom); - - TB_Top.HSplitBottom(2.5f, &TB_Top, 0); - TB_Bottom.HSplitTop(2.5f, 0, &TB_Bottom); - - // ctrl+o to open - if(Input()->KeyDown('o') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL))) - { - if(HasUnsavedData()) - { - m_PopupEventType = POPEVENT_LOAD; - m_PopupEventActivated = true; - } - else - InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_MAP, "Load map", "Load", "maps", "", CallbackOpenMap, this); - } - - // ctrl+s to save - if(Input()->KeyDown('s') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL))) - { - if(m_aFileName[0] && m_ValidSaveFilename) - { - str_copy(m_aFileSaveName, m_aFileName, sizeof(m_aFileSaveName)); - m_PopupEventType = POPEVENT_SAVE; - m_PopupEventActivated = true; - } - else - InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", "", CallbackSaveMap, this); - } - - // detail button - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_HqButton = 0; - if(DoButton_Editor(&s_HqButton, "HD", m_ShowDetail, &Button, 0, "[ctrl+h] Toggle High Detail") || - (Input()->KeyDown('h') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL)))) - { - m_ShowDetail = !m_ShowDetail; - } - - TB_Top.VSplitLeft(5.0f, 0, &TB_Top); - - // animation button - TB_Top.VSplitLeft(40.0f, &Button, &TB_Top); - static int s_AnimateButton = 0; - if(DoButton_Editor(&s_AnimateButton, "Anim", m_Animate, &Button, 0, "[ctrl+m] Toggle animation") || - (Input()->KeyDown('m') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL)))) - { - m_AnimateStart = time_get(); - m_Animate = !m_Animate; - } - - TB_Top.VSplitLeft(5.0f, 0, &TB_Top); - - // proof button - TB_Top.VSplitLeft(40.0f, &Button, &TB_Top); - static int s_ProofButton = 0; - if(DoButton_Editor(&s_ProofButton, "Proof", m_ProofBorders, &Button, 0, "[ctrl+p] Toggles proof borders. These borders represent what a player maximum can see.") || - (Input()->KeyDown('p') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL)))) - { - m_ProofBorders = !m_ProofBorders; - } - - TB_Top.VSplitLeft(5.0f, 0, &TB_Top); - - // tile info button - TB_Top.VSplitLeft(40.0f, &Button, &TB_Top); - static int s_TileInfoButton = 0; - if(DoButton_Editor(&s_TileInfoButton, "Info", m_ShowTileInfo, &Button, 0, "[ctrl+i] Show tile informations") || - (Input()->KeyDown('i') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL)))) - { - m_ShowTileInfo = !m_ShowTileInfo; - } - - TB_Top.VSplitLeft(15.0f, 0, &TB_Top); - - // zoom group - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_ZoomOutButton = 0; - if(DoButton_Ex(&s_ZoomOutButton, "ZO", 0, &Button, 0, "[NumPad-] Zoom out", CUI::CORNER_L) || Input()->KeyDown(KEY_KP_MINUS)) - m_ZoomLevel += 50; - - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_ZoomNormalButton = 0; - if(DoButton_Ex(&s_ZoomNormalButton, "1:1", 0, &Button, 0, "[NumPad*] Zoom to normal and remove editor offset", 0) || Input()->KeyDown(KEY_KP_MULTIPLY)) - { - m_EditorOffsetX = 0; - m_EditorOffsetY = 0; - m_ZoomLevel = 100; - } - - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_ZoomInButton = 0; - if(DoButton_Ex(&s_ZoomInButton, "ZI", 0, &Button, 0, "[NumPad+] Zoom in", CUI::CORNER_R) || Input()->KeyDown(KEY_KP_PLUS)) - m_ZoomLevel -= 50; - - TB_Top.VSplitLeft(10.0f, 0, &TB_Top); - - // animation speed - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_AnimFasterButton = 0; - if(DoButton_Ex(&s_AnimFasterButton, "A+", 0, &Button, 0, "Increase animation speed", CUI::CORNER_L)) - m_AnimateSpeed += 0.5f; - - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_AnimNormalButton = 0; - if(DoButton_Ex(&s_AnimNormalButton, "1", 0, &Button, 0, "Normal animation speed", 0)) - m_AnimateSpeed = 1.0f; - - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_AnimSlowerButton = 0; - if(DoButton_Ex(&s_AnimSlowerButton, "A-", 0, &Button, 0, "Decrease animation speed", CUI::CORNER_R)) - { - if(m_AnimateSpeed > 0.5f) - m_AnimateSpeed -= 0.5f; - } - - if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP) && m_Dialog == DIALOG_NONE) - m_ZoomLevel -= 20; - - if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN) && m_Dialog == DIALOG_NONE) - m_ZoomLevel += 20; - - if(m_ZoomLevel < 50) - m_ZoomLevel = 50; - m_WorldZoom = m_ZoomLevel/100.0f; - - TB_Top.VSplitLeft(10.0f, &Button, &TB_Top); - - - // brush manipulation - { - int Enabled = m_Brush.IsEmpty()?-1:0; - - // flip buttons - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_FlipXButton = 0; - if(DoButton_Ex(&s_FlipXButton, "X/X", Enabled, &Button, 0, "[N] Flip brush horizontal", CUI::CORNER_L) || Input()->KeyDown('n')) - { - for(int i = 0; i < m_Brush.m_lLayers.size(); i++) - m_Brush.m_lLayers[i]->BrushFlipX(); - } - - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_FlipyButton = 0; - if(DoButton_Ex(&s_FlipyButton, "Y/Y", Enabled, &Button, 0, "[M] Flip brush vertical", CUI::CORNER_R) || Input()->KeyDown('m')) - { - for(int i = 0; i < m_Brush.m_lLayers.size(); i++) - m_Brush.m_lLayers[i]->BrushFlipY(); - } - - // rotate buttons - TB_Top.VSplitLeft(15.0f, &Button, &TB_Top); - - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_RotationAmount = 90; - bool TileLayer = false; - // check for tile layers in brush selection - for(int i = 0; i < m_Brush.m_lLayers.size(); i++) - if(m_Brush.m_lLayers[i]->m_Type == LAYERTYPE_TILES) - { - TileLayer = true; - s_RotationAmount = max(90, (s_RotationAmount/90)*90); - break; - } - s_RotationAmount = UiDoValueSelector(&s_RotationAmount, &Button, "", s_RotationAmount, TileLayer?90:1, 359, TileLayer?90:1, TileLayer?10.0f:2.0f, "Rotation of the brush in degrees. Use left mouse button to drag and change the value. Hold shift to be more precise."); - - TB_Top.VSplitLeft(5.0f, &Button, &TB_Top); - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_CcwButton = 0; - if(DoButton_Ex(&s_CcwButton, "CCW", Enabled, &Button, 0, "[R] Rotates the brush counter clockwise", CUI::CORNER_L) || Input()->KeyDown('r')) - { - for(int i = 0; i < m_Brush.m_lLayers.size(); i++) - m_Brush.m_lLayers[i]->BrushRotate(-s_RotationAmount/360.0f*pi*2); - } - - TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); - static int s_CwButton = 0; - if(DoButton_Ex(&s_CwButton, "CW", Enabled, &Button, 0, "[T] Rotates the brush clockwise", CUI::CORNER_R) || Input()->KeyDown('t')) - { - for(int i = 0; i < m_Brush.m_lLayers.size(); i++) - m_Brush.m_lLayers[i]->BrushRotate(s_RotationAmount/360.0f*pi*2); - } - } - - // quad manipulation - { - // do add button - TB_Top.VSplitLeft(10.0f, &Button, &TB_Top); - TB_Top.VSplitLeft(60.0f, &Button, &TB_Top); - static int s_NewButton = 0; - - CLayerQuads *pQLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS); - //CLayerTiles *tlayer = (CLayerTiles *)get_selected_layer_type(0, LAYERTYPE_TILES); - if(DoButton_Editor(&s_NewButton, "Add Quad", pQLayer?0:-1, &Button, 0, "Adds a new quad")) - { - if(pQLayer) - { - float Mapping[4]; - CLayerGroup *g = GetSelectedGroup(); - g->Mapping(Mapping); - int AddX = f2fx(Mapping[0] + (Mapping[2]-Mapping[0])/2); - int AddY = f2fx(Mapping[1] + (Mapping[3]-Mapping[1])/2); - - CQuad *q = pQLayer->NewQuad(); - for(int i = 0; i < 5; i++) - { - q->m_aPoints[i].x += AddX; - q->m_aPoints[i].y += AddY; - } - } - } - } - - // tile manipulation - { - TB_Bottom.VSplitLeft(40.0f, &Button, &TB_Bottom); - static int s_BorderBut = 0; - CLayerTiles *pT = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES); - - if(DoButton_Editor(&s_BorderBut, "Border", pT?0:-1, &Button, 0, "Adds border tiles")) - { - if(pT) - DoMapBorder(); - } - } - - TB_Bottom.VSplitLeft(5.0f, 0, &TB_Bottom); - - // refocus button - TB_Bottom.VSplitLeft(50.0f, &Button, &TB_Bottom); - static int s_RefocusButton = 0; - if(DoButton_Editor(&s_RefocusButton, "Refocus", m_WorldOffsetX&&m_WorldOffsetY?0:-1, &Button, 0, "[HOME] Restore map focus") || Input()->KeyDown(KEY_HOME)) - { - m_WorldOffsetX = 0; - m_WorldOffsetY = 0; - } -} - -static void Rotate(CPoint *pCenter, CPoint *pPoint, float Rotation) -{ - int x = pPoint->x - pCenter->x; - int y = pPoint->y - pCenter->y; - pPoint->x = (int)(x * cosf(Rotation) - y * sinf(Rotation) + pCenter->x); - pPoint->y = (int)(x * sinf(Rotation) + y * cosf(Rotation) + pCenter->y); -} - -void CEditor::DoQuad(CQuad *q, int Index) -{ - enum - { - OP_NONE=0, - OP_MOVE_ALL, - OP_MOVE_PIVOT, - OP_ROTATE, - OP_CONTEXT_MENU, - }; - - // some basic values - void *pID = &q->m_aPoints[4]; // use pivot addr as id - static CPoint s_RotatePoints[4]; - static float s_LastWx; - static float s_LastWy; - static int s_Operation = OP_NONE; - static float s_RotateAngle = 0; - float wx = UI()->MouseWorldX(); - float wy = UI()->MouseWorldY(); - - // get pivot - float CenterX = fx2f(q->m_aPoints[4].x); - float CenterY = fx2f(q->m_aPoints[4].y); - - float dx = (CenterX - wx)/m_WorldZoom; - float dy = (CenterY - wy)/m_WorldZoom; - if(dx*dx+dy*dy < 50) - UI()->SetHotItem(pID); - - // draw selection background - if(m_SelectedQuad == Index) - { - Graphics()->SetColor(0,0,0,1); - IGraphics::CQuadItem QuadItem(CenterX, CenterY, 7.0f, 7.0f); - Graphics()->QuadsDraw(&QuadItem, 1); - } - - if(UI()->ActiveItem() == pID) - { - // check if we only should move pivot - if(s_Operation == OP_MOVE_PIVOT) - { - q->m_aPoints[4].x += f2fx(wx-s_LastWx); - q->m_aPoints[4].y += f2fx(wy-s_LastWy); - } - else if(s_Operation == OP_MOVE_ALL) - { - // move all points including pivot - for(int v = 0; v < 5; v++) - { - q->m_aPoints[v].x += f2fx(wx-s_LastWx); - q->m_aPoints[v].y += f2fx(wy-s_LastWy); - } - } - else if(s_Operation == OP_ROTATE) - { - for(int v = 0; v < 4; v++) - { - q->m_aPoints[v] = s_RotatePoints[v]; - Rotate(&q->m_aPoints[4], &q->m_aPoints[v], s_RotateAngle); - } - } - - s_RotateAngle += (m_MouseDeltaX) * 0.002f; - s_LastWx = wx; - s_LastWy = wy; - - if(s_Operation == OP_CONTEXT_MENU) - { - if(!UI()->MouseButton(1)) - { - static int s_QuadPopupID = 0; - UiInvokePopupMenu(&s_QuadPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 180, PopupQuad); - m_LockMouse = false; - s_Operation = OP_NONE; - UI()->SetActiveItem(0); - } - } - else - { - if(!UI()->MouseButton(0)) - { - m_LockMouse = false; - s_Operation = OP_NONE; - UI()->SetActiveItem(0); - } - } - - Graphics()->SetColor(1,1,1,1); - } - else if(UI()->HotItem() == pID) - { - ms_pUiGotContext = pID; - - Graphics()->SetColor(1,1,1,1); - m_pTooltip = "Left mouse button to move. Hold shift to move pivot. Hold ctrl to rotate."; - - if(UI()->MouseButton(0)) - { - if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) - s_Operation = OP_MOVE_PIVOT; - else if(Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL)) - { - m_LockMouse = true; - s_Operation = OP_ROTATE; - s_RotateAngle = 0; - s_RotatePoints[0] = q->m_aPoints[0]; - s_RotatePoints[1] = q->m_aPoints[1]; - s_RotatePoints[2] = q->m_aPoints[2]; - s_RotatePoints[3] = q->m_aPoints[3]; - } - else - s_Operation = OP_MOVE_ALL; - - UI()->SetActiveItem(pID); - m_SelectedQuad = Index; - s_LastWx = wx; - s_LastWy = wy; - } - - if(UI()->MouseButton(1)) - { - m_SelectedQuad = Index; - s_Operation = OP_CONTEXT_MENU; - UI()->SetActiveItem(pID); - } - } - else - Graphics()->SetColor(0,1,0,1); - - IGraphics::CQuadItem QuadItem(CenterX, CenterY, 5.0f*m_WorldZoom, 5.0f*m_WorldZoom); - Graphics()->QuadsDraw(&QuadItem, 1); -} - -void CEditor::DoQuadPoint(CQuad *pQuad, int QuadIndex, int V) -{ - void *pID = &pQuad->m_aPoints[V]; - - float wx = UI()->MouseWorldX(); - float wy = UI()->MouseWorldY(); - - float px = fx2f(pQuad->m_aPoints[V].x); - float py = fx2f(pQuad->m_aPoints[V].y); - - float dx = (px - wx)/m_WorldZoom; - float dy = (py - wy)/m_WorldZoom; - if(dx*dx+dy*dy < 50) - UI()->SetHotItem(pID); - - // draw selection background - if(m_SelectedQuad == QuadIndex && m_SelectedPoints&(1<SetColor(0,0,0,1); - IGraphics::CQuadItem QuadItem(px, py, 7.0f, 7.0f); - Graphics()->QuadsDraw(&QuadItem, 1); - } - - enum - { - OP_NONE=0, - OP_MOVEPOINT, - OP_MOVEUV, - OP_CONTEXT_MENU - }; - - static bool s_Moved; - static int s_Operation = OP_NONE; - - if(UI()->ActiveItem() == pID) - { - float dx = m_MouseDeltaWx; - float dy = m_MouseDeltaWy; - if(!s_Moved) - { - if(dx*dx+dy*dy > 0.5f) - s_Moved = true; - } - - if(s_Moved) - { - if(s_Operation == OP_MOVEPOINT) - { - for(int m = 0; m < 4; m++) - if(m_SelectedPoints&(1<m_aPoints[m].x += f2fx(dx); - pQuad->m_aPoints[m].y += f2fx(dy); - } - } - else if(s_Operation == OP_MOVEUV) - { - for(int m = 0; m < 4; m++) - if(m_SelectedPoints&(1<m_aTexcoords[m].x += f2fx(dx*0.001f); - pQuad->m_aTexcoords[(m+2)%4].x += f2fx(dx*0.001f); - - pQuad->m_aTexcoords[m].y += f2fx(dy*0.001f); - pQuad->m_aTexcoords[m^1].y += f2fx(dy*0.001f); - } - } - } - - if(s_Operation == OP_CONTEXT_MENU) - { - if(!UI()->MouseButton(1)) - { - static int s_PointPopupID = 0; - UiInvokePopupMenu(&s_PointPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 150, PopupPoint); - UI()->SetActiveItem(0); - } - } - else - { - if(!UI()->MouseButton(0)) - { - if(!s_Moved) - { - if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) - m_SelectedPoints ^= 1<SetActiveItem(0); - } - } - - Graphics()->SetColor(1,1,1,1); - } - else if(UI()->HotItem() == pID) - { - ms_pUiGotContext = pID; - - Graphics()->SetColor(1,1,1,1); - m_pTooltip = "Left mouse button to move. Hold shift to move the texture."; - - if(UI()->MouseButton(0)) - { - UI()->SetActiveItem(pID); - s_Moved = false; - if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) - { - s_Operation = OP_MOVEUV; - m_LockMouse = true; - } - else - s_Operation = OP_MOVEPOINT; - - if(!(m_SelectedPoints&(1<KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) - m_SelectedPoints |= 1<MouseButton(1)) - { - s_Operation = OP_CONTEXT_MENU; - m_SelectedQuad = QuadIndex; - UI()->SetActiveItem(pID); - if(!(m_SelectedPoints&(1<KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) - m_SelectedPoints |= 1<SetColor(1,0,0,1); - - IGraphics::CQuadItem QuadItem(px, py, 5.0f*m_WorldZoom, 5.0f*m_WorldZoom); - Graphics()->QuadsDraw(&QuadItem, 1); -} - -void CEditor::DoMapEditor(CUIRect View, CUIRect ToolBar, bool ShowPicker) -{ - // render all good stuff - if(!ShowPicker) - { - for(int g = 0; g < m_Map.m_lGroups.size(); g++) - { - if(m_Map.m_lGroups[g]->m_Visible) - m_Map.m_lGroups[g]->Render(); - //UI()->ClipEnable(&view); - } - - // render the game above everything else - if(m_Map.m_pGameGroup->m_Visible && m_Map.m_pGameLayer->m_Visible) - { - m_Map.m_pGameGroup->MapScreen(); - m_Map.m_pGameLayer->Render(); - } - - CLayerTiles *pT = static_cast(GetSelectedLayerType(0, LAYERTYPE_TILES)); - if(m_ShowTileInfo && pT && pT->m_Visible && m_ZoomLevel <= 300) - pT->ShowInfo(); - } - - static void *s_pEditorID = (void *)&s_pEditorID; - int Inside = UI()->MouseInside(&View); - - // fetch mouse position - float wx = UI()->MouseWorldX(); - float wy = UI()->MouseWorldY(); - float mx = UI()->MouseX(); - float my = UI()->MouseY(); - - static float s_StartWx = 0; - static float s_StartWy = 0; - static float s_StartMx = 0; - static float s_StartMy = 0; - - enum - { - OP_NONE=0, - OP_BRUSH_GRAB, - OP_BRUSH_DRAW, - OP_BRUSH_PAINT, - OP_PAN_WORLD, - OP_PAN_EDITOR, - }; - - // remap the screen so it can display the whole tileset - if(ShowPicker) - { - CUIRect Screen = *UI()->Screen(); - float Size = 32.0*16.0f; - float w = Size*(Screen.w/View.w); - float h = Size*(Screen.h/View.h); - float x = -(View.x/Screen.w)*w; - float y = -(View.y/Screen.h)*h; - wx = x+w*mx/Screen.w; - wy = y+h*my/Screen.h; - Graphics()->MapScreen(x, y, x+w, y+h); - CLayerTiles *t = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES); - if(t) - { - m_TilesetPicker.m_Image = t->m_Image; - m_TilesetPicker.m_TexID = t->m_TexID; - m_TilesetPicker.Render(); - if(m_ShowTileInfo) - m_TilesetPicker.ShowInfo(); - } - } - - static int s_Operation = OP_NONE; - - // draw layer borders - CLayer *pEditLayers[16]; - int NumEditLayers = 0; - NumEditLayers = 0; - - if(ShowPicker) - { - pEditLayers[0] = &m_TilesetPicker; - NumEditLayers++; - } - else - { - pEditLayers[0] = GetSelectedLayer(0); - if(pEditLayers[0]) - NumEditLayers++; - - CLayerGroup *g = GetSelectedGroup(); - if(g) - { - g->MapScreen(); - - for(int i = 0; i < NumEditLayers; i++) - { - if(pEditLayers[i]->m_Type != LAYERTYPE_TILES) - continue; - - float w, h; - pEditLayers[i]->GetSize(&w, &h); - - IGraphics::CLineItem Array[4] = { - IGraphics::CLineItem(0, 0, w, 0), - IGraphics::CLineItem(w, 0, w, h), - IGraphics::CLineItem(w, h, 0, h), - IGraphics::CLineItem(0, h, 0, 0)}; - Graphics()->TextureSet(-1); - Graphics()->LinesBegin(); - Graphics()->LinesDraw(Array, 4); - Graphics()->LinesEnd(); - } - } - } - - if(Inside) - { - UI()->SetHotItem(s_pEditorID); - - // do global operations like pan and zoom - if(UI()->ActiveItem() == 0 && (UI()->MouseButton(0) || UI()->MouseButton(2))) - { - s_StartWx = wx; - s_StartWy = wy; - s_StartMx = mx; - s_StartMy = my; - - if(Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL) || UI()->MouseButton(2)) - { - if(Input()->KeyPressed(KEY_LSHIFT)) - s_Operation = OP_PAN_EDITOR; - else - s_Operation = OP_PAN_WORLD; - UI()->SetActiveItem(s_pEditorID); - } - } - - // brush editing - if(UI()->HotItem() == s_pEditorID) - { - if(m_Brush.IsEmpty()) - m_pTooltip = "Use left mouse button to drag and create a brush."; - else - m_pTooltip = "Use left mouse button to paint with the brush. Right button clears the brush."; - - if(UI()->ActiveItem() == s_pEditorID) - { - CUIRect r; - r.x = s_StartWx; - r.y = s_StartWy; - r.w = wx-s_StartWx; - r.h = wy-s_StartWy; - if(r.w < 0) - { - r.x += r.w; - r.w = -r.w; - } - - if(r.h < 0) - { - r.y += r.h; - r.h = -r.h; - } - - if(s_Operation == OP_BRUSH_DRAW) - { - if(!m_Brush.IsEmpty()) - { - // draw with brush - for(int k = 0; k < NumEditLayers; k++) - { - if(pEditLayers[k]->m_Type == m_Brush.m_lLayers[0]->m_Type) - pEditLayers[k]->BrushDraw(m_Brush.m_lLayers[0], wx, wy); - } - } - } - else if(s_Operation == OP_BRUSH_GRAB) - { - if(!UI()->MouseButton(0)) - { - // grab brush - char aBuf[256]; - str_format(aBuf, sizeof(aBuf),"grabbing %f %f %f %f", r.x, r.y, r.w, r.h); - Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "editor", aBuf); - - // TODO: do all layers - int Grabs = 0; - for(int k = 0; k < NumEditLayers; k++) - Grabs += pEditLayers[k]->BrushGrab(&m_Brush, r); - if(Grabs == 0) - m_Brush.Clear(); - } - else - { - //editor.map.groups[selected_group]->mapscreen(); - for(int k = 0; k < NumEditLayers; k++) - pEditLayers[k]->BrushSelecting(r); - Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); - } - } - else if(s_Operation == OP_BRUSH_PAINT) - { - if(!UI()->MouseButton(0)) - { - for(int k = 0; k < NumEditLayers; k++) - pEditLayers[k]->FillSelection(m_Brush.IsEmpty(), m_Brush.m_lLayers[0], r); - } - else - { - //editor.map.groups[selected_group]->mapscreen(); - for(int k = 0; k < NumEditLayers; k++) - pEditLayers[k]->BrushSelecting(r); - Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); - } - } - } - else - { - if(UI()->MouseButton(1)) - m_Brush.Clear(); - - if(UI()->MouseButton(0) && s_Operation == OP_NONE) - { - UI()->SetActiveItem(s_pEditorID); - - if(m_Brush.IsEmpty()) - s_Operation = OP_BRUSH_GRAB; - else - { - s_Operation = OP_BRUSH_DRAW; - for(int k = 0; k < NumEditLayers; k++) - { - if(pEditLayers[k]->m_Type == m_Brush.m_lLayers[0]->m_Type) - pEditLayers[k]->BrushPlace(m_Brush.m_lLayers[0], wx, wy); - } - - } - - CLayerTiles *pLayer = (CLayerTiles*)GetSelectedLayerType(0, LAYERTYPE_TILES); - if((Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) && pLayer) - s_Operation = OP_BRUSH_PAINT; - } - - if(!m_Brush.IsEmpty()) - { - m_Brush.m_OffsetX = -(int)wx; - m_Brush.m_OffsetY = -(int)wy; - for(int i = 0; i < m_Brush.m_lLayers.size(); i++) - { - if(m_Brush.m_lLayers[i]->m_Type == LAYERTYPE_TILES) - { - m_Brush.m_OffsetX = -(int)(wx/32.0f)*32; - m_Brush.m_OffsetY = -(int)(wy/32.0f)*32; - break; - } - } - - CLayerGroup *g = GetSelectedGroup(); - if(g) - { - m_Brush.m_OffsetX += g->m_OffsetX; - m_Brush.m_OffsetY += g->m_OffsetY; - m_Brush.m_ParallaxX = g->m_ParallaxX; - m_Brush.m_ParallaxY = g->m_ParallaxY; - m_Brush.Render(); - float w, h; - m_Brush.GetSize(&w, &h); - - IGraphics::CLineItem Array[4] = { - IGraphics::CLineItem(0, 0, w, 0), - IGraphics::CLineItem(w, 0, w, h), - IGraphics::CLineItem(w, h, 0, h), - IGraphics::CLineItem(0, h, 0, 0)}; - Graphics()->TextureSet(-1); - Graphics()->LinesBegin(); - Graphics()->LinesDraw(Array, 4); - Graphics()->LinesEnd(); - } - } - } - } - - // quad editing - { - if(!ShowPicker && m_Brush.IsEmpty()) - { - // fetch layers - CLayerGroup *g = GetSelectedGroup(); - if(g) - g->MapScreen(); - - for(int k = 0; k < NumEditLayers; k++) - { - if(pEditLayers[k]->m_Type == LAYERTYPE_QUADS) - { - CLayerQuads *pLayer = (CLayerQuads *)pEditLayers[k]; - - Graphics()->TextureSet(-1); - Graphics()->QuadsBegin(); - for(int i = 0; i < pLayer->m_lQuads.size(); i++) - { - for(int v = 0; v < 4; v++) - DoQuadPoint(&pLayer->m_lQuads[i], i, v); - - DoQuad(&pLayer->m_lQuads[i], i); - } - Graphics()->QuadsEnd(); - } - } - - Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); - } - - // do panning - if(UI()->ActiveItem() == s_pEditorID) - { - if(s_Operation == OP_PAN_WORLD) - { - m_WorldOffsetX -= m_MouseDeltaX*m_WorldZoom; - m_WorldOffsetY -= m_MouseDeltaY*m_WorldZoom; - } - else if(s_Operation == OP_PAN_EDITOR) - { - m_EditorOffsetX -= m_MouseDeltaX*m_WorldZoom; - m_EditorOffsetY -= m_MouseDeltaY*m_WorldZoom; - } - - // release mouse - if(!UI()->MouseButton(0)) - { - s_Operation = OP_NONE; - UI()->SetActiveItem(0); - } - } - } - } - else if(UI()->ActiveItem() == s_pEditorID) - { - // release mouse - if(!UI()->MouseButton(0)) - { - s_Operation = OP_NONE; - UI()->SetActiveItem(0); - } - } - - if(GetSelectedGroup() && GetSelectedGroup()->m_UseClipping) - { - CLayerGroup *g = m_Map.m_pGameGroup; - g->MapScreen(); - - Graphics()->TextureSet(-1); - Graphics()->LinesBegin(); - - CUIRect r; - r.x = GetSelectedGroup()->m_ClipX; - r.y = GetSelectedGroup()->m_ClipY; - r.w = GetSelectedGroup()->m_ClipW; - r.h = GetSelectedGroup()->m_ClipH; - - IGraphics::CLineItem Array[4] = { - IGraphics::CLineItem(r.x, r.y, r.x+r.w, r.y), - IGraphics::CLineItem(r.x+r.w, r.y, r.x+r.w, r.y+r.h), - IGraphics::CLineItem(r.x+r.w, r.y+r.h, r.x, r.y+r.h), - IGraphics::CLineItem(r.x, r.y+r.h, r.x, r.y)}; - Graphics()->SetColor(1,0,0,1); - Graphics()->LinesDraw(Array, 4); - - Graphics()->LinesEnd(); - } - - // render screen sizes - if(m_ProofBorders) - { - CLayerGroup *g = m_Map.m_pGameGroup; - g->MapScreen(); - - Graphics()->TextureSet(-1); - Graphics()->LinesBegin(); - - float aLastPoints[4]; - float Start = 1.0f; //9.0f/16.0f; - float End = 16.0f/9.0f; - const int NumSteps = 20; - for(int i = 0; i <= NumSteps; i++) - { - float aPoints[4]; - float Aspect = Start + (End-Start)*(i/(float)NumSteps); - - RenderTools()->MapscreenToWorld( - m_WorldOffsetX, m_WorldOffsetY, - 1.0f, 1.0f, 0.0f, 0.0f, Aspect, 1.0f, aPoints); - - if(i == 0) - { - IGraphics::CLineItem Array[2] = { - IGraphics::CLineItem(aPoints[0], aPoints[1], aPoints[2], aPoints[1]), - IGraphics::CLineItem(aPoints[0], aPoints[3], aPoints[2], aPoints[3])}; - Graphics()->LinesDraw(Array, 2); - } - - if(i != 0) - { - IGraphics::CLineItem Array[4] = { - IGraphics::CLineItem(aPoints[0], aPoints[1], aLastPoints[0], aLastPoints[1]), - IGraphics::CLineItem(aPoints[2], aPoints[1], aLastPoints[2], aLastPoints[1]), - IGraphics::CLineItem(aPoints[0], aPoints[3], aLastPoints[0], aLastPoints[3]), - IGraphics::CLineItem(aPoints[2], aPoints[3], aLastPoints[2], aLastPoints[3])}; - Graphics()->LinesDraw(Array, 4); - } - - if(i == NumSteps) - { - IGraphics::CLineItem Array[2] = { - IGraphics::CLineItem(aPoints[0], aPoints[1], aPoints[0], aPoints[3]), - IGraphics::CLineItem(aPoints[2], aPoints[1], aPoints[2], aPoints[3])}; - Graphics()->LinesDraw(Array, 2); - } - - mem_copy(aLastPoints, aPoints, sizeof(aPoints)); - } - - if(1) - { - Graphics()->SetColor(1,0,0,1); - for(int i = 0; i < 2; i++) - { - float aPoints[4]; - float aAspects[] = {4.0f/3.0f, 16.0f/10.0f, 5.0f/4.0f, 16.0f/9.0f}; - float Aspect = aAspects[i]; - - RenderTools()->MapscreenToWorld( - m_WorldOffsetX, m_WorldOffsetY, - 1.0f, 1.0f, 0.0f, 0.0f, Aspect, 1.0f, aPoints); - - CUIRect r; - r.x = aPoints[0]; - r.y = aPoints[1]; - r.w = aPoints[2]-aPoints[0]; - r.h = aPoints[3]-aPoints[1]; - - IGraphics::CLineItem Array[4] = { - IGraphics::CLineItem(r.x, r.y, r.x+r.w, r.y), - IGraphics::CLineItem(r.x+r.w, r.y, r.x+r.w, r.y+r.h), - IGraphics::CLineItem(r.x+r.w, r.y+r.h, r.x, r.y+r.h), - IGraphics::CLineItem(r.x, r.y+r.h, r.x, r.y)}; - Graphics()->LinesDraw(Array, 4); - Graphics()->SetColor(0,1,0,1); - } - } - - Graphics()->LinesEnd(); - } - - Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); - //UI()->ClipDisable(); -} - - -int CEditor::DoProperties(CUIRect *pToolBox, CProperty *pProps, int *pIDs, int *pNewVal) -{ - int Change = -1; - - 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, -1, -1); - - 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_format(aBuf, sizeof(aBuf),"%d", pProps[i].m_Value); - RenderTools()->DrawUIRect(&Shifter, vec4(1,1,1,0.5f), 0, 0.0f); - UI()->DoLabel(&Shifter, aBuf, 10.0f, 0, -1); - - if(DoButton_ButtonDec(&pIDs[i], 0, 0, &Dec, 0, "Decrease")) - { - *pNewVal = pProps[i].m_Value-1; - Change = i; - } - if(DoButton_ButtonInc(((char *)&pIDs[i])+1, 0, 0, &Inc, 0, "Increase")) - { - *pNewVal = pProps[i].m_Value+1; - Change = i; - } - } - 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; - } - if(DoButton_ButtonInc(((char *)&pIDs[i])+1, "Yes", pProps[i].m_Value, &Yes, 0, "")) - { - *pNewVal = 1; - Change = i; - } - } - else if(pProps[i].m_Type == PROPTYPE_INT_SCROLL) - { - int NewValue = 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."); - if(NewValue != pProps[i].m_Value) - { - *pNewVal = NewValue; - Change = i; - } - } - else if(pProps[i].m_Type == PROPTYPE_COLOR) - { - static const char *s_paTexts[4] = {"R", "G", "B", "A"}; - static int s_aShift[] = {24, 16, 8, 0}; - int NewColor = 0; - - for(int c = 0; c < 4; c++) - { - int v = (pProps[i].m_Value >> s_aShift[c])&0xff; - NewColor |= UiDoValueSelector(((char *)&pIDs[i])+c, &Shifter, s_paTexts[c], v, 0, 255, 1, 1.0f, "Use left mouse button to drag and change the color value. Hold shift to be more precise.")<HSplitTop(13.0f, &Slot, pToolBox); - Slot.VSplitMid(0, &Shifter); - Shifter.HMargin(1.0f, &Shifter); - } - } - - if(NewColor != pProps[i].m_Value) - { - *pNewVal = NewColor; - Change = i; - } - } - else if(pProps[i].m_Type == PROPTYPE_IMAGE) - { - char aBuf[64]; - if(pProps[i].m_Value < 0) - str_copy(aBuf, "None", sizeof(aBuf)); - else - str_format(aBuf, sizeof(aBuf),"%s", m_Map.m_lImages[pProps[i].m_Value]->m_aName); - - if(DoButton_Editor(&pIDs[i], aBuf, 0, &Shifter, 0, 0)) - PopupSelectImageInvoke(pProps[i].m_Value, UI()->MouseX(), UI()->MouseY()); - - int r = PopupSelectImageResult(); - if(r >= -1) - { - *pNewVal = r; - Change = i; - } - } - else if(pProps[i].m_Type == PROPTYPE_SHIFT) - { - CUIRect Left, Right, Up, Down; - Shifter.VSplitMid(&Left, &Up); - Left.VSplitRight(1.0f, &Left, 0); - Up.VSplitLeft(1.0f, 0, &Up); - Left.VSplitLeft(10.0f, &Left, &Shifter); - Shifter.VSplitRight(10.0f, &Shifter, &Right); - RenderTools()->DrawUIRect(&Shifter, vec4(1,1,1,0.5f), 0, 0.0f); - UI()->DoLabel(&Shifter, "X", 10.0f, 0, -1); - Up.VSplitLeft(10.0f, &Up, &Shifter); - Shifter.VSplitRight(10.0f, &Shifter, &Down); - RenderTools()->DrawUIRect(&Shifter, vec4(1,1,1,0.5f), 0, 0.0f); - UI()->DoLabel(&Shifter, "Y", 10.0f, 0, -1); - if(DoButton_ButtonDec(&pIDs[i], "-", 0, &Left, 0, "Left")) - { - *pNewVal = 1; - Change = i; - } - if(DoButton_ButtonInc(((char *)&pIDs[i])+3, "+", 0, &Right, 0, "Right")) - { - *pNewVal = 2; - Change = i; - } - if(DoButton_ButtonDec(((char *)&pIDs[i])+1, "-", 0, &Up, 0, "Up")) - { - *pNewVal = 4; - Change = i; - } - if(DoButton_ButtonInc(((char *)&pIDs[i])+2, "+", 0, &Down, 0, "Down")) - { - *pNewVal = 8; - Change = i; - } - } - } - - return Change; -} - -void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) -{ - CUIRect LayersBox = ToolBox; - - if(!m_GuiActive) - return; - - CUIRect Slot, Button; - char aBuf[64]; - - int ValidGroup = 0; - int ValidLayer = 0; - if(m_SelectedGroup >= 0 && m_SelectedGroup < m_Map.m_lGroups.size()) - ValidGroup = 1; - - if(ValidGroup && m_SelectedLayer >= 0 && m_SelectedLayer < m_Map.m_lGroups[m_SelectedGroup]->m_lLayers.size()) - ValidLayer = 1; - - float LayersHeight = 12.0f; // Height of AddGroup button - static int s_ScrollBar = 0; - static float s_ScrollValue = 0; - - for(int g = 0; g < m_Map.m_lGroups.size(); g++) - // Each group is 19.0f - // Each layer is 14.0f - LayersHeight += 19.0f + m_Map.m_lGroups[g]->m_lLayers.size() * 14.0f; - - float ScrollDifference = LayersHeight - LayersBox.h; - - if(LayersHeight > LayersBox.h) // Do we even need a scrollbar? - { - CUIRect Scroll; - LayersBox.VSplitRight(15.0f, &LayersBox, &Scroll); - LayersBox.VSplitRight(3.0f, &LayersBox, 0); // extra spacing - Scroll.HMargin(5.0f, &Scroll); - s_ScrollValue = UiDoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue); - } - - float LayerStartAt = ScrollDifference * s_ScrollValue; - if(LayerStartAt < 0.0f) - LayerStartAt = 0.0f; - - float LayerStopAt = LayersHeight - ScrollDifference * (1 - s_ScrollValue); - float LayerCur = 0; - - // render layers - { - for(int g = 0; g < m_Map.m_lGroups.size(); g++) - { - if(LayerCur > LayerStopAt) - break; - else if(LayerCur + m_Map.m_lGroups[g]->m_lLayers.size() * 14.0f + 19.0f < LayerStartAt) - { - LayerCur += m_Map.m_lGroups[g]->m_lLayers.size() * 14.0f + 19.0f; - continue; - } - - CUIRect VisibleToggle, SaveCheck; - if(LayerCur >= LayerStartAt) - { - LayersBox.HSplitTop(12.0f, &Slot, &LayersBox); - Slot.VSplitLeft(12, &VisibleToggle, &Slot); - if(DoButton_Ex(&m_Map.m_lGroups[g]->m_Visible, m_Map.m_lGroups[g]->m_Visible?"V":"H", 0, &VisibleToggle, 0, "Toggle group visibility", CUI::CORNER_L)) - m_Map.m_lGroups[g]->m_Visible = !m_Map.m_lGroups[g]->m_Visible; - - Slot.VSplitRight(12.0f, &Slot, &SaveCheck); - if(DoButton_Ex(&m_Map.m_lGroups[g]->m_SaveToMap, "S", m_Map.m_lGroups[g]->m_SaveToMap, &SaveCheck, 0, "Enable/disable group for saving", CUI::CORNER_R)) - if(!m_Map.m_lGroups[g]->m_GameGroup) - m_Map.m_lGroups[g]->m_SaveToMap = !m_Map.m_lGroups[g]->m_SaveToMap; - - str_format(aBuf, sizeof(aBuf),"#%d %s", g, m_Map.m_lGroups[g]->m_pName); - if(int Result = DoButton_Ex(&m_Map.m_lGroups[g], aBuf, g==m_SelectedGroup, &Slot, - BUTTON_CONTEXT, "Select group. Right click for properties.", 0)) - { - m_SelectedGroup = g; - m_SelectedLayer = 0; - - static int s_GroupPopupId = 0; - if(Result == 2) - UiInvokePopupMenu(&s_GroupPopupId, 0, UI()->MouseX(), UI()->MouseY(), 120, 200, PopupGroup); - } - LayersBox.HSplitTop(2.0f, &Slot, &LayersBox); - } - LayerCur += 14.0f; - - for(int i = 0; i < m_Map.m_lGroups[g]->m_lLayers.size(); i++) - { - if(LayerCur > LayerStopAt) - break; - else if(LayerCur < LayerStartAt) - { - LayerCur += 14.0f; - continue; - } - - //visible - LayersBox.HSplitTop(12.0f, &Slot, &LayersBox); - Slot.VSplitLeft(12.0f, 0, &Button); - Button.VSplitLeft(15, &VisibleToggle, &Button); - - if(DoButton_Ex(&m_Map.m_lGroups[g]->m_lLayers[i]->m_Visible, m_Map.m_lGroups[g]->m_lLayers[i]->m_Visible?"V":"H", 0, &VisibleToggle, 0, "Toggle layer visibility", CUI::CORNER_L)) - m_Map.m_lGroups[g]->m_lLayers[i]->m_Visible = !m_Map.m_lGroups[g]->m_lLayers[i]->m_Visible; - - Button.VSplitRight(12.0f, &Button, &SaveCheck); - if(DoButton_Ex(&m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap, "S", m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap, &SaveCheck, 0, "Enable/disable layer for saving", CUI::CORNER_R)) - if(m_Map.m_lGroups[g]->m_lLayers[i] != m_Map.m_pGameLayer) - m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap = !m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap; - - str_format(aBuf, sizeof(aBuf),"#%d %s ", i, m_Map.m_lGroups[g]->m_lLayers[i]->m_pTypeName); - if(int Result = DoButton_Ex(m_Map.m_lGroups[g]->m_lLayers[i], aBuf, g==m_SelectedGroup&&i==m_SelectedLayer, &Button, - BUTTON_CONTEXT, "Select layer. Right click for properties.", 0)) - { - m_SelectedLayer = i; - m_SelectedGroup = g; - static int s_LayerPopupID = 0; - if(Result == 2) - UiInvokePopupMenu(&s_LayerPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 220, PopupLayer); - } - - LayerCur += 14.0f; - LayersBox.HSplitTop(2.0f, &Slot, &LayersBox); - } - if(LayerCur > LayerStartAt && LayerCur < LayerStopAt) - LayersBox.HSplitTop(5.0f, &Slot, &LayersBox); - LayerCur += 5.0f; - } - } - - if(LayerCur <= LayerStopAt) - { - LayersBox.HSplitTop(12.0f, &Slot, &LayersBox); - - static int s_NewGroupButton = 0; - if(DoButton_Editor(&s_NewGroupButton, "Add group", 0, &Slot, 0, "Adds a new group")) - { - m_Map.NewGroup(); - m_SelectedGroup = m_Map.m_lGroups.size()-1; - } - } -} - -void CEditor::ReplaceImage(const char *pFileName, int StorageType, void *pUser) -{ - CEditor *pEditor = (CEditor *)pUser; - CEditorImage ImgInfo(pEditor); - if(!pEditor->Graphics()->LoadPNG(&ImgInfo, pFileName, StorageType)) - return; - - CEditorImage *pImg = pEditor->m_Map.m_lImages[pEditor->m_SelectedImage]; - int External = pImg->m_External; - pEditor->Graphics()->UnloadTexture(pImg->m_TexID); - *pImg = ImgInfo; - pImg->m_External = External; - pEditor->ExtractName(pFileName, pImg->m_aName, sizeof(pImg->m_aName)); - pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0); - pEditor->SortImages(); - for(int i = 0; i < pEditor->m_Map.m_lImages.size(); ++i) - { - if(!str_comp(pEditor->m_Map.m_lImages[i]->m_aName, pImg->m_aName)) - pEditor->m_SelectedImage = i; - } - pEditor->m_Dialog = DIALOG_NONE; -} - -void CEditor::AddImage(const char *pFileName, int StorageType, void *pUser) -{ - CEditor *pEditor = (CEditor *)pUser; - CEditorImage ImgInfo(pEditor); - if(!pEditor->Graphics()->LoadPNG(&ImgInfo, pFileName, StorageType)) - return; - - // check if we have that image already - char aBuf[128]; - ExtractName(pFileName, aBuf, sizeof(aBuf)); - for(int i = 0; i < pEditor->m_Map.m_lImages.size(); ++i) - { - if(!str_comp(pEditor->m_Map.m_lImages[i]->m_aName, aBuf)) - return; - } - - CEditorImage *pImg = new CEditorImage(pEditor); - *pImg = ImgInfo; - pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0); - pImg->m_External = 1; // external by default - str_copy(pImg->m_aName, aBuf, sizeof(pImg->m_aName)); - pEditor->m_Map.m_lImages.add(pImg); - pEditor->SortImages(); - if(pEditor->m_SelectedImage > -1 && pEditor->m_SelectedImage < pEditor->m_Map.m_lImages.size()) - { - for(int i = 0; i <= pEditor->m_SelectedImage; ++i) - if(!str_comp(pEditor->m_Map.m_lImages[i]->m_aName, aBuf)) - { - pEditor->m_SelectedImage++; - break; - } - } - pEditor->m_Dialog = DIALOG_NONE; -} - - -static int gs_ModifyIndexDeletedIndex; -static void ModifyIndexDeleted(int *pIndex) -{ - if(*pIndex == gs_ModifyIndexDeletedIndex) - *pIndex = -1; - else if(*pIndex > gs_ModifyIndexDeletedIndex) - *pIndex = *pIndex - 1; -} - -int CEditor::PopupImage(CEditor *pEditor, CUIRect View) -{ - static int s_ReplaceButton = 0; - static int s_RemoveButton = 0; - - CUIRect Slot; - View.HSplitTop(2.0f, &Slot, &View); - View.HSplitTop(12.0f, &Slot, &View); - CEditorImage *pImg = pEditor->m_Map.m_lImages[pEditor->m_SelectedImage]; - - static int s_ExternalButton = 0; - if(pImg->m_External) - { - if(pEditor->DoButton_MenuItem(&s_ExternalButton, "Embed", 0, &Slot, 0, "Embeds the image into the map file.")) - { - pImg->m_External = 0; - return 1; - } - } - else - { - if(pEditor->DoButton_MenuItem(&s_ExternalButton, "Make external", 0, &Slot, 0, "Removes the image from the map file.")) - { - pImg->m_External = 1; - return 1; - } - } - - View.HSplitTop(10.0f, &Slot, &View); - View.HSplitTop(12.0f, &Slot, &View); - if(pEditor->DoButton_MenuItem(&s_ReplaceButton, "Replace", 0, &Slot, 0, "Replaces the image with a new one")) - { - pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Replace Image", "Replace", "mapres", "", ReplaceImage, pEditor); - return 1; - } - - View.HSplitTop(10.0f, &Slot, &View); - View.HSplitTop(12.0f, &Slot, &View); - if(pEditor->DoButton_MenuItem(&s_RemoveButton, "Remove", 0, &Slot, 0, "Removes the image from the map")) - { - delete pImg; - pEditor->m_Map.m_lImages.remove_index(pEditor->m_SelectedImage); - gs_ModifyIndexDeletedIndex = pEditor->m_SelectedImage; - pEditor->m_Map.ModifyImageIndex(ModifyIndexDeleted); - return 1; - } - - return 0; -} - -static int CompareImageName(const void *pObject1, const void *pObject2) -{ - CEditorImage *pImage1 = *(CEditorImage**)pObject1; - CEditorImage *pImage2 = *(CEditorImage**)pObject2; - - return str_comp(pImage1->m_aName, pImage2->m_aName); -} - -static int *gs_pSortedIndex = 0; -static void ModifySortedIndex(int *pIndex) -{ - if(*pIndex > -1) - *pIndex = gs_pSortedIndex[*pIndex]; -} - -void CEditor::SortImages() -{ - bool Sorted = true; - for(int i = 1; i < m_Map.m_lImages.size(); i++) - if( str_comp(m_Map.m_lImages[i]->m_aName, m_Map.m_lImages[i-1]->m_aName) < 0 ) - { - Sorted = false; - break; - } - - if(!Sorted) - { - array lTemp = array(m_Map.m_lImages); - gs_pSortedIndex = new int[lTemp.size()]; - - qsort(m_Map.m_lImages.base_ptr(), m_Map.m_lImages.size(), sizeof(CEditorImage*), CompareImageName); - - for(int OldIndex = 0; OldIndex < lTemp.size(); OldIndex++) - for(int NewIndex = 0; NewIndex < m_Map.m_lImages.size(); NewIndex++) - if(lTemp[OldIndex] == m_Map.m_lImages[NewIndex]) - gs_pSortedIndex[OldIndex] = NewIndex; - - m_Map.ModifyImageIndex(ModifySortedIndex); - - delete [] gs_pSortedIndex; - gs_pSortedIndex = 0; - } -} - - -void CEditor::RenderImages(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) -{ - static int s_ScrollBar = 0; - static float s_ScrollValue = 0; - float ImagesHeight = 30.0f + 14.0f * m_Map.m_lImages.size() + 27.0f; - float ScrollDifference = ImagesHeight - ToolBox.h; - - if(ImagesHeight > ToolBox.h) // Do we even need a scrollbar? - { - CUIRect Scroll; - ToolBox.VSplitRight(15.0f, &ToolBox, &Scroll); - ToolBox.VSplitRight(3.0f, &ToolBox, 0); // extra spacing - Scroll.HMargin(5.0f, &Scroll); - s_ScrollValue = UiDoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue); - } - - float ImageStartAt = ScrollDifference * s_ScrollValue; - if(ImageStartAt < 0.0f) - ImageStartAt = 0.0f; - - float ImageStopAt = ImagesHeight - ScrollDifference * (1 - s_ScrollValue); - float ImageCur = 0.0f; - - for(int e = 0; e < 2; e++) // two passes, first embedded, then external - { - CUIRect Slot; - - if(ImageCur > ImageStopAt) - break; - else if(ImageCur >= ImageStartAt) - { - - ToolBox.HSplitTop(15.0f, &Slot, &ToolBox); - if(e == 0) - UI()->DoLabel(&Slot, "Embedded", 12.0f, 0); - else - UI()->DoLabel(&Slot, "External", 12.0f, 0); - } - ImageCur += 15.0f; - - for(int i = 0; i < m_Map.m_lImages.size(); i++) - { - if((e && !m_Map.m_lImages[i]->m_External) || - (!e && m_Map.m_lImages[i]->m_External)) - { - continue; - } - - if(ImageCur > ImageStopAt) - break; - else if(ImageCur < ImageStartAt) - { - ImageCur += 14.0f; - continue; - } - ImageCur += 14.0f; - - char aBuf[128]; - str_copy(aBuf, m_Map.m_lImages[i]->m_aName, sizeof(aBuf)); - ToolBox.HSplitTop(12.0f, &Slot, &ToolBox); - - if(int Result = DoButton_Editor(&m_Map.m_lImages[i], aBuf, m_SelectedImage == i, &Slot, - BUTTON_CONTEXT, "Select image")) - { - m_SelectedImage = i; - - static int s_PopupImageID = 0; - if(Result == 2) - UiInvokePopupMenu(&s_PopupImageID, 0, UI()->MouseX(), UI()->MouseY(), 120, 80, PopupImage); - } - - ToolBox.HSplitTop(2.0f, 0, &ToolBox); - - // render image - if(m_SelectedImage == i) - { - CUIRect r; - View.Margin(10.0f, &r); - if(r.h < r.w) - r.w = r.h; - else - r.h = r.w; - Graphics()->TextureSet(m_Map.m_lImages[i]->m_TexID); - Graphics()->BlendNormal(); - Graphics()->QuadsBegin(); - IGraphics::CQuadItem QuadItem(r.x, r.y, r.w, r.h); - Graphics()->QuadsDrawTL(&QuadItem, 1); - Graphics()->QuadsEnd(); - - } - } - } - - if(ImageCur + 27.0f > ImageStopAt) - return; - - CUIRect Slot; - ToolBox.HSplitTop(5.0f, &Slot, &ToolBox); - - // new image - static int s_NewImageButton = 0; - ToolBox.HSplitTop(10.0f, &Slot, &ToolBox); - ToolBox.HSplitTop(12.0f, &Slot, &ToolBox); - if(DoButton_Editor(&s_NewImageButton, "Add", 0, &Slot, 0, "Load a new image to use in the map")) - InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Add Image", "Add", "mapres", "", AddImage, this); -} - - -static int EditorListdirCallback(const char *pName, int IsDir, int StorageType, void *pUser) -{ - CEditor *pEditor = (CEditor*)pUser; - int Length = str_length(pName); - if((pName[0] == '.' && (pName[1] == 0 || - (pName[1] == '.' && pName[2] == 0 && (!str_comp(pEditor->m_pFileDialogPath, "maps") || !str_comp(pEditor->m_pFileDialogPath, "mapres"))))) || - (!IsDir && ((pEditor->m_FileDialogFileType == CEditor::FILETYPE_MAP && (Length < 4 || str_comp(pName+Length-4, ".map"))) || - (pEditor->m_FileDialogFileType == CEditor::FILETYPE_IMG && (Length < 4 || str_comp(pName+Length-4, ".png")))))) - return 0; - - CEditor::CFilelistItem Item; - str_copy(Item.m_aFilename, pName, sizeof(Item.m_aFilename)); - if(IsDir) - str_format(Item.m_aName, sizeof(Item.m_aName), "%s/", pName); - else - str_copy(Item.m_aName, pName, min(static_cast(sizeof(Item.m_aName)), Length-3)); - Item.m_IsDir = IsDir != 0; - Item.m_IsLink = false; - Item.m_StorageType = StorageType; - pEditor->m_FileList.add(Item); - - return 0; -} - -void CEditor::AddFileDialogEntry(int Index, CUIRect *pView) -{ - m_FilesCur++; - if(m_FilesCur-1 < m_FilesStartAt || m_FilesCur >= m_FilesStopAt) - return; - - CUIRect Button, FileIcon; - pView->HSplitTop(15.0f, &Button, pView); - pView->HSplitTop(2.0f, 0, pView); - Button.VSplitLeft(Button.h, &FileIcon, &Button); - Button.VSplitLeft(5.0f, 0, &Button); - - Graphics()->TextureSet(g_pData->m_aImages[IMAGE_FILEICONS].m_Id); - Graphics()->QuadsBegin(); - RenderTools()->SelectSprite(m_FileList[Index].m_IsDir?SPRITE_FILE_FOLDER:SPRITE_FILE_MAP2); - IGraphics::CQuadItem QuadItem(FileIcon.x, FileIcon.y, FileIcon.w, FileIcon.h); - Graphics()->QuadsDrawTL(&QuadItem, 1); - Graphics()->QuadsEnd(); - - if(DoButton_File((void*)(10+(int)Button.y), m_FileList[Index].m_aName, m_FilesSelectedIndex == Index, &Button, 0, 0)) - { - if(!m_FileList[Index].m_IsDir) - str_copy(m_aFileDialogFileName, m_FileList[Index].m_aFilename, sizeof(m_aFileDialogFileName)); - else - m_aFileDialogFileName[0] = 0; - m_FilesSelectedIndex = Index; - - if(Input()->MouseDoubleClick()) - m_aFileDialogActivate = true; - } -} - -void CEditor::RenderFileDialog() -{ - // GUI coordsys - Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); - CUIRect View = *UI()->Screen(); - float Width = View.w, Height = View.h; - - RenderTools()->DrawUIRect(&View, vec4(0,0,0,0.25f), 0, 0); - View.VMargin(150.0f, &View); - View.HMargin(50.0f, &View); - RenderTools()->DrawUIRect(&View, vec4(0,0,0,0.75f), CUI::CORNER_ALL, 5.0f); - View.Margin(10.0f, &View); - - CUIRect Title, FileBox, FileBoxLabel, ButtonBar, Scroll; - View.HSplitTop(18.0f, &Title, &View); - View.HSplitTop(5.0f, 0, &View); // some spacing - View.HSplitBottom(14.0f, &View, &ButtonBar); - View.HSplitBottom(10.0f, &View, 0); // some spacing - View.HSplitBottom(14.0f, &View, &FileBox); - FileBox.VSplitLeft(55.0f, &FileBoxLabel, &FileBox); - View.HSplitBottom(10.0f, &View, 0); // some spacing - View.VSplitRight(15.0f, &View, &Scroll); - - // title - RenderTools()->DrawUIRect(&Title, vec4(1, 1, 1, 0.25f), CUI::CORNER_ALL, 4.0f); - Title.VMargin(10.0f, &Title); - UI()->DoLabel(&Title, m_pFileDialogTitle, 12.0f, -1, -1); - - // filebox - if(m_FileDialogStorageType == IStorage::TYPE_SAVE) - { - static int s_FileBoxID = 0; - UI()->DoLabel(&FileBoxLabel, "Filename:", 10.0f, -1, -1); - if(DoEditBox(&s_FileBoxID, &FileBox, m_aFileDialogFileName, sizeof(m_aFileDialogFileName), 10.0f)) - { - // remove '/' and '\' - for(int i = 0; m_aFileDialogFileName[i]; ++i) - if(m_aFileDialogFileName[i] == '/' || m_aFileDialogFileName[i] == '\\') - str_copy(&m_aFileDialogFileName[i], &m_aFileDialogFileName[i+1], (int)(sizeof(m_aFileDialogFileName))-i); - m_FilesSelectedIndex = -1; - } - } - - int Num = (int)(View.h/17.0f)+1; - static int ScrollBar = 0; - Scroll.HMargin(5.0f, &Scroll); - m_FileDialogScrollValue = UiDoScrollbarV(&ScrollBar, &Scroll, m_FileDialogScrollValue); - - int ScrollNum = m_FileList.size()-Num+1; - if(ScrollNum > 0) - { - if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP)) - m_FileDialogScrollValue -= 3.0f/ScrollNum; - if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN)) - m_FileDialogScrollValue += 3.0f/ScrollNum; - } - else - ScrollNum = 0; - - if(m_FilesSelectedIndex > -1) - { - for(int i = 0; i < Input()->NumEvents(); i++) - { - int NewIndex = -1; - if(Input()->GetEvent(i).m_Flags&IInput::FLAG_PRESS) - { - if(Input()->GetEvent(i).m_Key == KEY_DOWN) NewIndex = m_FilesSelectedIndex + 1; - if(Input()->GetEvent(i).m_Key == KEY_UP) NewIndex = m_FilesSelectedIndex - 1; - } - if(NewIndex > -1 && NewIndex < m_FileList.size()) - { - //scroll - float IndexY = View.y - m_FileDialogScrollValue*ScrollNum*17.0f + NewIndex*17.0f; - int Scroll = View.y > IndexY ? -1 : View.y+View.h < IndexY+17.0f ? 1 : 0; - if(Scroll) - { - if(Scroll < 0) - m_FileDialogScrollValue = ((float)(NewIndex)+0.5f)/ScrollNum; - else - m_FileDialogScrollValue = ((float)(NewIndex-Num)+2.5f)/ScrollNum; - } - - if(!m_FileList[NewIndex].m_IsDir) - str_copy(m_aFileDialogFileName, m_FileList[NewIndex].m_aFilename, sizeof(m_aFileDialogFileName)); - else - m_aFileDialogFileName[0] = 0; - m_FilesSelectedIndex = NewIndex; - } - } - } - - for(int i = 0; i < Input()->NumEvents(); i++) - { - if(Input()->GetEvent(i).m_Flags&IInput::FLAG_PRESS) - { - if(Input()->GetEvent(i).m_Key == KEY_RETURN || Input()->GetEvent(i).m_Key == KEY_KP_ENTER) - m_aFileDialogActivate = true; - } - } - - if(m_FileDialogScrollValue < 0) m_FileDialogScrollValue = 0; - if(m_FileDialogScrollValue > 1) m_FileDialogScrollValue = 1; - - m_FilesStartAt = (int)(ScrollNum*m_FileDialogScrollValue); - if(m_FilesStartAt < 0) - m_FilesStartAt = 0; - - m_FilesStopAt = m_FilesStartAt+Num; - - m_FilesCur = 0; - - // set clipping - UI()->ClipEnable(&View); - - for(int i = 0; i < m_FileList.size(); i++) - AddFileDialogEntry(i, &View); - - // disable clipping again - UI()->ClipDisable(); - - // the buttons - static int s_OkButton = 0; - static int s_CancelButton = 0; - static int s_NewFolderButton = 0; - - CUIRect Button; - ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button); - bool IsDir = m_FilesSelectedIndex >= 0 && m_FileList[m_FilesSelectedIndex].m_IsDir; - if(DoButton_Editor(&s_OkButton, IsDir ? "Open" : m_pFileDialogButtonText, 0, &Button, 0, 0) || m_aFileDialogActivate) - { - m_aFileDialogActivate = false; - if(IsDir) // folder - { - if(str_comp(m_FileList[m_FilesSelectedIndex].m_aFilename, "..") == 0) // parent folder - { - if(fs_parent_dir(m_pFileDialogPath)) - m_pFileDialogPath = m_aFileDialogCurrentFolder; // leave the link - } - else // sub folder - { - if(m_FileList[m_FilesSelectedIndex].m_IsLink) - { - m_pFileDialogPath = m_aFileDialogCurrentLink; // follow the link - str_copy(m_aFileDialogCurrentLink, m_FileList[m_FilesSelectedIndex].m_aFilename, sizeof(m_aFileDialogCurrentLink)); - } - else - { - char aTemp[MAX_PATH_LENGTH]; - str_copy(aTemp, m_pFileDialogPath, sizeof(aTemp)); - str_format(m_pFileDialogPath, MAX_PATH_LENGTH, "%s/%s", aTemp, m_FileList[m_FilesSelectedIndex].m_aFilename); - } - } - FilelistPopulate(!str_comp(m_pFileDialogPath, "maps") || !str_comp(m_pFileDialogPath, "mapres") ? m_FileDialogStorageType : - m_FileList[m_FilesSelectedIndex].m_StorageType); - if(m_FilesSelectedIndex >= 0 && !m_FileList[m_FilesSelectedIndex].m_IsDir) - str_copy(m_aFileDialogFileName, m_FileList[m_FilesSelectedIndex].m_aFilename, sizeof(m_aFileDialogFileName)); - else - m_aFileDialogFileName[0] = 0; - } - else // file - { - str_format(m_aFileSaveName, sizeof(m_aFileSaveName), "%s/%s", m_pFileDialogPath, m_aFileDialogFileName); - if(!str_comp(m_pFileDialogButtonText, "Save")) - { - IOHANDLE File = Storage()->OpenFile(m_aFileSaveName, IOFLAG_READ, IStorage::TYPE_SAVE); - if(File) - { - io_close(File); - m_PopupEventType = POPEVENT_SAVE; - m_PopupEventActivated = true; - } - else - if(m_pfnFileDialogFunc) - m_pfnFileDialogFunc(m_aFileSaveName, m_FilesSelectedIndex >= 0 ? m_FileList[m_FilesSelectedIndex].m_StorageType : m_FileDialogStorageType, m_pFileDialogUser); - } - else - if(m_pfnFileDialogFunc) - m_pfnFileDialogFunc(m_aFileSaveName, m_FilesSelectedIndex >= 0 ? m_FileList[m_FilesSelectedIndex].m_StorageType : m_FileDialogStorageType, m_pFileDialogUser); - } - } - - ButtonBar.VSplitRight(40.0f, &ButtonBar, &Button); - ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button); - if(DoButton_Editor(&s_CancelButton, "Cancel", 0, &Button, 0, 0) || Input()->KeyPressed(KEY_ESCAPE)) - m_Dialog = DIALOG_NONE; - - if(m_FileDialogStorageType == IStorage::TYPE_SAVE) - { - ButtonBar.VSplitLeft(40.0f, 0, &ButtonBar); - ButtonBar.VSplitLeft(70.0f, &Button, &ButtonBar); - if(DoButton_Editor(&s_NewFolderButton, "New folder", 0, &Button, 0, 0)) - { - m_FileDialogNewFolderName[0] = 0; - m_FileDialogErrString[0] = 0; - static int s_NewFolderPopupID = 0; - UiInvokePopupMenu(&s_NewFolderPopupID, 0, Width/2.0f-200.0f, Height/2.0f-100.0f, 400.0f, 200.0f, PopupNewFolder); - UI()->SetActiveItem(0); - } - } -} - -void CEditor::FilelistPopulate(int StorageType) -{ - m_FileList.clear(); - if(m_FileDialogStorageType != IStorage::TYPE_SAVE && !str_comp(m_pFileDialogPath, "maps")) - { - CFilelistItem Item; - str_copy(Item.m_aFilename, "downloadedmaps", sizeof(Item.m_aFilename)); - str_copy(Item.m_aName, "downloadedmaps/", sizeof(Item.m_aName)); - Item.m_IsDir = true; - Item.m_IsLink = true; - Item.m_StorageType = IStorage::TYPE_SAVE; - m_FileList.add(Item); - } - Storage()->ListDirectory(StorageType, m_pFileDialogPath, EditorListdirCallback, this); - m_FilesSelectedIndex = m_FileList.size() ? 0 : -1; - m_aFileDialogActivate = false; -} - -void CEditor::InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText, - const char *pBasePath, const char *pDefaultName, - void (*pfnFunc)(const char *pFileName, int StorageType, void *pUser), void *pUser) -{ - m_FileDialogStorageType = StorageType; - m_pFileDialogTitle = pTitle; - m_pFileDialogButtonText = pButtonText; - m_pfnFileDialogFunc = pfnFunc; - m_pFileDialogUser = pUser; - m_aFileDialogFileName[0] = 0; - m_aFileDialogCurrentFolder[0] = 0; - m_aFileDialogCurrentLink[0] = 0; - m_pFileDialogPath = m_aFileDialogCurrentFolder; - m_FileDialogFileType = FileType; - m_FileDialogScrollValue = 0.0f; - - if(pDefaultName) - str_copy(m_aFileDialogFileName, pDefaultName, sizeof(m_aFileDialogFileName)); - if(pBasePath) - str_copy(m_aFileDialogCurrentFolder, pBasePath, sizeof(m_aFileDialogCurrentFolder)); - - FilelistPopulate(m_FileDialogStorageType); - - m_Dialog = DIALOG_FILE; -} - - - -void CEditor::RenderModebar(CUIRect View) -{ - CUIRect Button; - - // mode buttons - { - View.VSplitLeft(65.0f, &Button, &View); - Button.HSplitTop(30.0f, 0, &Button); - static int s_Button = 0; - const char *pButName = m_Mode == MODE_LAYERS ? "Layers" : "Images"; - if(DoButton_Tab(&s_Button, pButName, 0, &Button, 0, "Switch between images and layers managment.")) - { - if(m_Mode == MODE_LAYERS) - m_Mode = MODE_IMAGES; - else - m_Mode = MODE_LAYERS; - } - } - - View.VSplitLeft(5.0f, 0, &View); -} - -void CEditor::RenderStatusbar(CUIRect View) -{ - CUIRect Button; - View.VSplitRight(60.0f, &View, &Button); - static int s_EnvelopeButton = 0; - if(DoButton_Editor(&s_EnvelopeButton, "Envelopes", m_ShowEnvelopeEditor, &Button, 0, "Toggles the envelope editor.")) - m_ShowEnvelopeEditor = (m_ShowEnvelopeEditor+1)%4; - - if(m_pTooltip) - { - if(ms_pUiGotContext && ms_pUiGotContext == UI()->HotItem()) - { - char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "%s Right click for context menu.", m_pTooltip); - UI()->DoLabel(&View, aBuf, 10.0f, -1, -1); - } - else - UI()->DoLabel(&View, m_pTooltip, 10.0f, -1, -1); - } -} - -void CEditor::RenderEnvelopeEditor(CUIRect View) -{ - if(m_SelectedEnvelope < 0) m_SelectedEnvelope = 0; - if(m_SelectedEnvelope >= m_Map.m_lEnvelopes.size()) m_SelectedEnvelope = m_Map.m_lEnvelopes.size()-1; - - CEnvelope *pEnvelope = 0; - if(m_SelectedEnvelope >= 0 && m_SelectedEnvelope < m_Map.m_lEnvelopes.size()) - pEnvelope = m_Map.m_lEnvelopes[m_SelectedEnvelope]; - - CUIRect ToolBar, CurveBar, ColorBar; - View.HSplitTop(15.0f, &ToolBar, &View); - View.HSplitTop(15.0f, &CurveBar, &View); - ToolBar.Margin(2.0f, &ToolBar); - CurveBar.Margin(2.0f, &CurveBar); - - // do the toolbar - { - CUIRect Button; - CEnvelope *pNewEnv = 0; - - ToolBar.VSplitRight(50.0f, &ToolBar, &Button); - static int s_New4dButton = 0; - if(DoButton_Editor(&s_New4dButton, "Color+", 0, &Button, 0, "Creates a new color envelope")) - { - m_Map.m_Modified = true; - pNewEnv = m_Map.NewEnvelope(4); - } - - ToolBar.VSplitRight(5.0f, &ToolBar, &Button); - ToolBar.VSplitRight(50.0f, &ToolBar, &Button); - static int s_New2dButton = 0; - if(DoButton_Editor(&s_New2dButton, "Pos.+", 0, &Button, 0, "Creates a new pos envelope")) - { - m_Map.m_Modified = true; - pNewEnv = m_Map.NewEnvelope(3); - } - - // Delete button - if(m_SelectedEnvelope >= 0) - { - ToolBar.VSplitRight(10.0f, &ToolBar, &Button); - ToolBar.VSplitRight(50.0f, &ToolBar, &Button); - static int s_DelButton = 0; - if(DoButton_Editor(&s_DelButton, "Delete", 0, &Button, 0, "Delete this envelope")) - { - m_Map.m_Modified = true; - m_Map.DeleteEnvelope(m_SelectedEnvelope); - if(m_SelectedEnvelope >= m_Map.m_lEnvelopes.size()) - m_SelectedEnvelope = m_Map.m_lEnvelopes.size()-1; - pEnvelope = m_SelectedEnvelope >= 0 ? m_Map.m_lEnvelopes[m_SelectedEnvelope] : 0; - } - } - - if(pNewEnv) // add the default points - { - if(pNewEnv->m_Channels == 4) - { - pNewEnv->AddPoint(0, 1,1,1,1); - pNewEnv->AddPoint(1000, 1,1,1,1); - } - else - { - pNewEnv->AddPoint(0, 0); - pNewEnv->AddPoint(1000, 0); - } - } - - CUIRect Shifter, Inc, Dec; - ToolBar.VSplitLeft(60.0f, &Shifter, &ToolBar); - Shifter.VSplitRight(15.0f, &Shifter, &Inc); - Shifter.VSplitLeft(15.0f, &Dec, &Shifter); - char aBuf[512]; - str_format(aBuf, sizeof(aBuf),"%d/%d", m_SelectedEnvelope+1, m_Map.m_lEnvelopes.size()); - RenderTools()->DrawUIRect(&Shifter, vec4(1,1,1,0.5f), 0, 0.0f); - UI()->DoLabel(&Shifter, aBuf, 10.0f, 0, -1); - - static int s_PrevButton = 0; - if(DoButton_ButtonDec(&s_PrevButton, 0, 0, &Dec, 0, "Previous Envelope")) - m_SelectedEnvelope--; - - static int s_NextButton = 0; - if(DoButton_ButtonInc(&s_NextButton, 0, 0, &Inc, 0, "Next Envelope")) - m_SelectedEnvelope++; - - if(pEnvelope) - { - ToolBar.VSplitLeft(15.0f, &Button, &ToolBar); - ToolBar.VSplitLeft(35.0f, &Button, &ToolBar); - UI()->DoLabel(&Button, "Name:", 10.0f, -1, -1); - - ToolBar.VSplitLeft(80.0f, &Button, &ToolBar); - - static int s_NameBox = 0; - if(DoEditBox(&s_NameBox, &Button, pEnvelope->m_aName, sizeof(pEnvelope->m_aName), 10.0f)) - m_Map.m_Modified = true; - } - } - - bool ShowColorBar = false; - if(pEnvelope && pEnvelope->m_Channels == 4) - { - ShowColorBar = true; - View.HSplitTop(20.0f, &ColorBar, &View); - ColorBar.Margin(2.0f, &ColorBar); - RenderBackground(ColorBar, ms_CheckerTexture, 16.0f, 1.0f); - } - - RenderBackground(View, ms_CheckerTexture, 32.0f, 0.1f); - - if(pEnvelope) - { - static array Selection; - static int sEnvelopeEditorID = 0; - static int s_ActiveChannels = 0xf; - - if(pEnvelope) - { - CUIRect Button; - - ToolBar.VSplitLeft(15.0f, &Button, &ToolBar); - - static const char *s_paNames[2][4] = { - {"X", "Y", "R", ""}, - {"R", "G", "B", "A"}, - }; - - const char *paDescriptions[2][4] = { - {"X-axis of the envelope", "Y-axis of the envelope", "Rotation of the envelope", ""}, - {"Red value of the envelope", "Green value of the envelope", "Blue value of the envelope", "Alpha value of the envelope"}, - }; - - static int s_aChannelButtons[4] = {0}; - int Bit = 1; - //ui_draw_button_func draw_func; - - for(int i = 0; i < pEnvelope->m_Channels; i++, Bit<<=1) - { - ToolBar.VSplitLeft(15.0f, &Button, &ToolBar); - - /*if(i == 0) draw_func = draw_editor_button_l; - else if(i == envelope->channels-1) draw_func = draw_editor_button_r; - else draw_func = draw_editor_button_m;*/ - - if(DoButton_Editor(&s_aChannelButtons[i], s_paNames[pEnvelope->m_Channels-3][i], s_ActiveChannels&Bit, &Button, 0, paDescriptions[pEnvelope->m_Channels-3][i])) - s_ActiveChannels ^= Bit; - } - } - - float EndTime = pEnvelope->EndTime(); - if(EndTime < 1) - EndTime = 1; - - pEnvelope->FindTopBottom(s_ActiveChannels); - float Top = pEnvelope->m_Top; - float Bottom = pEnvelope->m_Bottom; - - if(Top < 1) - Top = 1; - if(Bottom >= 0) - Bottom = 0; - - float TimeScale = EndTime/View.w; - float ValueScale = (Top-Bottom)/View.h; - - if(UI()->MouseInside(&View)) - UI()->SetHotItem(&sEnvelopeEditorID); - - if(UI()->HotItem() == &sEnvelopeEditorID) - { - // do stuff - if(pEnvelope) - { - if(UI()->MouseButtonClicked(1)) - { - // add point - int Time = (int)(((UI()->MouseX()-View.x)*TimeScale)*1000.0f); - //float env_y = (UI()->MouseY()-view.y)/TimeScale; - float aChannels[4]; - pEnvelope->Eval(Time, aChannels); - pEnvelope->AddPoint(Time, - f2fx(aChannels[0]), f2fx(aChannels[1]), - f2fx(aChannels[2]), f2fx(aChannels[3])); - m_Map.m_Modified = true; - } - - m_pTooltip = "Press right mouse button to create a new point"; - } - } - - vec3 aColors[] = {vec3(1,0.2f,0.2f), vec3(0.2f,1,0.2f), vec3(0.2f,0.2f,1), vec3(1,1,0.2f)}; - - // render lines - { - UI()->ClipEnable(&View); - Graphics()->TextureSet(-1); - Graphics()->LinesBegin(); - for(int c = 0; c < pEnvelope->m_Channels; c++) - { - if(s_ActiveChannels&(1<SetColor(aColors[c].r,aColors[c].g,aColors[c].b,1); - else - Graphics()->SetColor(aColors[c].r*0.5f,aColors[c].g*0.5f,aColors[c].b*0.5f,1); - - float PrevX = 0; - float aResults[4]; - pEnvelope->Eval(0.000001f, aResults); - float PrevValue = aResults[c]; - - int Steps = (int)((View.w/UI()->Screen()->w) * Graphics()->ScreenWidth()); - for(int i = 1; i <= Steps; i++) - { - float a = i/(float)Steps; - pEnvelope->Eval(a*EndTime, aResults); - float v = aResults[c]; - v = (v-Bottom)/(Top-Bottom); - - IGraphics::CLineItem LineItem(View.x + PrevX*View.w, View.y+View.h - PrevValue*View.h, View.x + a*View.w, View.y+View.h - v*View.h); - Graphics()->LinesDraw(&LineItem, 1); - PrevX = a; - PrevValue = v; - } - } - Graphics()->LinesEnd(); - UI()->ClipDisable(); - } - - // render curve options - { - for(int i = 0; i < pEnvelope->m_lPoints.size()-1; i++) - { - float t0 = pEnvelope->m_lPoints[i].m_Time/1000.0f/EndTime; - float t1 = pEnvelope->m_lPoints[i+1].m_Time/1000.0f/EndTime; - - //dbg_msg("", "%f", end_time); - - CUIRect v; - v.x = CurveBar.x + (t0+(t1-t0)*0.5f) * CurveBar.w; - v.y = CurveBar.y; - v.h = CurveBar.h; - v.w = CurveBar.h; - v.x -= v.w/2; - void *pID = &pEnvelope->m_lPoints[i].m_Curvetype; - const char *paTypeName[] = { - "N", "L", "S", "F", "M" - }; - - if(DoButton_Editor(pID, paTypeName[pEnvelope->m_lPoints[i].m_Curvetype], 0, &v, 0, "Switch curve type")) - pEnvelope->m_lPoints[i].m_Curvetype = (pEnvelope->m_lPoints[i].m_Curvetype+1)%NUM_CURVETYPES; - } - } - - // render colorbar - if(ShowColorBar) - { - Graphics()->TextureSet(-1); - Graphics()->QuadsBegin(); - for(int i = 0; i < pEnvelope->m_lPoints.size()-1; i++) - { - float r0 = fx2f(pEnvelope->m_lPoints[i].m_aValues[0]); - float g0 = fx2f(pEnvelope->m_lPoints[i].m_aValues[1]); - float b0 = fx2f(pEnvelope->m_lPoints[i].m_aValues[2]); - float a0 = fx2f(pEnvelope->m_lPoints[i].m_aValues[3]); - float r1 = fx2f(pEnvelope->m_lPoints[i+1].m_aValues[0]); - float g1 = fx2f(pEnvelope->m_lPoints[i+1].m_aValues[1]); - float b1 = fx2f(pEnvelope->m_lPoints[i+1].m_aValues[2]); - float a1 = fx2f(pEnvelope->m_lPoints[i+1].m_aValues[3]); - - IGraphics::CColorVertex Array[4] = {IGraphics::CColorVertex(0, r0, g0, b0, a0), - IGraphics::CColorVertex(1, r1, g1, b1, a1), - IGraphics::CColorVertex(2, r1, g1, b1, a1), - IGraphics::CColorVertex(3, r0, g0, b0, a0)}; - Graphics()->SetColorVertex(Array, 4); - - float x0 = pEnvelope->m_lPoints[i].m_Time/1000.0f/EndTime; -// float y0 = (fx2f(envelope->points[i].values[c])-bottom)/(top-bottom); - float x1 = pEnvelope->m_lPoints[i+1].m_Time/1000.0f/EndTime; - //float y1 = (fx2f(envelope->points[i+1].values[c])-bottom)/(top-bottom); - CUIRect v; - v.x = ColorBar.x + x0*ColorBar.w; - v.y = ColorBar.y; - v.w = (x1-x0)*ColorBar.w; - v.h = ColorBar.h; - - IGraphics::CQuadItem QuadItem(v.x, v.y, v.w, v.h); - Graphics()->QuadsDrawTL(&QuadItem, 1); - } - Graphics()->QuadsEnd(); - } - - // render handles - { - static bool s_Move = false; - - int CurrentValue = 0, CurrentTime = 0; - - Graphics()->TextureSet(-1); - Graphics()->QuadsBegin(); - for(int c = 0; c < pEnvelope->m_Channels; c++) - { - if(!(s_ActiveChannels&(1<m_lPoints.size(); i++) - { - float x0 = pEnvelope->m_lPoints[i].m_Time/1000.0f/EndTime; - float y0 = (fx2f(pEnvelope->m_lPoints[i].m_aValues[c])-Bottom)/(Top-Bottom); - CUIRect Final; - Final.x = View.x + x0*View.w; - Final.y = View.y+View.h - y0*View.h; - Final.x -= 2.0f; - Final.y -= 2.0f; - Final.w = 4.0f; - Final.h = 4.0f; - - void *pID = &pEnvelope->m_lPoints[i].m_aValues[c]; - - if(UI()->MouseInside(&Final)) - UI()->SetHotItem(pID); - - float ColorMod = 1.0f; - - if(UI()->ActiveItem() == pID) - { - if(!UI()->MouseButton(0)) - { - UI()->SetActiveItem(0); - s_Move = false; - } - else - { - if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) - { - if(i != 0) - { - if((Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL))) - pEnvelope->m_lPoints[i].m_Time += (int)((m_MouseDeltaX)); - else - pEnvelope->m_lPoints[i].m_Time += (int)((m_MouseDeltaX*TimeScale)*1000.0f); - if(pEnvelope->m_lPoints[i].m_Time < pEnvelope->m_lPoints[i-1].m_Time) - pEnvelope->m_lPoints[i].m_Time = pEnvelope->m_lPoints[i-1].m_Time + 1; - if(i+1 != pEnvelope->m_lPoints.size() && pEnvelope->m_lPoints[i].m_Time > pEnvelope->m_lPoints[i+1].m_Time) - pEnvelope->m_lPoints[i].m_Time = pEnvelope->m_lPoints[i+1].m_Time - 1; - } - } - else - { - if((Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL))) - pEnvelope->m_lPoints[i].m_aValues[c] -= f2fx(m_MouseDeltaY*0.001f); - else - pEnvelope->m_lPoints[i].m_aValues[c] -= f2fx(m_MouseDeltaY*ValueScale); - } - m_Map.m_Modified = true; - } - - ColorMod = 100.0f; - Graphics()->SetColor(1,1,1,1); - } - else if(UI()->HotItem() == pID) - { - if(UI()->MouseButton(0)) - { - Selection.clear(); - Selection.add(i); - UI()->SetActiveItem(pID); - } - - // remove point - if(UI()->MouseButtonClicked(1)) - { - pEnvelope->m_lPoints.remove_index(i); - m_Map.m_Modified = true; - } - - ColorMod = 100.0f; - Graphics()->SetColor(1,0.75f,0.75f,1); - m_pTooltip = "Left mouse to drag. Hold ctrl to be more precise. Hold shift to alter time point aswell. Right click to delete."; - } - - if(UI()->ActiveItem() == pID || UI()->HotItem() == pID) - { - CurrentTime = pEnvelope->m_lPoints[i].m_Time; - CurrentValue = pEnvelope->m_lPoints[i].m_aValues[c]; - } - - Graphics()->SetColor(aColors[c].r*ColorMod, aColors[c].g*ColorMod, aColors[c].b*ColorMod, 1.0f); - IGraphics::CQuadItem QuadItem(Final.x, Final.y, Final.w, Final.h); - Graphics()->QuadsDrawTL(&QuadItem, 1); - } - } - Graphics()->QuadsEnd(); - - char aBuf[512]; - str_format(aBuf, sizeof(aBuf),"%.3f %.3f", CurrentTime/1000.0f, fx2f(CurrentValue)); - UI()->DoLabel(&ToolBar, aBuf, 10.0f, 0, -1); - } - } -} - -int CEditor::PopupMenuFile(CEditor *pEditor, CUIRect View) -{ - static int s_NewMapButton = 0; - static int s_SaveButton = 0; - static int s_SaveAsButton = 0; - static int s_OpenButton = 0; - static int s_AppendButton = 0; - static int s_ExitButton = 0; - - CUIRect Slot; - View.HSplitTop(2.0f, &Slot, &View); - View.HSplitTop(12.0f, &Slot, &View); - if(pEditor->DoButton_MenuItem(&s_NewMapButton, "New", 0, &Slot, 0, "Creates a new map")) - { - if(pEditor->HasUnsavedData()) - { - pEditor->m_PopupEventType = POPEVENT_NEW; - pEditor->m_PopupEventActivated = true; - } - else - { - pEditor->Reset(); - pEditor->m_aFileName[0] = 0; - } - return 1; - } - - View.HSplitTop(10.0f, &Slot, &View); - View.HSplitTop(12.0f, &Slot, &View); - if(pEditor->DoButton_MenuItem(&s_OpenButton, "Load", 0, &Slot, 0, "Opens a map for editing")) - { - if(pEditor->HasUnsavedData()) - { - pEditor->m_PopupEventType = POPEVENT_LOAD; - pEditor->m_PopupEventActivated = true; - } - else - pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_MAP, "Load map", "Load", "maps", "", pEditor->CallbackOpenMap, pEditor); - return 1; - } - - View.HSplitTop(10.0f, &Slot, &View); - View.HSplitTop(12.0f, &Slot, &View); - if(pEditor->DoButton_MenuItem(&s_AppendButton, "Append", 0, &Slot, 0, "Opens a map and adds everything from that map to the current one")) - { - pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_MAP, "Append map", "Append", "maps", "", pEditor->CallbackAppendMap, pEditor); - return 1; - } - - View.HSplitTop(10.0f, &Slot, &View); - View.HSplitTop(12.0f, &Slot, &View); - if(pEditor->DoButton_MenuItem(&s_SaveButton, "Save", 0, &Slot, 0, "Saves the current map")) - { - if(pEditor->m_aFileName[0] && pEditor->m_ValidSaveFilename) - { - str_copy(pEditor->m_aFileSaveName, pEditor->m_aFileName, sizeof(pEditor->m_aFileSaveName)); - pEditor->m_PopupEventType = POPEVENT_SAVE; - pEditor->m_PopupEventActivated = true; - } - else - pEditor->InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", "", pEditor->CallbackSaveMap, pEditor); - return 1; - } - - View.HSplitTop(2.0f, &Slot, &View); - View.HSplitTop(12.0f, &Slot, &View); - if(pEditor->DoButton_MenuItem(&s_SaveAsButton, "Save As", 0, &Slot, 0, "Saves the current map under a new name")) - { - pEditor->InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", "", pEditor->CallbackSaveMap, pEditor); - return 1; - } - - View.HSplitTop(10.0f, &Slot, &View); - View.HSplitTop(12.0f, &Slot, &View); - if(pEditor->DoButton_MenuItem(&s_ExitButton, "Exit", 0, &Slot, 0, "Exits from the editor")) - { - if(pEditor->HasUnsavedData()) - { - pEditor->m_PopupEventType = POPEVENT_EXIT; - pEditor->m_PopupEventActivated = true; - } - else - g_Config.m_ClEditor = 0; - return 1; - } - - return 0; -} - -void CEditor::RenderMenubar(CUIRect MenuBar) -{ - static CUIRect s_File /*, view, help*/; - - MenuBar.VSplitLeft(60.0f, &s_File, &MenuBar); - if(DoButton_Menu(&s_File, "File", 0, &s_File, 0, 0)) - UiInvokePopupMenu(&s_File, 1, s_File.x, s_File.y+s_File.h-1.0f, 120, 150, PopupMenuFile, this); - - /* - menubar.VSplitLeft(5.0f, 0, &menubar); - menubar.VSplitLeft(60.0f, &view, &menubar); - if(do_editor_button(&view, "View", 0, &view, draw_editor_button_menu, 0, 0)) - (void)0; - - menubar.VSplitLeft(5.0f, 0, &menubar); - menubar.VSplitLeft(60.0f, &help, &menubar); - if(do_editor_button(&help, "Help", 0, &help, draw_editor_button_menu, 0, 0)) - (void)0; - */ - - MenuBar.VSplitLeft(40.0f, 0, &MenuBar); - char aBuf[128]; - str_format(aBuf, sizeof(aBuf), "File: %s", m_aFileName); - UI()->DoLabel(&MenuBar, aBuf, 10.0f, -1, -1); -} - -void CEditor::Render() -{ - // basic start - Graphics()->Clear(1.0f, 0.0f, 1.0f); - CUIRect View = *UI()->Screen(); - Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); - - float Width = View.w; - float Height = View.h; - - // reset tip - m_pTooltip = 0; - - // render checker - RenderBackground(View, ms_CheckerTexture, 32.0f, 1.0f); - - CUIRect MenuBar, CModeBar, ToolBar, StatusBar, EnvelopeEditor, ToolBox; - bool ShowPicker = Input()->KeyPressed(KEY_SPACE) != 0 && m_Dialog == DIALOG_NONE; - - if(m_GuiActive) - { - - View.HSplitTop(16.0f, &MenuBar, &View); - View.HSplitTop(53.0f, &ToolBar, &View); - View.VSplitLeft(100.0f, &ToolBox, &View); - View.HSplitBottom(16.0f, &View, &StatusBar); - - if(m_ShowEnvelopeEditor && !ShowPicker) - { - float size = 125.0f; - if(m_ShowEnvelopeEditor == 2) - size *= 2.0f; - else if(m_ShowEnvelopeEditor == 3) - size *= 3.0f; - View.HSplitBottom(size, &View, &EnvelopeEditor); - } - } - - // a little hack for now - if(m_Mode == MODE_LAYERS) - DoMapEditor(View, ToolBar, ShowPicker); - - if(m_GuiActive) - { - float Brightness = 0.25f; - RenderBackground(MenuBar, ms_BackgroundTexture, 128.0f, Brightness*0); - MenuBar.Margin(2.0f, &MenuBar); - - RenderBackground(ToolBox, ms_BackgroundTexture, 128.0f, Brightness); - ToolBox.Margin(2.0f, &ToolBox); - - RenderBackground(ToolBar, ms_BackgroundTexture, 128.0f, Brightness); - ToolBar.Margin(2.0f, &ToolBar); - ToolBar.VSplitLeft(100.0f, &CModeBar, &ToolBar); - - RenderBackground(StatusBar, ms_BackgroundTexture, 128.0f, Brightness); - StatusBar.Margin(2.0f, &StatusBar); - - // do the toolbar - if(m_Mode == MODE_LAYERS) - DoToolbar(ToolBar); - - if(m_ShowEnvelopeEditor) - { - RenderBackground(EnvelopeEditor, ms_BackgroundTexture, 128.0f, Brightness); - EnvelopeEditor.Margin(2.0f, &EnvelopeEditor); - } - } - - - if(m_Mode == MODE_LAYERS) - RenderLayers(ToolBox, ToolBar, View); - else if(m_Mode == MODE_IMAGES) - RenderImages(ToolBox, ToolBar, View); - - Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); - - if(m_GuiActive) - { - RenderMenubar(MenuBar); - - RenderModebar(CModeBar); - if(m_ShowEnvelopeEditor) - RenderEnvelopeEditor(EnvelopeEditor); - } - - if(m_Dialog == DIALOG_FILE) - { - static int s_NullUiTarget = 0; - UI()->SetHotItem(&s_NullUiTarget); - RenderFileDialog(); - } - - if(m_PopupEventActivated) - { - static int s_PopupID = 0; - UiInvokePopupMenu(&s_PopupID, 0, Width/2.0f-200.0f, Height/2.0f-100.0f, 400.0f, 200.0f, PopupEvent); - m_PopupEventActivated = false; - } - - - UiDoPopupMenu(); - - if(m_GuiActive) - RenderStatusbar(StatusBar); - - // - if(g_Config.m_EdShowkeys) - { - Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); - CTextCursor Cursor; - TextRender()->SetCursor(&Cursor, View.x+10, View.y+View.h-24-10, 24.0f, TEXTFLAG_RENDER); - - int NKeys = 0; - for(int i = 0; i < KEY_LAST; i++) - { - if(Input()->KeyPressed(i)) - { - if(NKeys) - TextRender()->TextEx(&Cursor, " + ", -1); - TextRender()->TextEx(&Cursor, Input()->KeyName(i), -1); - NKeys++; - } - } - } - - if(m_ShowMousePointer) - { - // render butt ugly mouse cursor - float mx = UI()->MouseX(); - float my = UI()->MouseY(); - Graphics()->TextureSet(ms_CursorTexture); - Graphics()->QuadsBegin(); - if(ms_pUiGotContext == UI()->HotItem()) - Graphics()->SetColor(1,0,0,1); - IGraphics::CQuadItem QuadItem(mx,my, 16.0f, 16.0f); - Graphics()->QuadsDrawTL(&QuadItem, 1); - Graphics()->QuadsEnd(); - } - -} - -void CEditor::Reset(bool CreateDefault) -{ - m_Map.Clean(); - - // create default layers - if(CreateDefault) - m_Map.CreateDefault(ms_EntitiesTexture); - - /* - { - }*/ - - m_SelectedLayer = 0; - m_SelectedGroup = 0; - m_SelectedQuad = -1; - m_SelectedPoints = 0; - m_SelectedEnvelope = 0; - m_SelectedImage = 0; - - m_WorldOffsetX = 0; - m_WorldOffsetY = 0; - m_EditorOffsetX = 0.0f; - m_EditorOffsetY = 0.0f; - - m_WorldZoom = 1.0f; - m_ZoomLevel = 200; - - m_MouseDeltaX = 0; - m_MouseDeltaY = 0; - m_MouseDeltaWx = 0; - m_MouseDeltaWy = 0; - - m_Map.m_Modified = false; -} - -void CEditorMap::DeleteEnvelope(int Index) -{ - if(Index < 0 || Index >= m_lEnvelopes.size()) - return; - - m_Modified = true; - - // fix links between envelopes and quads - for(int i = 0; i < m_lGroups.size(); ++i) - for(int j = 0; j < m_lGroups[i]->m_lLayers.size(); ++j) - if(m_lGroups[i]->m_lLayers[j]->m_Type == LAYERTYPE_QUADS) - { - CLayerQuads *Layer = static_cast(m_lGroups[i]->m_lLayers[j]); - for(int k = 0; k < Layer->m_lQuads.size(); ++k) - { - if(Layer->m_lQuads[k].m_PosEnv == Index) - Layer->m_lQuads[k].m_PosEnv = -1; - else if(Layer->m_lQuads[k].m_PosEnv > Index) - Layer->m_lQuads[k].m_PosEnv--; - if(Layer->m_lQuads[k].m_ColorEnv == Index) - Layer->m_lQuads[k].m_ColorEnv = -1; - else if(Layer->m_lQuads[k].m_ColorEnv > Index) - Layer->m_lQuads[k].m_ColorEnv--; - } - } - - m_lEnvelopes.remove_index(Index); -} - -void CEditorMap::MakeGameLayer(CLayer *pLayer) -{ - m_pGameLayer = (CLayerGame *)pLayer; - m_pGameLayer->m_pEditor = m_pEditor; - m_pGameLayer->m_TexID = m_pEditor->ms_EntitiesTexture; -} - -void CEditorMap::MakeGameGroup(CLayerGroup *pGroup) -{ - m_pGameGroup = pGroup; - m_pGameGroup->m_GameGroup = true; - m_pGameGroup->m_pName = "Game"; -} - - - -void CEditorMap::Clean() -{ - m_lGroups.delete_all(); - m_lEnvelopes.delete_all(); - m_lImages.delete_all(); - - m_pGameLayer = 0x0; - m_pGameGroup = 0x0; - - m_Modified = false; -} - -void CEditorMap::CreateDefault(int EntitiesTexture) -{ - // add background - CLayerGroup *pGroup = NewGroup(); - pGroup->m_ParallaxX = 0; - pGroup->m_ParallaxY = 0; - CLayerQuads *pLayer = new CLayerQuads; - pLayer->m_pEditor = m_pEditor; - CQuad *pQuad = pLayer->NewQuad(); - const int Width = 800000; - const int Height = 600000; - pQuad->m_aPoints[0].x = pQuad->m_aPoints[2].x = -Width; - pQuad->m_aPoints[1].x = pQuad->m_aPoints[3].x = Width; - pQuad->m_aPoints[0].y = pQuad->m_aPoints[1].y = -Height; - pQuad->m_aPoints[2].y = pQuad->m_aPoints[3].y = Height; - pQuad->m_aColors[0].r = pQuad->m_aColors[1].r = 94; - pQuad->m_aColors[0].g = pQuad->m_aColors[1].g = 132; - pQuad->m_aColors[0].b = pQuad->m_aColors[1].b = 174; - pQuad->m_aColors[2].r = pQuad->m_aColors[3].r = 204; - pQuad->m_aColors[2].g = pQuad->m_aColors[3].g = 232; - pQuad->m_aColors[2].b = pQuad->m_aColors[3].b = 255; - pGroup->AddLayer(pLayer); - - // add game layer - MakeGameGroup(NewGroup()); - MakeGameLayer(new CLayerGame(50, 50)); - m_pGameGroup->AddLayer(m_pGameLayer); -} - -void CEditor::Init() -{ - m_pInput = Kernel()->RequestInterface(); - m_pClient = Kernel()->RequestInterface(); - m_pConsole = Kernel()->RequestInterface(); - m_pGraphics = Kernel()->RequestInterface(); - m_pTextRender = Kernel()->RequestInterface(); - m_pStorage = Kernel()->RequestInterface(); - m_RenderTools.m_pGraphics = m_pGraphics; - m_RenderTools.m_pUI = &m_UI; - m_UI.SetGraphics(m_pGraphics, m_pTextRender); - m_Map.m_pEditor = this; - - ms_CheckerTexture = Graphics()->LoadTexture("editor/checker.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); - ms_BackgroundTexture = Graphics()->LoadTexture("editor/background.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); - ms_CursorTexture = Graphics()->LoadTexture("editor/cursor.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); - ms_EntitiesTexture = Graphics()->LoadTexture("editor/entities.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); - - m_TilesetPicker.m_pEditor = this; - m_TilesetPicker.MakePalette(); - m_TilesetPicker.m_Readonly = true; - - m_Brush.m_pMap = &m_Map; - - Reset(); - m_Map.m_Modified = false; -} - -void CEditor::DoMapBorder() -{ - CLayerTiles *pT = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES); - - for(int i = 0; i < pT->m_Width*2; ++i) - pT->m_pTiles[i].m_Index = 1; - - for(int i = 0; i < pT->m_Width*pT->m_Height; ++i) - { - if(i%pT->m_Width < 2 || i%pT->m_Width > pT->m_Width-3) - pT->m_pTiles[i].m_Index = 1; - } - - for(int i = (pT->m_Width*(pT->m_Height-2)); i < pT->m_Width*pT->m_Height; ++i) - pT->m_pTiles[i].m_Index = 1; -} - -void CEditor::UpdateAndRender() -{ - static float s_MouseX = 0.0f; - static float s_MouseY = 0.0f; - - if(m_Animate) - m_AnimateTime = (time_get()-m_AnimateStart)/(float)time_freq(); - else - m_AnimateTime = 0; - ms_pUiGotContext = 0; - - // handle mouse movement - float mx, my, Mwx, Mwy; - float rx, ry; - { - Input()->MouseRelative(&rx, &ry); - m_MouseDeltaX = rx; - m_MouseDeltaY = ry; - - if(!m_LockMouse) - { - s_MouseX += rx; - s_MouseY += ry; - } - - s_MouseX = clamp(s_MouseX, 0.0f, UI()->Screen()->w); - s_MouseY = clamp(s_MouseY, 0.0f, UI()->Screen()->h); - - // update the ui - mx = s_MouseX; - my = s_MouseY; - Mwx = 0; - Mwy = 0; - - // fix correct world x and y - CLayerGroup *g = GetSelectedGroup(); - if(g) - { - float aPoints[4]; - g->Mapping(aPoints); - - float WorldWidth = aPoints[2]-aPoints[0]; - float WorldHeight = aPoints[3]-aPoints[1]; - - Mwx = aPoints[0] + WorldWidth * (s_MouseX/UI()->Screen()->w); - Mwy = aPoints[1] + WorldHeight * (s_MouseY/UI()->Screen()->h); - m_MouseDeltaWx = m_MouseDeltaX*(WorldWidth / UI()->Screen()->w); - m_MouseDeltaWy = m_MouseDeltaY*(WorldHeight / UI()->Screen()->h); - } - - int Buttons = 0; - if(Input()->KeyPressed(KEY_MOUSE_1)) Buttons |= 1; - if(Input()->KeyPressed(KEY_MOUSE_2)) Buttons |= 2; - if(Input()->KeyPressed(KEY_MOUSE_3)) Buttons |= 4; - - UI()->Update(mx,my,Mwx,Mwy,Buttons); - } - - // toggle gui - if(Input()->KeyDown(KEY_TAB)) - m_GuiActive = !m_GuiActive; - - if(Input()->KeyDown(KEY_F5)) - Save("maps/debug_test2.map"); - - if(Input()->KeyDown(KEY_F6)) - Load("maps/debug_test2.map", IStorage::TYPE_ALL); - - if(Input()->KeyDown(KEY_F8)) - Load("maps/debug_test.map", IStorage::TYPE_ALL); - - if(Input()->KeyDown(KEY_F7)) - Save("maps/quicksave.map"); - - if(Input()->KeyDown(KEY_F10)) - m_ShowMousePointer = false; - - Render(); - - if(Input()->KeyDown(KEY_F10)) - { - Graphics()->TakeScreenshot(0); - m_ShowMousePointer = true; - } - - Input()->ClearEvents(); -} - -IEditor *CreateEditor() { return new CEditor; } diff --git a/src/game/editor/ed_editor.h b/src/game/editor/ed_editor.h deleted file mode 100644 index 41162b22..00000000 --- a/src/game/editor/ed_editor.h +++ /dev/null @@ -1,741 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#ifndef GAME_EDITOR_ED_EDITOR_H -#define GAME_EDITOR_ED_EDITOR_H - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -typedef void (*INDEX_MODIFY_FUNC)(int *pIndex); - -//CRenderTools m_RenderTools; - -// CEditor SPECIFIC -enum -{ - MODE_LAYERS=0, - MODE_IMAGES, - - DIALOG_NONE=0, - DIALOG_FILE, -}; - -struct CEntity -{ - CPoint m_Position; - int m_Type; -}; - -class CEnvelope -{ -public: - int m_Channels; - array m_lPoints; - char m_aName[32]; - float m_Bottom, m_Top; - - CEnvelope(int Chan) - { - m_Channels = Chan; - m_aName[0] = 0; - m_Bottom = 0; - m_Top = 0; - } - - void Resort() - { - sort(m_lPoints.all()); - FindTopBottom(0xf); - } - - void FindTopBottom(int ChannelMask) - { - m_Top = -1000000000.0f; - m_Bottom = 1000000000.0f; - for(int i = 0; i < m_lPoints.size(); i++) - { - for(int c = 0; c < m_Channels; c++) - { - if(ChannelMask&(1< m_Top) m_Top = v; - if(v < m_Bottom) m_Bottom = v; - } - } - } - } - - int Eval(float Time, float *pResult) - { - CRenderTools::RenderEvalEnvelope(m_lPoints.base_ptr(), m_lPoints.size(), m_Channels, Time, pResult); - return m_Channels; - } - - void AddPoint(int Time, int v0, int v1=0, int v2=0, int v3=0) - { - CEnvPoint p; - p.m_Time = Time; - p.m_aValues[0] = v0; - p.m_aValues[1] = v1; - p.m_aValues[2] = v2; - p.m_aValues[3] = v3; - p.m_Curvetype = CURVETYPE_LINEAR; - m_lPoints.add(p); - Resort(); - } - - float EndTime() - { - if(m_lPoints.size()) - return m_lPoints[m_lPoints.size()-1].m_Time*(1.0f/1000.0f); - return 0; - } -}; - - -class CLayer; -class CLayerGroup; -class CEditorMap; - -class CLayer -{ -public: - class CEditor *m_pEditor; - class IGraphics *Graphics(); - class ITextRender *TextRender(); - - CLayer() - { - m_Type = LAYERTYPE_INVALID; - m_pTypeName = "(invalid)"; - m_Visible = true; - m_Readonly = false; - m_SaveToMap = true; - m_Flags = 0; - m_pEditor = 0; - } - - virtual ~CLayer() - { - } - - - virtual void BrushSelecting(CUIRect Rect) {} - virtual int BrushGrab(CLayerGroup *pBrush, CUIRect Rect) { return 0; } - virtual void FillSelection(bool Empty, CLayer *pBrush, CUIRect Rect) {} - virtual void BrushDraw(CLayer *pBrush, float x, float y) {} - virtual void BrushPlace(CLayer *pBrush, float x, float y) {} - virtual void BrushFlipX() {} - virtual void BrushFlipY() {} - virtual void BrushRotate(float Amount) {} - - virtual void Render() {} - virtual int RenderProperties(CUIRect *pToolbox) { return 0; } - - virtual void ModifyImageIndex(INDEX_MODIFY_FUNC pfnFunc) {} - virtual void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc) {} - - virtual void GetSize(float *w, float *h) { *w = 0; *h = 0;} - - const char *m_pTypeName; - int m_Type; - int m_Flags; - - bool m_Readonly; - bool m_Visible; - bool m_SaveToMap; -}; - -class CLayerGroup -{ -public: - class CEditorMap *m_pMap; - - array m_lLayers; - - int m_OffsetX; - int m_OffsetY; - - int m_ParallaxX; - int m_ParallaxY; - - int m_UseClipping; - int m_ClipX; - int m_ClipY; - int m_ClipW; - int m_ClipH; - - const char *m_pName; - bool m_GameGroup; - bool m_Visible; - bool m_SaveToMap; - - CLayerGroup(); - ~CLayerGroup(); - - void Convert(CUIRect *pRect); - void Render(); - void MapScreen(); - void Mapping(float *pPoints); - - void GetSize(float *w, float *h); - - void DeleteLayer(int Index); - int SwapLayers(int Index0, int Index1); - - bool IsEmpty() const - { - return m_lLayers.size() == 0; - } - - void Clear() - { - m_lLayers.delete_all(); - } - - void AddLayer(CLayer *l); - - void ModifyImageIndex(INDEX_MODIFY_FUNC Func) - { - for(int i = 0; i < m_lLayers.size(); i++) - m_lLayers[i]->ModifyImageIndex(Func); - } - - void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC Func) - { - for(int i = 0; i < m_lLayers.size(); i++) - m_lLayers[i]->ModifyEnvelopeIndex(Func); - } -}; - -class CEditorImage : public CImageInfo -{ -public: - CEditor *m_pEditor; - - CEditorImage(CEditor *pEditor) - { - m_pEditor = pEditor; - m_TexID = -1; - m_aName[0] = 0; - m_External = 0; - m_Width = 0; - m_Height = 0; - m_pData = 0; - m_Format = 0; - } - - ~CEditorImage(); - - void AnalyseTileFlags(); - - int m_TexID; - int m_External; - char m_aName[128]; - unsigned char m_aTileFlags[256]; -}; - -class CEditorMap -{ - void MakeGameGroup(CLayerGroup *pGroup); - void MakeGameLayer(CLayer *pLayer); -public: - CEditor *m_pEditor; - bool m_Modified; - - CEditorMap() - { - Clean(); - } - - array m_lGroups; - array m_lImages; - array m_lEnvelopes; - - class CLayerGame *m_pGameLayer; - CLayerGroup *m_pGameGroup; - - CEnvelope *NewEnvelope(int Channels) - { - m_Modified = true; - CEnvelope *e = new CEnvelope(Channels); - m_lEnvelopes.add(e); - return e; - } - - void DeleteEnvelope(int Index); - - CLayerGroup *NewGroup() - { - m_Modified = true; - CLayerGroup *g = new CLayerGroup; - g->m_pMap = this; - m_lGroups.add(g); - return g; - } - - int SwapGroups(int Index0, int Index1) - { - if(Index0 < 0 || Index0 >= m_lGroups.size()) return Index0; - if(Index1 < 0 || Index1 >= m_lGroups.size()) return Index0; - if(Index0 == Index1) return Index0; - m_Modified = true; - swap(m_lGroups[Index0], m_lGroups[Index1]); - return Index1; - } - - void DeleteGroup(int Index) - { - if(Index < 0 || Index >= m_lGroups.size()) return; - m_Modified = true; - delete m_lGroups[Index]; - m_lGroups.remove_index(Index); - } - - void ModifyImageIndex(INDEX_MODIFY_FUNC pfnFunc) - { - m_Modified = true; - for(int i = 0; i < m_lGroups.size(); i++) - m_lGroups[i]->ModifyImageIndex(pfnFunc); - } - - void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc) - { - m_Modified = true; - for(int i = 0; i < m_lGroups.size(); i++) - m_lGroups[i]->ModifyEnvelopeIndex(pfnFunc); - } - - void Clean(); - void CreateDefault(int EntitiesTexture); - - // io - int Save(class IStorage *pStorage, const char *pFilename); - int Load(class IStorage *pStorage, const char *pFilename, int StorageType); -}; - - -struct CProperty -{ - const char *m_pName; - int m_Value; - int m_Type; - int m_Min; - int m_Max; -}; - -enum -{ - PROPTYPE_NULL=0, - PROPTYPE_BOOL, - PROPTYPE_INT_STEP, - PROPTYPE_INT_SCROLL, - PROPTYPE_COLOR, - PROPTYPE_IMAGE, - PROPTYPE_ENVELOPE, - PROPTYPE_SHIFT, -}; - -typedef struct -{ - int x, y; - int w, h; -} RECTi; - -class CLayerTiles : public CLayer -{ -public: - CLayerTiles(int w, int h); - ~CLayerTiles(); - - void Resize(int NewW, int NewH); - void Shift(int Direction); - - void MakePalette(); - virtual void Render(); - - int ConvertX(float x) const; - int ConvertY(float y) const; - void Convert(CUIRect Rect, RECTi *pOut); - void Snap(CUIRect *pRect); - void Clamp(RECTi *pRect); - - virtual void BrushSelecting(CUIRect Rect); - virtual int BrushGrab(CLayerGroup *pBrush, CUIRect Rect); - virtual void FillSelection(bool Empty, CLayer *pBrush, CUIRect Rect); - virtual void BrushDraw(CLayer *pBrush, float wx, float wy); - virtual void BrushFlipX(); - virtual void BrushFlipY(); - virtual void BrushRotate(float Amount); - - virtual void ShowInfo(); - virtual int RenderProperties(CUIRect *pToolbox); - - virtual void ModifyImageIndex(INDEX_MODIFY_FUNC pfnFunc); - virtual void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc); - - void PrepareForSave(); - - void GetSize(float *w, float *h) { *w = m_Width*32.0f; *h = m_Height*32.0f; } - - int m_TexID; - int m_Game; - int m_Image; - int m_Width; - int m_Height; - CColor m_Color; - CTile *m_pTiles; -}; - -class CLayerQuads : public CLayer -{ -public: - CLayerQuads(); - ~CLayerQuads(); - - virtual void Render(); - CQuad *NewQuad(); - - virtual void BrushSelecting(CUIRect Rect); - virtual int BrushGrab(CLayerGroup *pBrush, CUIRect Rect); - virtual void BrushPlace(CLayer *pBrush, float wx, float wy); - virtual void BrushFlipX(); - virtual void BrushFlipY(); - virtual void BrushRotate(float Amount); - - virtual int RenderProperties(CUIRect *pToolbox); - - virtual void ModifyImageIndex(INDEX_MODIFY_FUNC pfnFunc); - virtual void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc); - - void GetSize(float *w, float *h); - - int m_Image; - array m_lQuads; -}; - -class CLayerGame : public CLayerTiles -{ -public: - CLayerGame(int w, int h); - ~CLayerGame(); - - virtual int RenderProperties(CUIRect *pToolbox); -}; - -class CEditor : public IEditor -{ - class IInput *m_pInput; - class IClient *m_pClient; - class IConsole *m_pConsole; - class IGraphics *m_pGraphics; - class ITextRender *m_pTextRender; - class IStorage *m_pStorage; - CRenderTools m_RenderTools; - CUI m_UI; -public: - class IInput *Input() { return m_pInput; }; - class IClient *Client() { return m_pClient; }; - class IConsole *Console() { return m_pConsole; }; - class IGraphics *Graphics() { return m_pGraphics; }; - class ITextRender *TextRender() { return m_pTextRender; }; - class IStorage *Storage() { return m_pStorage; }; - CUI *UI() { return &m_UI; } - CRenderTools *RenderTools() { return &m_RenderTools; } - - CEditor() : m_TilesetPicker(16, 16) - { - m_pInput = 0; - m_pClient = 0; - m_pGraphics = 0; - m_pTextRender = 0; - - m_Mode = MODE_LAYERS; - m_Dialog = 0; - m_pTooltip = 0; - - m_aFileName[0] = 0; - m_aFileSaveName[0] = 0; - m_ValidSaveFilename = false; - - m_PopupEventActivated = false; - - m_FileDialogStorageType = 0; - m_pFileDialogTitle = 0; - m_pFileDialogButtonText = 0; - m_pFileDialogUser = 0; - m_aFileDialogFileName[0] = 0; - m_aFileDialogCurrentFolder[0] = 0; - m_aFileDialogCurrentLink[0] = 0; - m_pFileDialogPath = m_aFileDialogCurrentFolder; - m_aFileDialogActivate = false; - m_FileDialogScrollValue = 0.0f; - m_FilesSelectedIndex = -1; - m_FilesStartAt = 0; - m_FilesCur = 0; - m_FilesStopAt = 999; - - m_WorldOffsetX = 0; - m_WorldOffsetY = 0; - m_EditorOffsetX = 0.0f; - m_EditorOffsetY = 0.0f; - - m_WorldZoom = 1.0f; - m_ZoomLevel = 200; - m_LockMouse = false; - m_ShowMousePointer = true; - m_MouseDeltaX = 0; - m_MouseDeltaY = 0; - m_MouseDeltaWx = 0; - m_MouseDeltaWy = 0; - - m_GuiActive = true; - m_ProofBorders = false; - - m_ShowTileInfo = false; - m_ShowDetail = true; - m_Animate = false; - m_AnimateStart = 0; - m_AnimateTime = 0; - m_AnimateSpeed = 1; - - m_ShowEnvelopeEditor = 0; - - ms_CheckerTexture = 0; - ms_BackgroundTexture = 0; - ms_CursorTexture = 0; - ms_EntitiesTexture = 0; - - ms_pUiGotContext = 0; - } - - virtual void Init(); - virtual void UpdateAndRender(); - virtual bool HasUnsavedData() { return m_Map.m_Modified; } - - void FilelistPopulate(int StorageType); - void InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText, - const char *pBasepath, const char *pDefaultName, - void (*pfnFunc)(const char *pFilename, int StorageType, void *pUser), void *pUser); - - void Reset(bool CreateDefault=true); - int Save(const char *pFilename); - int Load(const char *pFilename, int StorageType); - int Append(const char *pFilename, int StorageType); - void Render(); - - CQuad *GetSelectedQuad(); - CLayer *GetSelectedLayerType(int Index, int Type); - CLayer *GetSelectedLayer(int Index); - CLayerGroup *GetSelectedGroup(); - - int DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal); - - int m_Mode; - int m_Dialog; - const char *m_pTooltip; - - char m_aFileName[512]; - char m_aFileSaveName[512]; - bool m_ValidSaveFilename; - - enum - { - POPEVENT_EXIT=0, - POPEVENT_LOAD, - POPEVENT_NEW, - POPEVENT_SAVE, - }; - - int m_PopupEventType; - int m_PopupEventActivated; - - enum - { - FILETYPE_MAP, - FILETYPE_IMG, - - MAX_PATH_LENGTH = 512 - }; - - int m_FileDialogStorageType; - const char *m_pFileDialogTitle; - const char *m_pFileDialogButtonText; - void (*m_pfnFileDialogFunc)(const char *pFileName, int StorageType, void *pUser); - void *m_pFileDialogUser; - char m_aFileDialogFileName[MAX_PATH_LENGTH]; - char m_aFileDialogCurrentFolder[MAX_PATH_LENGTH]; - char m_aFileDialogCurrentLink[MAX_PATH_LENGTH]; - char *m_pFileDialogPath; - bool m_aFileDialogActivate; - int m_FileDialogFileType; - float m_FileDialogScrollValue; - int m_FilesSelectedIndex; - char m_FileDialogNewFolderName[64]; - char m_FileDialogErrString[64]; - - struct CFilelistItem - { - char m_aFilename[128]; - char m_aName[128]; - bool m_IsDir; - bool m_IsLink; - int m_StorageType; - - bool operator<(const CFilelistItem &Other) { return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false : - m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false : - str_comp_filenames(m_aFilename, Other.m_aFilename) < 0; } - }; - sorted_array m_FileList; - int m_FilesStartAt; - int m_FilesCur; - int m_FilesStopAt; - - float m_WorldOffsetX; - float m_WorldOffsetY; - float m_EditorOffsetX; - float m_EditorOffsetY; - float m_WorldZoom; - int m_ZoomLevel; - bool m_LockMouse; - bool m_ShowMousePointer; - bool m_GuiActive; - bool m_ProofBorders; - float m_MouseDeltaX; - float m_MouseDeltaY; - float m_MouseDeltaWx; - float m_MouseDeltaWy; - - bool m_ShowTileInfo; - bool m_ShowDetail; - bool m_Animate; - int64 m_AnimateStart; - float m_AnimateTime; - float m_AnimateSpeed; - - int m_ShowEnvelopeEditor; - - int m_SelectedLayer; - int m_SelectedGroup; - int m_SelectedQuad; - int m_SelectedPoints; - int m_SelectedEnvelope; - int m_SelectedImage; - - static int ms_CheckerTexture; - static int ms_BackgroundTexture; - static int ms_CursorTexture; - static int ms_EntitiesTexture; - - CLayerGroup m_Brush; - CLayerTiles m_TilesetPicker; - - static const void *ms_pUiGotContext; - - CEditorMap m_Map; - - void DoMapBorder(); - int DoButton_Editor_Common(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); - int DoButton_Editor(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); - - int DoButton_Tab(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); - int DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners); - int DoButton_ButtonDec(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); - int DoButton_ButtonInc(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); - - int DoButton_File(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); - - int DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); - int DoButton_MenuItem(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags=0, const char *pToolTip=0); - - int DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden=false); - - void RenderBackground(CUIRect View, int Texture, float Size, float Brightness); - - void UiInvokePopupMenu(void *pID, int Flags, float X, float Y, float W, float H, int (*pfnFunc)(CEditor *pEditor, CUIRect Rect), void *pExtra=0); - void UiDoPopupMenu(); - - int UiDoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, int Current, int Min, int Max, int Step, float Scale, const char *pToolTip); - - static int PopupGroup(CEditor *pEditor, CUIRect View); - static int PopupLayer(CEditor *pEditor, CUIRect View); - static int PopupQuad(CEditor *pEditor, CUIRect View); - static int PopupPoint(CEditor *pEditor, CUIRect View); - static int PopupNewFolder(CEditor *pEditor, CUIRect View); - static int PopupEvent(CEditor *pEditor, CUIRect View); - static int PopupSelectImage(CEditor *pEditor, CUIRect View); - static int PopupSelectGametileOp(CEditor *pEditor, CUIRect View); - static int PopupImage(CEditor *pEditor, CUIRect View); - static int PopupMenuFile(CEditor *pEditor, CUIRect View); - - static void CallbackOpenMap(const char *pFileName, int StorageType, void *pUser); - static void CallbackAppendMap(const char *pFileName, int StorageType, void *pUser); - static void CallbackSaveMap(const char *pFileName, int StorageType, void *pUser); - - void PopupSelectImageInvoke(int Current, float x, float y); - int PopupSelectImageResult(); - - void PopupSelectGametileOpInvoke(float x, float y); - int PopupSelectGameTileOpResult(); - - vec4 ButtonColorMul(const void *pID); - - void DoQuadPoint(CQuad *pQuad, int QuadIndex, int v); - void DoMapEditor(CUIRect View, CUIRect Toolbar, bool ShowPicker); - void DoToolbar(CUIRect Toolbar); - void DoQuad(CQuad *pQuad, int Index); - float UiDoScrollbarV(const void *pID, const CUIRect *pRect, float Current); - vec4 GetButtonColor(const void *pID, int Checked); - - static void ReplaceImage(const char *pFilename, int StorageType, void *pUser); - static void AddImage(const char *pFilename, int StorageType, void *pUser); - - void RenderImages(CUIRect Toolbox, CUIRect Toolbar, CUIRect View); - void RenderLayers(CUIRect Toolbox, CUIRect Toolbar, CUIRect View); - void RenderModebar(CUIRect View); - void RenderStatusbar(CUIRect View); - void RenderEnvelopeEditor(CUIRect View); - - void RenderMenubar(CUIRect Menubar); - void RenderFileDialog(); - - void AddFileDialogEntry(int Index, CUIRect *pView); - void SortImages(); - static void ExtractName(const char *pFileName, char *pName, int BufferSize) - { - const char *pExtractedName = pFileName; - const char *pEnd = 0; - for(; *pFileName; ++pFileName) - { - if(*pFileName == '/' || *pFileName == '\\') - pExtractedName = pFileName+1; - else if(*pFileName == '.') - pEnd = pFileName; - } - - int Length = pEnd > pExtractedName ? min(BufferSize, (int)(pEnd-pExtractedName+1)) : BufferSize; - str_copy(pName, pExtractedName, Length); - } -}; - -// make sure to inline this function -inline class IGraphics *CLayer::Graphics() { return m_pEditor->Graphics(); } -inline class ITextRender *CLayer::TextRender() { return m_pEditor->TextRender(); } - -#endif diff --git a/src/game/editor/ed_io.cpp b/src/game/editor/ed_io.cpp deleted file mode 100644 index a5ead97a..00000000 --- a/src/game/editor/ed_io.cpp +++ /dev/null @@ -1,638 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include -#include -#include -#include -#include -#include -#include "ed_editor.h" - -template -static int MakeVersion(int i, const T &v) -{ return (i<<16)+sizeof(T); } - -// backwards compatiblity -/* -void editor_load_old(DATAFILE *df, MAP *map) -{ - class mapres_image - { - public: - int width; - int height; - int image_data; - }; - - struct mapres_tilemap - { - int image; - int width; - int height; - int x, y; - int scale; - int data; - int main; - }; - - struct mapres_entity - { - int x, y; - int data[1]; - }; - - struct mapres_spawnpoint - { - int x, y; - }; - - struct mapres_item - { - int x, y; - int type; - }; - - struct mapres_flagstand - { - int x, y; - }; - - enum - { - MAPRES_ENTS_START=1, - MAPRES_SPAWNPOINT=1, - MAPRES_ITEM=2, - MAPRES_SPAWNPOINT_RED=3, - MAPRES_SPAWNPOINT_BLUE=4, - MAPRES_FLAGSTAND_RED=5, - MAPRES_FLAGSTAND_BLUE=6, - MAPRES_ENTS_END, - - ITEM_NULL=0, - ITEM_WEAPON_GUN=0x00010001, - ITEM_WEAPON_SHOTGUN=0x00010002, - ITEM_WEAPON_ROCKET=0x00010003, - ITEM_WEAPON_SNIPER=0x00010004, - ITEM_WEAPON_HAMMER=0x00010005, - ITEM_HEALTH =0x00020001, - ITEM_ARMOR=0x00030001, - ITEM_NINJA=0x00040001, - }; - - enum - { - MAPRES_REGISTERED=0x8000, - MAPRES_IMAGE=0x8001, - MAPRES_TILEMAP=0x8002, - MAPRES_COLLISIONMAP=0x8003, - MAPRES_TEMP_THEME=0x8fff, - }; - - // load tilemaps - int game_width = 0; - int game_height = 0; - { - int start, num; - datafile_get_type(df, MAPRES_TILEMAP, &start, &num); - for(int t = 0; t < num; t++) - { - mapres_tilemap *tmap = (mapres_tilemap *)datafile_get_item(df, start+t,0,0); - - CLayerTiles *l = new CLayerTiles(tmap->width, tmap->height); - - if(tmap->main) - { - // move game layer to correct position - for(int i = 0; i < map->groups[0]->layers.len()-1; i++) - { - if(map->groups[0]->layers[i] == pEditor->map.game_layer) - map->groups[0]->swap_layers(i, i+1); - } - - game_width = tmap->width; - game_height = tmap->height; - } - - // add new layer - map->groups[0]->add_layer(l); - - // process the data - unsigned char *src_data = (unsigned char *)datafile_get_data(df, tmap->data); - CTile *dst_data = l->tiles; - - for(int y = 0; y < tmap->height; y++) - for(int x = 0; x < tmap->width; x++, dst_data++, src_data+=2) - { - dst_data->index = src_data[0]; - dst_data->flags = src_data[1]; - } - - l->image = tmap->image; - } - } - - // load images - { - int start, count; - datafile_get_type(df, MAPRES_IMAGE, &start, &count); - for(int i = 0; i < count; i++) - { - mapres_image *imgres = (mapres_image *)datafile_get_item(df, start+i, 0, 0); - void *data = datafile_get_data(df, imgres->image_data); - - EDITOR_IMAGE *img = new EDITOR_IMAGE; - img->width = imgres->width; - img->height = imgres->height; - img->format = CImageInfo::FORMAT_RGBA; - - // copy image data - img->data = mem_alloc(img->width*img->height*4, 1); - mem_copy(img->data, data, img->width*img->height*4); - img->tex_id = Graphics()->LoadTextureRaw(img->width, img->height, img->format, img->data, CImageInfo::FORMAT_AUTO, 0); - map->images.add(img); - - // unload image - datafile_unload_data(df, imgres->image_data); - } - } - - // load entities - { - CLayerGame *g = map->game_layer; - g->resize(game_width, game_height); - for(int t = MAPRES_ENTS_START; t < MAPRES_ENTS_END; t++) - { - // fetch entities of this class - int start, num; - datafile_get_type(df, t, &start, &num); - - - for(int i = 0; i < num; i++) - { - mapres_entity *e = (mapres_entity *)datafile_get_item(df, start+i,0,0); - int x = e->x/32; - int y = e->y/32; - int id = -1; - - if(t == MAPRES_SPAWNPOINT) id = ENTITY_SPAWN; - else if(t == MAPRES_SPAWNPOINT_RED) id = ENTITY_SPAWN_RED; - else if(t == MAPRES_SPAWNPOINT_BLUE) id = ENTITY_SPAWN_BLUE; - else if(t == MAPRES_FLAGSTAND_RED) id = ENTITY_FLAGSTAND_RED; - else if(t == MAPRES_FLAGSTAND_BLUE) id = ENTITY_FLAGSTAND_BLUE; - else if(t == MAPRES_ITEM) - { - if(e->data[0] == ITEM_WEAPON_SHOTGUN) id = ENTITY_WEAPON_SHOTGUN; - else if(e->data[0] == ITEM_WEAPON_ROCKET) id = ENTITY_WEAPON_GRENADE; - else if(e->data[0] == ITEM_NINJA) id = ENTITY_POWERUP_NINJA; - else if(e->data[0] == ITEM_ARMOR) id = ENTITY_ARMOR_1; - else if(e->data[0] == ITEM_HEALTH) id = ENTITY_HEALTH_1; - } - - if(id > 0 && x >= 0 && x < g->width && y >= 0 && y < g->height) - g->tiles[y*g->width+x].index = id+ENTITY_OFFSET; - } - } - } -}*/ - -int CEditor::Save(const char *pFilename) -{ - return m_Map.Save(Kernel()->RequestInterface(), pFilename); -} - -int CEditorMap::Save(class IStorage *pStorage, const char *pFileName) -{ - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "saving to '%s'...", pFileName); - m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "editor", aBuf); - CDataFileWriter df; - if(!df.Open(pStorage, pFileName)) - { - str_format(aBuf, sizeof(aBuf), "failed to open file '%s'...", pFileName); - m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "editor", aBuf); - return 0; - } - - // save version - { - CMapItemVersion Item; - Item.m_Version = 1; - df.AddItem(MAPITEMTYPE_VERSION, 0, sizeof(Item), &Item); - } - - // save images - for(int i = 0; i < m_lImages.size(); i++) - { - CEditorImage *pImg = m_lImages[i]; - - // analyse the image for when saving (should be done when we load the image) - // TODO! - pImg->AnalyseTileFlags(); - - CMapItemImage Item; - Item.m_Version = 1; - - Item.m_Width = pImg->m_Width; - Item.m_Height = pImg->m_Height; - Item.m_External = pImg->m_External; - Item.m_ImageName = df.AddData(str_length(pImg->m_aName)+1, pImg->m_aName); - if(pImg->m_External) - Item.m_ImageData = -1; - else - Item.m_ImageData = df.AddData(Item.m_Width*Item.m_Height*4, pImg->m_pData); - df.AddItem(MAPITEMTYPE_IMAGE, i, sizeof(Item), &Item); - } - - // save layers - int LayerCount = 0, GroupCount = 0; - for(int g = 0; g < m_lGroups.size(); g++) - { - CLayerGroup *pGroup = m_lGroups[g]; - if(!pGroup->m_SaveToMap) - continue; - - CMapItemGroup GItem; - GItem.m_Version = CMapItemGroup::CURRENT_VERSION; - - GItem.m_ParallaxX = pGroup->m_ParallaxX; - GItem.m_ParallaxY = pGroup->m_ParallaxY; - GItem.m_OffsetX = pGroup->m_OffsetX; - GItem.m_OffsetY = pGroup->m_OffsetY; - GItem.m_UseClipping = pGroup->m_UseClipping; - GItem.m_ClipX = pGroup->m_ClipX; - GItem.m_ClipY = pGroup->m_ClipY; - GItem.m_ClipW = pGroup->m_ClipW; - GItem.m_ClipH = pGroup->m_ClipH; - GItem.m_StartLayer = LayerCount; - GItem.m_NumLayers = 0; - - for(int l = 0; l < pGroup->m_lLayers.size(); l++) - { - if(!pGroup->m_lLayers[l]->m_SaveToMap) - continue; - - if(pGroup->m_lLayers[l]->m_Type == LAYERTYPE_TILES) - { - m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "editor", "saving tiles layer"); - CLayerTiles *pLayer = (CLayerTiles *)pGroup->m_lLayers[l]; - pLayer->PrepareForSave(); - - CMapItemLayerTilemap Item; - Item.m_Version = 2; - - Item.m_Layer.m_Flags = pLayer->m_Flags; - Item.m_Layer.m_Type = pLayer->m_Type; - - Item.m_Color.r = pLayer->m_Color.r; - Item.m_Color.g = pLayer->m_Color.g; - Item.m_Color.b = pLayer->m_Color.b; - Item.m_Color.a = pLayer->m_Color.a; - Item.m_ColorEnv = -1; // not in use right now - Item.m_ColorEnvOffset = 0; - - Item.m_Width = pLayer->m_Width; - Item.m_Height = pLayer->m_Height; - Item.m_Flags = pLayer->m_Game; - Item.m_Image = pLayer->m_Image; - Item.m_Data = df.AddData(pLayer->m_Width*pLayer->m_Height*sizeof(CTile), pLayer->m_pTiles); - df.AddItem(MAPITEMTYPE_LAYER, LayerCount, sizeof(Item), &Item); - - GItem.m_NumLayers++; - LayerCount++; - } - else if(pGroup->m_lLayers[l]->m_Type == LAYERTYPE_QUADS) - { - m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "editor", "saving quads layer"); - CLayerQuads *pLayer = (CLayerQuads *)pGroup->m_lLayers[l]; - if(pLayer->m_lQuads.size()) - { - CMapItemLayerQuads Item; - Item.m_Version = 1; - Item.m_Layer.m_Flags = pLayer->m_Flags; - Item.m_Layer.m_Type = pLayer->m_Type; - Item.m_Image = pLayer->m_Image; - - // add the data - Item.m_NumQuads = pLayer->m_lQuads.size(); - Item.m_Data = df.AddDataSwapped(pLayer->m_lQuads.size()*sizeof(CQuad), pLayer->m_lQuads.base_ptr()); - df.AddItem(MAPITEMTYPE_LAYER, LayerCount, sizeof(Item), &Item); - - // clean up - //mem_free(quads); - - GItem.m_NumLayers++; - LayerCount++; - } - } - } - - df.AddItem(MAPITEMTYPE_GROUP, GroupCount++, sizeof(GItem), &GItem); - } - - // save envelopes - int PointCount = 0; - for(int e = 0; e < m_lEnvelopes.size(); e++) - { - CMapItemEnvelope Item; - Item.m_Version = 1; - Item.m_Channels = m_lEnvelopes[e]->m_Channels; - Item.m_StartPoint = PointCount; - Item.m_NumPoints = m_lEnvelopes[e]->m_lPoints.size(); - StrToInts(Item.m_aName, sizeof(Item.m_aName)/sizeof(int), m_lEnvelopes[e]->m_aName); - - df.AddItem(MAPITEMTYPE_ENVELOPE, e, sizeof(Item), &Item); - PointCount += Item.m_NumPoints; - } - - // save points - int TotalSize = sizeof(CEnvPoint) * PointCount; - CEnvPoint *pPoints = (CEnvPoint *)mem_alloc(TotalSize, 1); - PointCount = 0; - - for(int e = 0; e < m_lEnvelopes.size(); e++) - { - int Count = m_lEnvelopes[e]->m_lPoints.size(); - mem_copy(&pPoints[PointCount], m_lEnvelopes[e]->m_lPoints.base_ptr(), sizeof(CEnvPoint)*Count); - PointCount += Count; - } - - df.AddItem(MAPITEMTYPE_ENVPOINTS, 0, TotalSize, pPoints); - - // finish the data file - df.Finish(); - m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "editor", "saving done"); - - // send rcon.. if we can - if(m_pEditor->Client()->RconAuthed()) - { - CServerInfo CurrentServerInfo; - m_pEditor->Client()->GetServerInfo(&CurrentServerInfo); - char aMapName[128]; - m_pEditor->ExtractName(pFileName, aMapName, sizeof(aMapName)); - if(!str_comp(aMapName, CurrentServerInfo.m_aMap)) - m_pEditor->Client()->Rcon("reload"); - } - - return 1; -} - -int CEditor::Load(const char *pFileName, int StorageType) -{ - Reset(); - return m_Map.Load(Kernel()->RequestInterface(), pFileName, StorageType); -} - -int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int StorageType) -{ - CDataFileReader DataFile; - //DATAFILE *df = datafile_load(filename); - if(!DataFile.Open(pStorage, pFileName, StorageType)) - return 0; - - Clean(); - - // check version - CMapItemVersion *pItem = (CMapItemVersion *)DataFile.FindItem(MAPITEMTYPE_VERSION, 0); - if(!pItem) - { - // import old map - /*MAP old_mapstuff; - editor->reset(); - editor_load_old(df, this); - */ - } - else if(pItem->m_Version == 1) - { - //editor.reset(false); - - // load images - { - int Start, Num; - DataFile.GetType( MAPITEMTYPE_IMAGE, &Start, &Num); - for(int i = 0; i < Num; i++) - { - CMapItemImage *pItem = (CMapItemImage *)DataFile.GetItem(Start+i, 0, 0); - char *pName = (char *)DataFile.GetData(pItem->m_ImageName); - - // copy base info - CEditorImage *pImg = new CEditorImage(m_pEditor); - pImg->m_External = pItem->m_External; - - if(pItem->m_External) - { - char aBuf[256]; - str_format(aBuf, sizeof(aBuf),"mapres/%s.png", pName); - - // load external - CEditorImage ImgInfo(m_pEditor); - if(m_pEditor->Graphics()->LoadPNG(&ImgInfo, aBuf, IStorage::TYPE_ALL)) - { - *pImg = ImgInfo; - pImg->m_TexID = m_pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0); - pImg->m_External = 1; - } - } - else - { - pImg->m_Width = pItem->m_Width; - pImg->m_Height = pItem->m_Height; - pImg->m_Format = CImageInfo::FORMAT_RGBA; - - // copy image data - void *pData = DataFile.GetData(pItem->m_ImageData); - pImg->m_pData = mem_alloc(pImg->m_Width*pImg->m_Height*4, 1); - mem_copy(pImg->m_pData, pData, pImg->m_Width*pImg->m_Height*4); - pImg->m_TexID = m_pEditor->Graphics()->LoadTextureRaw(pImg->m_Width, pImg->m_Height, pImg->m_Format, pImg->m_pData, CImageInfo::FORMAT_AUTO, 0); - } - - // copy image name - if(pName) - str_copy(pImg->m_aName, pName, 128); - - m_lImages.add(pImg); - - // unload image - DataFile.UnloadData(pItem->m_ImageData); - DataFile.UnloadData(pItem->m_ImageName); - } - } - - // load groups - { - int LayersStart, LayersNum; - DataFile.GetType(MAPITEMTYPE_LAYER, &LayersStart, &LayersNum); - - int Start, Num; - DataFile.GetType(MAPITEMTYPE_GROUP, &Start, &Num); - for(int g = 0; g < Num; g++) - { - CMapItemGroup *pGItem = (CMapItemGroup *)DataFile.GetItem(Start+g, 0, 0); - - if(pGItem->m_Version < 1 || pGItem->m_Version > CMapItemGroup::CURRENT_VERSION) - continue; - - CLayerGroup *pGroup = NewGroup(); - pGroup->m_ParallaxX = pGItem->m_ParallaxX; - pGroup->m_ParallaxY = pGItem->m_ParallaxY; - pGroup->m_OffsetX = pGItem->m_OffsetX; - pGroup->m_OffsetY = pGItem->m_OffsetY; - - if(pGItem->m_Version >= 2) - { - pGroup->m_UseClipping = pGItem->m_UseClipping; - pGroup->m_ClipX = pGItem->m_ClipX; - pGroup->m_ClipY = pGItem->m_ClipY; - pGroup->m_ClipW = pGItem->m_ClipW; - pGroup->m_ClipH = pGItem->m_ClipH; - } - - for(int l = 0; l < pGItem->m_NumLayers; l++) - { - CLayer *pLayer = 0; - CMapItemLayer *pLayerItem = (CMapItemLayer *)DataFile.GetItem(LayersStart+pGItem->m_StartLayer+l, 0, 0); - if(!pLayerItem) - continue; - - if(pLayerItem->m_Type == LAYERTYPE_TILES) - { - CMapItemLayerTilemap *pTilemapItem = (CMapItemLayerTilemap *)pLayerItem; - CLayerTiles *pTiles = 0; - - if(pTilemapItem->m_Flags&1) - { - pTiles = new CLayerGame(pTilemapItem->m_Width, pTilemapItem->m_Height); - MakeGameLayer(pTiles); - MakeGameGroup(pGroup); - } - else - { - pTiles = new CLayerTiles(pTilemapItem->m_Width, pTilemapItem->m_Height); - pTiles->m_pEditor = m_pEditor; - pTiles->m_Color.r = pTilemapItem->m_Color.r; - pTiles->m_Color.g = pTilemapItem->m_Color.g; - pTiles->m_Color.b = pTilemapItem->m_Color.b; - pTiles->m_Color.a = pTilemapItem->m_Color.a; - } - - pLayer = pTiles; - - pGroup->AddLayer(pTiles); - void *pData = DataFile.GetData(pTilemapItem->m_Data); - pTiles->m_Image = pTilemapItem->m_Image; - pTiles->m_Game = pTilemapItem->m_Flags&1; - - mem_copy(pTiles->m_pTiles, pData, pTiles->m_Width*pTiles->m_Height*sizeof(CTile)); - - if(pTiles->m_Game && pTilemapItem->m_Version == MakeVersion(1, *pTilemapItem)) - { - for(int i = 0; i < pTiles->m_Width*pTiles->m_Height; i++) - { - if(pTiles->m_pTiles[i].m_Index) - pTiles->m_pTiles[i].m_Index += ENTITY_OFFSET; - } - } - - DataFile.UnloadData(pTilemapItem->m_Data); - } - else if(pLayerItem->m_Type == LAYERTYPE_QUADS) - { - CMapItemLayerQuads *pQuadsItem = (CMapItemLayerQuads *)pLayerItem; - CLayerQuads *pQuads = new CLayerQuads; - pQuads->m_pEditor = m_pEditor; - pLayer = pQuads; - pQuads->m_Image = pQuadsItem->m_Image; - if(pQuads->m_Image < -1 || pQuads->m_Image >= m_lImages.size()) - pQuads->m_Image = -1; - void *pData = DataFile.GetDataSwapped(pQuadsItem->m_Data); - pGroup->AddLayer(pQuads); - pQuads->m_lQuads.set_size(pQuadsItem->m_NumQuads); - mem_copy(pQuads->m_lQuads.base_ptr(), pData, sizeof(CQuad)*pQuadsItem->m_NumQuads); - DataFile.UnloadData(pQuadsItem->m_Data); - } - - if(pLayer) - pLayer->m_Flags = pLayerItem->m_Flags; - } - } - } - - // load envelopes - { - CEnvPoint *pPoints = 0; - - { - int Start, Num; - DataFile.GetType(MAPITEMTYPE_ENVPOINTS, &Start, &Num); - if(Num) - pPoints = (CEnvPoint *)DataFile.GetItem(Start, 0, 0); - } - - int Start, Num; - DataFile.GetType(MAPITEMTYPE_ENVELOPE, &Start, &Num); - for(int e = 0; e < Num; e++) - { - CMapItemEnvelope *pItem = (CMapItemEnvelope *)DataFile.GetItem(Start+e, 0, 0); - CEnvelope *pEnv = new CEnvelope(pItem->m_Channels); - pEnv->m_lPoints.set_size(pItem->m_NumPoints); - mem_copy(pEnv->m_lPoints.base_ptr(), &pPoints[pItem->m_StartPoint], sizeof(CEnvPoint)*pItem->m_NumPoints); - if(pItem->m_aName[0] != -1) // compatibility with old maps - IntsToStr(pItem->m_aName, sizeof(pItem->m_aName)/sizeof(int), pEnv->m_aName); - m_lEnvelopes.add(pEnv); - } - } - } - - return 1; -} - -static int gs_ModifyAddAmount = 0; -static void ModifyAdd(int *pIndex) -{ - if(*pIndex >= 0) - *pIndex += gs_ModifyAddAmount; -} - -int CEditor::Append(const char *pFileName, int StorageType) -{ - CEditorMap NewMap; - NewMap.m_pEditor = this; - - int Err; - Err = NewMap.Load(Kernel()->RequestInterface(), pFileName, StorageType); - if(!Err) - return Err; - - // modify indecies - gs_ModifyAddAmount = m_Map.m_lImages.size(); - NewMap.ModifyImageIndex(ModifyAdd); - - gs_ModifyAddAmount = m_Map.m_lEnvelopes.size(); - NewMap.ModifyEnvelopeIndex(ModifyAdd); - - // transfer images - for(int i = 0; i < NewMap.m_lImages.size(); i++) - m_Map.m_lImages.add(NewMap.m_lImages[i]); - NewMap.m_lImages.clear(); - - // transfer envelopes - for(int i = 0; i < NewMap.m_lEnvelopes.size(); i++) - m_Map.m_lEnvelopes.add(NewMap.m_lEnvelopes[i]); - NewMap.m_lEnvelopes.clear(); - - // transfer groups - - for(int i = 0; i < NewMap.m_lGroups.size(); i++) - { - if(NewMap.m_lGroups[i] == NewMap.m_pGameGroup) - delete NewMap.m_lGroups[i]; - else - { - NewMap.m_lGroups[i]->m_pMap = &m_Map; - m_Map.m_lGroups.add(NewMap.m_lGroups[i]); - } - } - NewMap.m_lGroups.clear(); - - // all done \o/ - return 0; -} diff --git a/src/game/editor/ed_layer_game.cpp b/src/game/editor/ed_layer_game.cpp deleted file mode 100644 index cf48845e..00000000 --- a/src/game/editor/ed_layer_game.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include "ed_editor.h" - - -CLayerGame::CLayerGame(int w, int h) -: CLayerTiles(w, h) -{ - m_pTypeName = "Game"; - m_Game = 1; -} - -CLayerGame::~CLayerGame() -{ -} - -int CLayerGame::RenderProperties(CUIRect *pToolbox) -{ - int r = CLayerTiles::RenderProperties(pToolbox); - m_Image = -1; - return r; -} diff --git a/src/game/editor/ed_layer_quads.cpp b/src/game/editor/ed_layer_quads.cpp deleted file mode 100644 index 680a54cd..00000000 --- a/src/game/editor/ed_layer_quads.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include - -#include -#include - -#include "ed_editor.h" -#include -#include -#include - -CLayerQuads::CLayerQuads() -{ - m_Type = LAYERTYPE_QUADS; - m_pTypeName = "Quads"; - m_Image = -1; -} - -CLayerQuads::~CLayerQuads() -{ -} - -static void EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser) -{ - CEditor *pEditor = (CEditor *)pUser; - if(Env < 0 || Env > pEditor->m_Map.m_lEnvelopes.size()) - { - pChannels[0] = 0; - pChannels[1] = 0; - pChannels[2] = 0; - pChannels[3] = 0; - return; - } - - CEnvelope *e = pEditor->m_Map.m_lEnvelopes[Env]; - float t = pEditor->m_AnimateTime+TimeOffset; - t *= pEditor->m_AnimateSpeed; - e->Eval(t, pChannels); -} - -void CLayerQuads::Render() -{ - Graphics()->TextureSet(-1); - if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size()) - Graphics()->TextureSet(m_pEditor->m_Map.m_lImages[m_Image]->m_TexID); - - m_pEditor->RenderTools()->RenderQuads(m_lQuads.base_ptr(), m_lQuads.size(), LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, m_pEditor); -} - -CQuad *CLayerQuads::NewQuad() -{ - m_pEditor->m_Map.m_Modified = true; - - CQuad *q = &m_lQuads[m_lQuads.add(CQuad())]; - - q->m_PosEnv = -1; - q->m_ColorEnv = -1; - q->m_PosEnvOffset = 0; - q->m_ColorEnvOffset = 0; - int x = 0, y = 0; - q->m_aPoints[0].x = x; - q->m_aPoints[0].y = y; - q->m_aPoints[1].x = x+64; - q->m_aPoints[1].y = y; - q->m_aPoints[2].x = x; - q->m_aPoints[2].y = y+64; - q->m_aPoints[3].x = x+64; - q->m_aPoints[3].y = y+64; - - q->m_aPoints[4].x = x+32; // pivot - q->m_aPoints[4].y = y+32; - - for(int i = 0; i < 5; i++) - { - q->m_aPoints[i].x <<= 10; - q->m_aPoints[i].y <<= 10; - } - - - q->m_aTexcoords[0].x = 0; - q->m_aTexcoords[0].y = 0; - - q->m_aTexcoords[1].x = 1<<10; - q->m_aTexcoords[1].y = 0; - - q->m_aTexcoords[2].x = 0; - q->m_aTexcoords[2].y = 1<<10; - - q->m_aTexcoords[3].x = 1<<10; - q->m_aTexcoords[3].y = 1<<10; - - q->m_aColors[0].r = 255; q->m_aColors[0].g = 255; q->m_aColors[0].b = 255; q->m_aColors[0].a = 255; - q->m_aColors[1].r = 255; q->m_aColors[1].g = 255; q->m_aColors[1].b = 255; q->m_aColors[1].a = 255; - q->m_aColors[2].r = 255; q->m_aColors[2].g = 255; q->m_aColors[2].b = 255; q->m_aColors[2].a = 255; - q->m_aColors[3].r = 255; q->m_aColors[3].g = 255; q->m_aColors[3].b = 255; q->m_aColors[3].a = 255; - - return q; -} - -void CLayerQuads::BrushSelecting(CUIRect Rect) -{ - // draw selection rectangle - IGraphics::CLineItem Array[4] = { - IGraphics::CLineItem(Rect.x, Rect.y, Rect.x+Rect.w, Rect.y), - IGraphics::CLineItem(Rect.x+Rect.w, Rect.y, Rect.x+Rect.w, Rect.y+Rect.h), - IGraphics::CLineItem(Rect.x+Rect.w, Rect.y+Rect.h, Rect.x, Rect.y+Rect.h), - IGraphics::CLineItem(Rect.x, Rect.y+Rect.h, Rect.x, Rect.y)}; - Graphics()->TextureSet(-1); - Graphics()->LinesBegin(); - Graphics()->LinesDraw(Array, 4); - Graphics()->LinesEnd(); -} - -int CLayerQuads::BrushGrab(CLayerGroup *pBrush, CUIRect Rect) -{ - // create new layers - CLayerQuads *pGrabbed = new CLayerQuads(); - pGrabbed->m_pEditor = m_pEditor; - pGrabbed->m_Image = m_Image; - pBrush->AddLayer(pGrabbed); - - //dbg_msg("", "%f %f %f %f", rect.x, rect.y, rect.w, rect.h); - for(int i = 0; i < m_lQuads.size(); i++) - { - CQuad *q = &m_lQuads[i]; - float px = fx2f(q->m_aPoints[4].x); - float py = fx2f(q->m_aPoints[4].y); - - if(px > Rect.x && px < Rect.x+Rect.w && py > Rect.y && py < Rect.y+Rect.h) - { - CQuad n; - n = *q; - - for(int p = 0; p < 5; p++) - { - n.m_aPoints[p].x -= f2fx(Rect.x); - n.m_aPoints[p].y -= f2fx(Rect.y); - } - - pGrabbed->m_lQuads.add(n); - } - } - - return pGrabbed->m_lQuads.size()?1:0; -} - -void CLayerQuads::BrushPlace(CLayer *pBrush, float wx, float wy) -{ - CLayerQuads *l = (CLayerQuads *)pBrush; - for(int i = 0; i < l->m_lQuads.size(); i++) - { - CQuad n = l->m_lQuads[i]; - - for(int p = 0; p < 5; p++) - { - n.m_aPoints[p].x += f2fx(wx); - n.m_aPoints[p].y += f2fx(wy); - } - - m_lQuads.add(n); - } - m_pEditor->m_Map.m_Modified = true; -} - -void CLayerQuads::BrushFlipX() -{ -} - -void CLayerQuads::BrushFlipY() -{ -} - -void Rotate(vec2 *pCenter, vec2 *pPoint, float Rotation) -{ - float x = pPoint->x - pCenter->x; - float y = pPoint->y - pCenter->y; - pPoint->x = x * cosf(Rotation) - y * sinf(Rotation) + pCenter->x; - pPoint->y = x * sinf(Rotation) + y * cosf(Rotation) + pCenter->y; -} - -void CLayerQuads::BrushRotate(float Amount) -{ - vec2 Center; - GetSize(&Center.x, &Center.y); - Center.x /= 2; - Center.y /= 2; - - for(int i = 0; i < m_lQuads.size(); i++) - { - CQuad *q = &m_lQuads[i]; - - for(int p = 0; p < 5; p++) - { - vec2 Pos(fx2f(q->m_aPoints[p].x), fx2f(q->m_aPoints[p].y)); - Rotate(&Center, &Pos, Amount); - q->m_aPoints[p].x = f2fx(Pos.x); - q->m_aPoints[p].y = f2fx(Pos.y); - } - } -} - -void CLayerQuads::GetSize(float *w, float *h) -{ - *w = 0; *h = 0; - - for(int i = 0; i < m_lQuads.size(); i++) - { - for(int p = 0; p < 5; p++) - { - *w = max(*w, fx2f(m_lQuads[i].m_aPoints[p].x)); - *h = max(*h, fx2f(m_lQuads[i].m_aPoints[p].y)); - } - } -} - -extern int gs_SelectedPoints; - -int CLayerQuads::RenderProperties(CUIRect *pToolBox) -{ - // layer props - enum - { - PROP_IMAGE=0, - NUM_PROPS, - }; - - CProperty aProps[] = { - {"Image", m_Image, PROPTYPE_IMAGE, -1, 0}, - {0}, - }; - - static int s_aIds[NUM_PROPS] = {0}; - int NewVal = 0; - int Prop = m_pEditor->DoProperties(pToolBox, aProps, s_aIds, &NewVal); - if(Prop != -1) - m_pEditor->m_Map.m_Modified = true; - - if(Prop == PROP_IMAGE) - { - if(NewVal >= 0) - m_Image = NewVal%m_pEditor->m_Map.m_lImages.size(); - else - m_Image = -1; - } - - return 0; -} - - -void CLayerQuads::ModifyImageIndex(INDEX_MODIFY_FUNC Func) -{ - Func(&m_Image); -} - -void CLayerQuads::ModifyEnvelopeIndex(INDEX_MODIFY_FUNC Func) -{ - for(int i = 0; i < m_lQuads.size(); i++) - { - Func(&m_lQuads[i].m_PosEnv); - Func(&m_lQuads[i].m_ColorEnv); - } -} diff --git a/src/game/editor/ed_layer_tiles.cpp b/src/game/editor/ed_layer_tiles.cpp deleted file mode 100644 index d0c9041c..00000000 --- a/src/game/editor/ed_layer_tiles.cpp +++ /dev/null @@ -1,460 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include - -#include -#include -#include - -#include -#include -#include "ed_editor.h" - -#include - -CLayerTiles::CLayerTiles(int w, int h) -{ - m_Type = LAYERTYPE_TILES; - m_pTypeName = "Tiles"; - m_Width = w; - m_Height = h; - m_Image = -1; - m_TexID = -1; - m_Game = 0; - m_Color.r = 255; - m_Color.g = 255; - m_Color.b = 255; - m_Color.a = 255; - - m_pTiles = new CTile[m_Width*m_Height]; - mem_zero(m_pTiles, m_Width*m_Height*sizeof(CTile)); -} - -CLayerTiles::~CLayerTiles() -{ - delete [] m_pTiles; -} - -void CLayerTiles::PrepareForSave() -{ - for(int y = 0; y < m_Height; y++) - for(int x = 0; x < m_Width; x++) - m_pTiles[y*m_Width+x].m_Flags &= TILEFLAG_VFLIP|TILEFLAG_HFLIP|TILEFLAG_ROTATE; - - if(m_Image != -1 && m_Color.a == 255) - { - for(int y = 0; y < m_Height; y++) - for(int x = 0; x < m_Width; x++) - m_pTiles[y*m_Width+x].m_Flags |= m_pEditor->m_Map.m_lImages[m_Image]->m_aTileFlags[m_pTiles[y*m_Width+x].m_Index]; - } -} - -void CLayerTiles::MakePalette() -{ - for(int y = 0; y < m_Height; y++) - for(int x = 0; x < m_Width; x++) - m_pTiles[y*m_Width+x].m_Index = y*16+x; -} - -void CLayerTiles::Render() -{ - if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size()) - m_TexID = m_pEditor->m_Map.m_lImages[m_Image]->m_TexID; - Graphics()->TextureSet(m_TexID); - vec4 Color = vec4(m_Color.r/255.0f, m_Color.g/255.0f, m_Color.b/255.0f, m_Color.a/255.0f); - m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT); -} - -int CLayerTiles::ConvertX(float x) const { return (int)(x/32.0f); } -int CLayerTiles::ConvertY(float y) const { return (int)(y/32.0f); } - -void CLayerTiles::Convert(CUIRect Rect, RECTi *pOut) -{ - pOut->x = ConvertX(Rect.x); - pOut->y = ConvertY(Rect.y); - pOut->w = ConvertX(Rect.x+Rect.w+31) - pOut->x; - pOut->h = ConvertY(Rect.y+Rect.h+31) - pOut->y; -} - -void CLayerTiles::Snap(CUIRect *pRect) -{ - RECTi Out; - Convert(*pRect, &Out); - pRect->x = Out.x*32.0f; - pRect->y = Out.y*32.0f; - pRect->w = Out.w*32.0f; - pRect->h = Out.h*32.0f; -} - -void CLayerTiles::Clamp(RECTi *pRect) -{ - if(pRect->x < 0) - { - pRect->w += pRect->x; - pRect->x = 0; - } - - if(pRect->y < 0) - { - pRect->h += pRect->y; - pRect->y = 0; - } - - if(pRect->x+pRect->w > m_Width) - pRect->w = m_Width - pRect->x; - - if(pRect->y+pRect->h > m_Height) - pRect->h = m_Height - pRect->y; - - if(pRect->h < 0) - pRect->h = 0; - if(pRect->w < 0) - pRect->w = 0; -} - -void CLayerTiles::BrushSelecting(CUIRect Rect) -{ - Graphics()->TextureSet(-1); - m_pEditor->Graphics()->QuadsBegin(); - m_pEditor->Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f); - Snap(&Rect); - IGraphics::CQuadItem QuadItem(Rect.x, Rect.y, Rect.w, Rect.h); - m_pEditor->Graphics()->QuadsDrawTL(&QuadItem, 1); - m_pEditor->Graphics()->QuadsEnd(); - char aBuf[16]; - str_format(aBuf, sizeof(aBuf), "%d,%d", ConvertX(Rect.w), ConvertY(Rect.h)); - TextRender()->Text(0, Rect.x+3.0f, Rect.y+3.0f, 15.0f*m_pEditor->m_WorldZoom, aBuf, -1); -} - -int CLayerTiles::BrushGrab(CLayerGroup *pBrush, CUIRect Rect) -{ - RECTi r; - Convert(Rect, &r); - Clamp(&r); - - if(!r.w || !r.h) - return 0; - - // create new layers - CLayerTiles *pGrabbed = new CLayerTiles(r.w, r.h); - pGrabbed->m_pEditor = m_pEditor; - pGrabbed->m_TexID = m_TexID; - pGrabbed->m_Image = m_Image; - pGrabbed->m_Game = m_Game; - pBrush->AddLayer(pGrabbed); - - // copy the tiles - for(int y = 0; y < r.h; y++) - for(int x = 0; x < r.w; x++) - pGrabbed->m_pTiles[y*pGrabbed->m_Width+x] = m_pTiles[(r.y+y)*m_Width+(r.x+x)]; - - return 1; -} - -void CLayerTiles::FillSelection(bool Empty, CLayer *pBrush, CUIRect Rect) -{ - if(m_Readonly) - return; - - int sx = ConvertX(Rect.x); - int sy = ConvertY(Rect.y); - int w = ConvertX(Rect.w); - int h = ConvertY(Rect.h); - - CLayerTiles *pLt = static_cast(pBrush); - - for(int y = 0; y <= h; y++) - { - for(int x = 0; x <= w; x++) - { - int fx = x+sx; - int fy = y+sy; - - if(fx < 0 || fx >= m_Width || fy < 0 || fy >= m_Height) - continue; - - if(Empty) - m_pTiles[fy*m_Width+fx].m_Index = 1; - else - m_pTiles[fy*m_Width+fx] = pLt->m_pTiles[(y*pLt->m_Width + x%pLt->m_Width) % (pLt->m_Width*pLt->m_Height)]; - } - } - m_pEditor->m_Map.m_Modified = true; -} - -void CLayerTiles::BrushDraw(CLayer *pBrush, float wx, float wy) -{ - if(m_Readonly) - return; - - // - CLayerTiles *l = (CLayerTiles *)pBrush; - int sx = ConvertX(wx); - int sy = ConvertY(wy); - - for(int y = 0; y < l->m_Height; y++) - for(int x = 0; x < l->m_Width; x++) - { - int fx = x+sx; - int fy = y+sy; - if(fx<0 || fx >= m_Width || fy < 0 || fy >= m_Height) - continue; - - m_pTiles[fy*m_Width+fx] = l->m_pTiles[y*l->m_Width+x]; - } - m_pEditor->m_Map.m_Modified = true; -} - -void CLayerTiles::BrushFlipX() -{ - for(int y = 0; y < m_Height; y++) - for(int x = 0; x < m_Width/2; x++) - { - CTile Tmp = m_pTiles[y*m_Width+x]; - m_pTiles[y*m_Width+x] = m_pTiles[y*m_Width+m_Width-1-x]; - m_pTiles[y*m_Width+m_Width-1-x] = Tmp; - } - - if(!m_Game) - for(int y = 0; y < m_Height; y++) - for(int x = 0; x < m_Width; x++) - m_pTiles[y*m_Width+x].m_Flags ^= m_pTiles[y*m_Width+x].m_Flags&TILEFLAG_ROTATE ? TILEFLAG_HFLIP : TILEFLAG_VFLIP; -} - -void CLayerTiles::BrushFlipY() -{ - for(int y = 0; y < m_Height/2; y++) - for(int x = 0; x < m_Width; x++) - { - CTile Tmp = m_pTiles[y*m_Width+x]; - m_pTiles[y*m_Width+x] = m_pTiles[(m_Height-1-y)*m_Width+x]; - m_pTiles[(m_Height-1-y)*m_Width+x] = Tmp; - } - - if(!m_Game) - for(int y = 0; y < m_Height; y++) - for(int x = 0; x < m_Width; x++) - m_pTiles[y*m_Width+x].m_Flags ^= m_pTiles[y*m_Width+x].m_Flags&TILEFLAG_ROTATE ? TILEFLAG_VFLIP : TILEFLAG_HFLIP; -} - -void CLayerTiles::BrushRotate(float Amount) -{ - int Rotation = (round(360.0f*Amount/(pi*2))/90)%4; // 0=0°, 1=90°, 2=180°, 3=270° - if(Rotation < 0) - Rotation +=4; - - if(Rotation == 1 || Rotation == 3) - { - // 90° rotation - CTile *pTempData = new CTile[m_Width*m_Height]; - mem_copy(pTempData, m_pTiles, m_Width*m_Height*sizeof(CTile)); - CTile *pDst = m_pTiles; - for(int x = 0; x < m_Width; ++x) - for(int y = m_Height-1; y >= 0; --y, ++pDst) - { - *pDst = pTempData[y*m_Width+x]; - if(!m_Game) - { - if(pDst->m_Flags&TILEFLAG_ROTATE) - pDst->m_Flags ^= (TILEFLAG_HFLIP|TILEFLAG_VFLIP); - pDst->m_Flags ^= TILEFLAG_ROTATE; - } - } - - int Temp = m_Width; - m_Width = m_Height; - m_Height = Temp; - delete[] pTempData; - } - - if(Rotation == 2 || Rotation == 3) - { - BrushFlipX(); - BrushFlipY(); - } -} - -void CLayerTiles::Resize(int NewW, int NewH) -{ - CTile *pNewData = new CTile[NewW*NewH]; - mem_zero(pNewData, NewW*NewH*sizeof(CTile)); - - // copy old data - for(int y = 0; y < min(NewH, m_Height); y++) - mem_copy(&pNewData[y*NewW], &m_pTiles[y*m_Width], min(m_Width, NewW)*sizeof(CTile)); - - // replace old - delete [] m_pTiles; - m_pTiles = pNewData; - m_Width = NewW; - m_Height = NewH; -} - -void CLayerTiles::Shift(int Direction) -{ - switch(Direction) - { - case 1: - { - // left - for(int y = 0; y < m_Height; ++y) - mem_move(&m_pTiles[y*m_Width], &m_pTiles[y*m_Width+1], (m_Width-1)*sizeof(CTile)); - } - break; - case 2: - { - // right - for(int y = 0; y < m_Height; ++y) - mem_move(&m_pTiles[y*m_Width+1], &m_pTiles[y*m_Width], (m_Width-1)*sizeof(CTile)); - } - break; - case 4: - { - // up - for(int y = 0; y < m_Height-1; ++y) - mem_copy(&m_pTiles[y*m_Width], &m_pTiles[(y+1)*m_Width], m_Width*sizeof(CTile)); - } - break; - case 8: - { - // down - for(int y = m_Height-1; y > 0; --y) - mem_copy(&m_pTiles[y*m_Width], &m_pTiles[(y-1)*m_Width], m_Width*sizeof(CTile)); - } - } -} - -void CLayerTiles::ShowInfo() -{ - float ScreenX0, ScreenY0, ScreenX1, ScreenY1; - Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1); - Graphics()->TextureSet(m_pEditor->Client()->GetDebugFont()); - - int StartY = max(0, (int)(ScreenY0/32.0f)-1); - int StartX = max(0, (int)(ScreenX0/32.0f)-1); - int EndY = min((int)(ScreenY1/32.0f)+1, m_Height); - int EndX = min((int)(ScreenX1/32.0f)+1, m_Width); - - for(int y = StartY; y < EndY; y++) - for(int x = StartX; x < EndX; x++) - { - int c = x + y*m_Width; - if(m_pTiles[c].m_Index) - { - char aBuf[64]; - str_format(aBuf, sizeof(aBuf), "%i", m_pTiles[c].m_Index); - m_pEditor->Graphics()->QuadsText(x*32, y*32, 16.0f, 1,1,1,1, aBuf); - - char aFlags[4] = { m_pTiles[c].m_Flags&TILEFLAG_VFLIP ? 'V' : ' ', - m_pTiles[c].m_Flags&TILEFLAG_HFLIP ? 'H' : ' ', - m_pTiles[c].m_Flags&TILEFLAG_ROTATE? 'R' : ' ', - 0}; - m_pEditor->Graphics()->QuadsText(x*32, y*32+16, 16.0f, 1,1,1,1, aFlags); - } - x += m_pTiles[c].m_Skip; - } -} - -int CLayerTiles::RenderProperties(CUIRect *pToolBox) -{ - CUIRect Button; - pToolBox->HSplitBottom(12.0f, pToolBox, &Button); - - bool InGameGroup = !find_linear(m_pEditor->m_Map.m_pGameGroup->m_lLayers.all(), this).empty(); - if(m_pEditor->m_Map.m_pGameLayer == this) - InGameGroup = false; - - if(InGameGroup) - { - static int s_ColclButton = 0; - if(m_pEditor->DoButton_Editor(&s_ColclButton, "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(); - if(Result > -1) - { - CLayerTiles *gl = m_pEditor->m_Map.m_pGameLayer; - int w = min(gl->m_Width, m_Width); - int h = min(gl->m_Height, m_Height); - for(int y = 0; y < h; y++) - for(int x = 0; x < w; x++) - if(m_pTiles[y*m_Width+x].m_Index) - gl->m_pTiles[y*gl->m_Width+x].m_Index = TILE_AIR+Result; - - return 1; - } - } - - enum - { - PROP_WIDTH=0, - PROP_HEIGHT, - PROP_SHIFT, - PROP_IMAGE, - PROP_COLOR, - NUM_PROPS, - }; - - int Color = 0; - Color |= m_Color.r<<24; - Color |= m_Color.g<<16; - Color |= m_Color.b<<8; - Color |= m_Color.a; - - CProperty aProps[] = { - {"Width", m_Width, PROPTYPE_INT_SCROLL, 1, 1000000000}, - {"Height", m_Height, PROPTYPE_INT_SCROLL, 1, 1000000000}, - {"Shift", 0, PROPTYPE_SHIFT, 0, 0}, - {"Image", m_Image, PROPTYPE_IMAGE, 0, 0}, - {"Color", Color, PROPTYPE_COLOR, 0, 0}, - {0}, - }; - - if(m_pEditor->m_Map.m_pGameLayer == this) // remove the image and color properties if this is the game layer - { - aProps[3].m_pName = 0; - aProps[4].m_pName = 0; - } - - static int s_aIds[NUM_PROPS] = {0}; - int NewVal = 0; - int Prop = m_pEditor->DoProperties(pToolBox, aProps, s_aIds, &NewVal); - if(Prop != -1) - m_pEditor->m_Map.m_Modified = true; - - if(Prop == PROP_WIDTH && NewVal > 1) - Resize(NewVal, m_Height); - else if(Prop == PROP_HEIGHT && NewVal > 1) - Resize(m_Width, NewVal); - else if(Prop == PROP_SHIFT) - Shift(NewVal); - else if(Prop == PROP_IMAGE) - { - if (NewVal == -1) - { - m_TexID = -1; - m_Image = -1; - } - else - m_Image = NewVal%m_pEditor->m_Map.m_lImages.size(); - } - else if(Prop == 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; - } - - return 0; -} - - -void CLayerTiles::ModifyImageIndex(INDEX_MODIFY_FUNC Func) -{ - Func(&m_Image); -} - -void CLayerTiles::ModifyEnvelopeIndex(INDEX_MODIFY_FUNC Func) -{ -} diff --git a/src/game/editor/ed_popups.cpp b/src/game/editor/ed_popups.cpp deleted file mode 100644 index f572e43c..00000000 --- a/src/game/editor/ed_popups.cpp +++ /dev/null @@ -1,739 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include -#include -#include -#include -#include -#include "ed_editor.h" - - -// popup menu handling -static struct -{ - CUIRect m_Rect; - void *m_pId; - int (*m_pfnFunc)(CEditor *pEditor, CUIRect Rect); - int m_IsMenu; - void *m_pExtra; -} s_UiPopups[8]; - -static int g_UiNumPopups = 0; - -void CEditor::UiInvokePopupMenu(void *pID, int Flags, float x, float y, float Width, float Height, int (*pfnFunc)(CEditor *pEditor, CUIRect Rect), void *pExtra) -{ - Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "editor", "invoked"); - if(x + Width > UI()->Screen()->w) - x -= Width; - if(y + Height > UI()->Screen()->h) - y -= Height; - s_UiPopups[g_UiNumPopups].m_pId = pID; - s_UiPopups[g_UiNumPopups].m_IsMenu = Flags; - s_UiPopups[g_UiNumPopups].m_Rect.x = x; - s_UiPopups[g_UiNumPopups].m_Rect.y = y; - s_UiPopups[g_UiNumPopups].m_Rect.w = Width; - s_UiPopups[g_UiNumPopups].m_Rect.h = Height; - s_UiPopups[g_UiNumPopups].m_pfnFunc = pfnFunc; - s_UiPopups[g_UiNumPopups].m_pExtra = pExtra; - g_UiNumPopups++; -} - -void CEditor::UiDoPopupMenu() -{ - for(int i = 0; i < g_UiNumPopups; i++) - { - bool Inside = UI()->MouseInside(&s_UiPopups[i].m_Rect); - UI()->SetHotItem(&s_UiPopups[i].m_pId); - - if(UI()->ActiveItem() == &s_UiPopups[i].m_pId) - { - if(!UI()->MouseButton(0)) - { - if(!Inside) - g_UiNumPopups--; - UI()->SetActiveItem(0); - } - } - else if(UI()->HotItem() == &s_UiPopups[i].m_pId) - { - if(UI()->MouseButton(0)) - UI()->SetActiveItem(&s_UiPopups[i].m_pId); - } - - int Corners = CUI::CORNER_ALL; - if(s_UiPopups[i].m_IsMenu) - Corners = CUI::CORNER_R|CUI::CORNER_B; - - CUIRect r = s_UiPopups[i].m_Rect; - RenderTools()->DrawUIRect(&r, vec4(0.5f,0.5f,0.5f,0.75f), Corners, 3.0f); - r.Margin(1.0f, &r); - RenderTools()->DrawUIRect(&r, vec4(0,0,0,0.75f), Corners, 3.0f); - r.Margin(4.0f, &r); - - if(s_UiPopups[i].m_pfnFunc(this, r)) - g_UiNumPopups--; - - if(Input()->KeyDown(KEY_ESCAPE)) - g_UiNumPopups--; - } -} - - -int CEditor::PopupGroup(CEditor *pEditor, CUIRect View) -{ - // remove group button - CUIRect Button; - View.HSplitBottom(12.0f, &View, &Button); - static int s_DeleteButton = 0; - - // don't allow deletion of game group - if(pEditor->m_Map.m_pGameGroup != pEditor->GetSelectedGroup()) - { - if(pEditor->DoButton_Editor(&s_DeleteButton, "Delete group", 0, &Button, 0, "Delete group")) - { - pEditor->m_Map.DeleteGroup(pEditor->m_SelectedGroup); - pEditor->m_SelectedGroup = max(0, pEditor->m_SelectedGroup-1); - return 1; - } - } - else - { - if(pEditor->DoButton_Editor(&s_DeleteButton, "Clean-up game tiles", 0, &Button, 0, "Removes game tiles that aren't based on a layer")) - { - // gather all tile layers - array Layers; - for(int i = 0; i < pEditor->m_Map.m_pGameGroup->m_lLayers.size(); ++i) - { - if(pEditor->m_Map.m_pGameGroup->m_lLayers[i] != pEditor->m_Map.m_pGameLayer && pEditor->m_Map.m_pGameGroup->m_lLayers[i]->m_Type == LAYERTYPE_TILES) - Layers.add(static_cast(pEditor->m_Map.m_pGameGroup->m_lLayers[i])); - } - - // search for unneeded game tiles - CLayerTiles *gl = pEditor->m_Map.m_pGameLayer; - for(int y = 0; y < gl->m_Height; ++y) - for(int x = 0; x < gl->m_Width; ++x) - { - if(gl->m_pTiles[y*gl->m_Width+x].m_Index > static_cast(TILE_NOHOOK)) - continue; - - bool Found = false; - for(int i = 0; i < Layers.size(); ++i) - { - if(x < Layers[i]->m_Width && y < Layers[i]->m_Height && Layers[i]->m_pTiles[y*Layers[i]->m_Width+x].m_Index) - { - Found = true; - break; - } - } - - if(!Found) - { - gl->m_pTiles[y*gl->m_Width+x].m_Index = TILE_AIR; - pEditor->m_Map.m_Modified = true; - } - } - - return 1; - } - } - - // new tile layer - View.HSplitBottom(10.0f, &View, &Button); - View.HSplitBottom(12.0f, &View, &Button); - static int s_NewQuadLayerButton = 0; - if(pEditor->DoButton_Editor(&s_NewQuadLayerButton, "Add quads layer", 0, &Button, 0, "Creates a new quad layer")) - { - CLayer *l = new CLayerQuads; - l->m_pEditor = pEditor; - pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->AddLayer(l); - pEditor->m_SelectedLayer = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_lLayers.size()-1; - return 1; - } - - // new quad layer - View.HSplitBottom(5.0f, &View, &Button); - View.HSplitBottom(12.0f, &View, &Button); - static int s_NewTileLayerButton = 0; - if(pEditor->DoButton_Editor(&s_NewTileLayerButton, "Add tile layer", 0, &Button, 0, "Creates a new tile layer")) - { - CLayer *l = new CLayerTiles(50, 50); - l->m_pEditor = pEditor; - pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->AddLayer(l); - pEditor->m_SelectedLayer = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_lLayers.size()-1; - return 1; - } - - 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, pEditor->m_Map.m_lGroups.size()-1}, - {"Pos X", -pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_OffsetX, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {"Pos Y", -pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_OffsetY, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {"Para X", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ParallaxX, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {"Para Y", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ParallaxY, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - - {"Use Clipping", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_UseClipping, PROPTYPE_BOOL, 0, 1}, - {"Clip X", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipX, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {"Clip Y", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipY, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {"Clip W", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipW, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {"Clip H", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipH, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {0}, - }; - - static int s_aIds[NUM_PROPS] = {0}; - int NewVal = 0; - - // cut the properties that isn't needed - if(pEditor->GetSelectedGroup()->m_GameGroup) - aProps[PROP_POS_X].m_pName = 0; - - int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal); - if(Prop != -1) - pEditor->m_Map.m_Modified = true; - - if(Prop == PROP_ORDER) - pEditor->m_SelectedGroup = pEditor->m_Map.SwapGroups(pEditor->m_SelectedGroup, NewVal); - - // these can not be changed on the game group - if(!pEditor->GetSelectedGroup()->m_GameGroup) - { - if(Prop == PROP_PARA_X) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ParallaxX = NewVal; - else if(Prop == PROP_PARA_Y) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ParallaxY = NewVal; - else if(Prop == PROP_POS_X) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_OffsetX = -NewVal; - else if(Prop == PROP_POS_Y) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_OffsetY = -NewVal; - else if(Prop == PROP_USE_CLIPPING) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_UseClipping = NewVal; - else if(Prop == PROP_CLIP_X) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipX = NewVal; - else if(Prop == PROP_CLIP_Y) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipY = NewVal; - else if(Prop == PROP_CLIP_W) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipW = NewVal; - else if(Prop == PROP_CLIP_H) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipH = NewVal; - } - - return 0; -} - -int CEditor::PopupLayer(CEditor *pEditor, CUIRect View) -{ - // remove layer button - CUIRect Button; - View.HSplitBottom(12.0f, &View, &Button); - static int s_DeleteButton = 0; - - // don't allow deletion of game layer - if(pEditor->m_Map.m_pGameLayer != pEditor->GetSelectedLayer(0) && - pEditor->DoButton_Editor(&s_DeleteButton, "Delete layer", 0, &Button, 0, "Deletes the layer")) - { - pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->DeleteLayer(pEditor->m_SelectedLayer); - return 1; - } - - View.HSplitBottom(10.0f, &View, 0); - - CLayerGroup *pCurrentGroup = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]; - CLayer *pCurrentLayer = pEditor->GetSelectedLayer(0); - - enum - { - PROP_GROUP=0, - PROP_ORDER, - PROP_HQ, - NUM_PROPS, - }; - - CProperty aProps[] = { - {"Group", pEditor->m_SelectedGroup, PROPTYPE_INT_STEP, 0, pEditor->m_Map.m_lGroups.size()-1}, - {"Order", pEditor->m_SelectedLayer, PROPTYPE_INT_STEP, 0, pCurrentGroup->m_lLayers.size()}, - {"Detail", pCurrentLayer->m_Flags&LAYERFLAG_DETAIL, PROPTYPE_BOOL, 0, 1}, - {0}, - }; - - if(pEditor->m_Map.m_pGameLayer == pEditor->GetSelectedLayer(0)) // dont use Group and Detail from the selection if this is the game layer - { - aProps[0].m_Type = PROPTYPE_NULL; - aProps[2].m_Type = PROPTYPE_NULL; - } - - static int s_aIds[NUM_PROPS] = {0}; - int NewVal = 0; - int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal); - if(Prop != -1) - pEditor->m_Map.m_Modified = true; - - if(Prop == PROP_ORDER) - pEditor->m_SelectedLayer = pCurrentGroup->SwapLayers(pEditor->m_SelectedLayer, NewVal); - else if(Prop == PROP_GROUP && pCurrentLayer->m_Type != LAYERTYPE_GAME) - { - if(NewVal >= 0 && NewVal < pEditor->m_Map.m_lGroups.size()) - { - pCurrentGroup->m_lLayers.remove(pCurrentLayer); - pEditor->m_Map.m_lGroups[NewVal]->m_lLayers.add(pCurrentLayer); - pEditor->m_SelectedGroup = NewVal; - pEditor->m_SelectedLayer = pEditor->m_Map.m_lGroups[NewVal]->m_lLayers.size()-1; - } - } - else if(Prop == PROP_HQ) - { - pCurrentLayer->m_Flags &= ~LAYERFLAG_DETAIL; - if(NewVal) - pCurrentLayer->m_Flags |= LAYERFLAG_DETAIL; - } - - return pCurrentLayer->RenderProperties(&View); -} - -int CEditor::PopupQuad(CEditor *pEditor, CUIRect View) -{ - CQuad *pQuad = pEditor->GetSelectedQuad(); - - CUIRect Button; - - // delete button - View.HSplitBottom(12.0f, &View, &Button); - static int s_DeleteButton = 0; - if(pEditor->DoButton_Editor(&s_DeleteButton, "Delete", 0, &Button, 0, "Deletes the current quad")) - { - CLayerQuads *pLayer = (CLayerQuads *)pEditor->GetSelectedLayerType(0, LAYERTYPE_QUADS); - if(pLayer) - { - pEditor->m_Map.m_Modified = true; - pLayer->m_lQuads.remove_index(pEditor->m_SelectedQuad); - pEditor->m_SelectedQuad--; - } - return 1; - } - - // aspect ratio button - View.HSplitBottom(10.0f, &View, &Button); - View.HSplitBottom(12.0f, &View, &Button); - CLayerQuads *pLayer = (CLayerQuads *)pEditor->GetSelectedLayerType(0, LAYERTYPE_QUADS); - if(pLayer && pLayer->m_Image >= 0 && pLayer->m_Image < pEditor->m_Map.m_lImages.size()) - { - 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")) - { - int Top = pQuad->m_aPoints[0].y; - int Left = pQuad->m_aPoints[0].x; - int Right = pQuad->m_aPoints[0].x; - - for(int k = 1; k < 4; k++) - { - if(pQuad->m_aPoints[k].y < Top) Top = pQuad->m_aPoints[k].y; - if(pQuad->m_aPoints[k].x < Left) Left = pQuad->m_aPoints[k].x; - if(pQuad->m_aPoints[k].x > Right) Right = pQuad->m_aPoints[k].x; - } - - int Height = (Right-Left)*pEditor->m_Map.m_lImages[pLayer->m_Image]->m_Height/pEditor->m_Map.m_lImages[pLayer->m_Image]->m_Width; - - pQuad->m_aPoints[0].x = Left; pQuad->m_aPoints[0].y = Top; - pQuad->m_aPoints[1].x = Right; pQuad->m_aPoints[1].y = Top; - pQuad->m_aPoints[2].x = Left; pQuad->m_aPoints[2].y = Top+Height; - pQuad->m_aPoints[3].x = Right; pQuad->m_aPoints[3].y = Top+Height; - pEditor->m_Map.m_Modified = true; - return 1; - } - } - - // align button - View.HSplitBottom(6.0f, &View, &Button); - View.HSplitBottom(12.0f, &View, &Button); - static int s_AlignButton = 0; - if(pEditor->DoButton_Editor(&s_AlignButton, "Align", 0, &Button, 0, "Aligns coordinates of the quad points")) - { - for(int k = 1; k < 4; k++) - { - pQuad->m_aPoints[k].x = 1000.0f * (int(pQuad->m_aPoints[k].x) / 1000); - pQuad->m_aPoints[k].y = 1000.0f * (int(pQuad->m_aPoints[k].y) / 1000); - } - pEditor->m_Map.m_Modified = true; - return 1; - } - - // square button - View.HSplitBottom(6.0f, &View, &Button); - View.HSplitBottom(12.0f, &View, &Button); - static int s_Button = 0; - if(pEditor->DoButton_Editor(&s_Button, "Square", 0, &Button, 0, "Squares the current quad")) - { - int Top = pQuad->m_aPoints[0].y; - int Left = pQuad->m_aPoints[0].x; - int Bottom = pQuad->m_aPoints[0].y; - int Right = pQuad->m_aPoints[0].x; - - for(int k = 1; k < 4; k++) - { - if(pQuad->m_aPoints[k].y < Top) Top = pQuad->m_aPoints[k].y; - if(pQuad->m_aPoints[k].x < Left) Left = pQuad->m_aPoints[k].x; - if(pQuad->m_aPoints[k].y > Bottom) Bottom = pQuad->m_aPoints[k].y; - if(pQuad->m_aPoints[k].x > Right) Right = pQuad->m_aPoints[k].x; - } - - pQuad->m_aPoints[0].x = Left; pQuad->m_aPoints[0].y = Top; - pQuad->m_aPoints[1].x = Right; pQuad->m_aPoints[1].y = Top; - pQuad->m_aPoints[2].x = Left; pQuad->m_aPoints[2].y = Bottom; - pQuad->m_aPoints[3].x = Right; pQuad->m_aPoints[3].y = Bottom; - pEditor->m_Map.m_Modified = true; - return 1; - } - - - enum - { - PROP_POS_X=0, - PROP_POS_Y, - PROP_POS_ENV, - PROP_POS_ENV_OFFSET, - PROP_COLOR_ENV, - PROP_COLOR_ENV_OFFSET, - NUM_PROPS, - }; - - CProperty aProps[] = { - {"Pos X", pQuad->m_aPoints[4].x/1000, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {"Pos Y", pQuad->m_aPoints[4].y/1000, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {"Pos. Env", pQuad->m_PosEnv+1, PROPTYPE_INT_STEP, 0, pEditor->m_Map.m_lEnvelopes.size()+1}, - {"Pos. TO", pQuad->m_PosEnvOffset, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {"Color Env", pQuad->m_ColorEnv+1, PROPTYPE_INT_STEP, 0, pEditor->m_Map.m_lEnvelopes.size()+1}, - {"Color TO", pQuad->m_ColorEnvOffset, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - - {0}, - }; - - static int s_aIds[NUM_PROPS] = {0}; - int NewVal = 0; - int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal); - if(Prop != -1) - pEditor->m_Map.m_Modified = true; - - if(Prop == PROP_POS_X) - { - float Offset = NewVal*1000-pQuad->m_aPoints[4].x; - for(int k = 0; k < 5; ++k) - pQuad->m_aPoints[k].x += Offset; - } - if(Prop == PROP_POS_Y) - { - float Offset = NewVal*1000-pQuad->m_aPoints[4].y; - for(int k = 0; k < 5; ++k) - pQuad->m_aPoints[k].y += Offset; - } - if(Prop == PROP_POS_ENV) pQuad->m_PosEnv = clamp(NewVal-1, -1, pEditor->m_Map.m_lEnvelopes.size()-1); - if(Prop == PROP_POS_ENV_OFFSET) pQuad->m_PosEnvOffset = NewVal; - if(Prop == PROP_COLOR_ENV) pQuad->m_ColorEnv = clamp(NewVal-1, -1, pEditor->m_Map.m_lEnvelopes.size()-1); - if(Prop == PROP_COLOR_ENV_OFFSET) pQuad->m_ColorEnvOffset = NewVal; - - return 0; -} - -int CEditor::PopupPoint(CEditor *pEditor, CUIRect View) -{ - CQuad *pQuad = pEditor->GetSelectedQuad(); - - enum - { - PROP_POS_X=0, - PROP_POS_Y, - PROP_COLOR, - NUM_PROPS, - }; - - int Color = 0; - int x = 0, y = 0; - - for(int v = 0; v < 4; v++) - { - if(pEditor->m_SelectedPoints&(1<m_aColors[v].r<<24; - Color |= pQuad->m_aColors[v].g<<16; - Color |= pQuad->m_aColors[v].b<<8; - Color |= pQuad->m_aColors[v].a; - - x = pQuad->m_aPoints[v].x/1000; - y = pQuad->m_aPoints[v].y/1000; - } - } - - - CProperty aProps[] = { - {"Pos X", x, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {"Pos Y", y, PROPTYPE_INT_SCROLL, -1000000, 1000000}, - {"Color", Color, PROPTYPE_COLOR, -1, pEditor->m_Map.m_lEnvelopes.size()}, - {0}, - }; - - static int s_aIds[NUM_PROPS] = {0}; - int NewVal = 0; - int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal); - if(Prop != -1) - pEditor->m_Map.m_Modified = true; - - if(Prop == PROP_POS_X) - { - for(int v = 0; v < 4; v++) - if(pEditor->m_SelectedPoints&(1<m_aPoints[v].x = NewVal*1000; - } - if(Prop == PROP_POS_Y) - { - for(int v = 0; v < 4; v++) - if(pEditor->m_SelectedPoints&(1<m_aPoints[v].y = NewVal*1000; - } - if(Prop == PROP_COLOR) - { - for(int v = 0; v < 4; v++) - { - if(pEditor->m_SelectedPoints&(1<m_aColors[v].r = (NewVal>>24)&0xff; - pQuad->m_aColors[v].g = (NewVal>>16)&0xff; - pQuad->m_aColors[v].b = (NewVal>>8)&0xff; - pQuad->m_aColors[v].a = NewVal&0xff; - } - } - } - - return 0; -} - -int CEditor::PopupNewFolder(CEditor *pEditor, CUIRect View) -{ - CUIRect Label, ButtonBar; - - // title - View.HSplitTop(10.0f, 0, &View); - View.HSplitTop(30.0f, &Label, &View); - pEditor->UI()->DoLabel(&Label, "Create new folder", 20.0f, 0); - - View.HSplitBottom(10.0f, &View, 0); - View.HSplitBottom(20.0f, &View, &ButtonBar); - - if(pEditor->m_FileDialogErrString[0] == 0) - { - // interaction box - View.HSplitBottom(40.0f, &View, 0); - View.VMargin(40.0f, &View); - View.HSplitBottom(20.0f, &View, &Label); - static int s_FolderBox = 0; - pEditor->DoEditBox(&s_FolderBox, &Label, pEditor->m_FileDialogNewFolderName, sizeof(pEditor->m_FileDialogNewFolderName), 15.0f); - View.HSplitBottom(20.0f, &View, &Label); - pEditor->UI()->DoLabel(&Label, "Name:", 10.0f, -1); - - // button bar - ButtonBar.VSplitLeft(30.0f, 0, &ButtonBar); - ButtonBar.VSplitLeft(110.0f, &Label, &ButtonBar); - static int s_CreateButton = 0; - if(pEditor->DoButton_Editor(&s_CreateButton, "Create", 0, &Label, 0, 0)) - { - // create the folder - if(*pEditor->m_FileDialogNewFolderName) - { - char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "%s/%s", pEditor->m_pFileDialogPath, pEditor->m_FileDialogNewFolderName); - if(pEditor->Storage()->CreateFolder(aBuf, IStorage::TYPE_SAVE)) - { - pEditor->FilelistPopulate(IStorage::TYPE_SAVE); - return 1; - } - else - str_copy(pEditor->m_FileDialogErrString, "Unable to create the folder", sizeof(pEditor->m_FileDialogErrString)); - } - } - ButtonBar.VSplitRight(30.0f, &ButtonBar, 0); - ButtonBar.VSplitRight(110.0f, &ButtonBar, &Label); - static int s_AbortButton = 0; - if(pEditor->DoButton_Editor(&s_AbortButton, "Abort", 0, &Label, 0, 0)) - return 1; - } - else - { - // error text - View.HSplitTop(30.0f, 0, &View); - View.VMargin(40.0f, &View); - View.HSplitTop(20.0f, &Label, &View); - pEditor->UI()->DoLabel(&Label, "Error:", 10.0f, -1); - View.HSplitTop(20.0f, &Label, &View); - pEditor->UI()->DoLabel(&Label, "Unable to create the folder", 10.0f, -1, View.w); - - // button - ButtonBar.VMargin(ButtonBar.w/2.0f-55.0f, &ButtonBar); - static int s_CreateButton = 0; - if(pEditor->DoButton_Editor(&s_CreateButton, "Ok", 0, &ButtonBar, 0, 0)) - return 1; - } - - return 0; -} - -int CEditor::PopupEvent(CEditor *pEditor, CUIRect View) -{ - CUIRect Label, ButtonBar; - - // title - View.HSplitTop(10.0f, 0, &View); - View.HSplitTop(30.0f, &Label, &View); - if(pEditor->m_PopupEventType == POPEVENT_EXIT) - pEditor->UI()->DoLabel(&Label, "Exit the editor", 20.0f, 0); - else if(pEditor->m_PopupEventType == POPEVENT_LOAD) - pEditor->UI()->DoLabel(&Label, "Load map", 20.0f, 0); - else if(pEditor->m_PopupEventType == POPEVENT_NEW) - pEditor->UI()->DoLabel(&Label, "New map", 20.0f, 0); - else if(pEditor->m_PopupEventType == POPEVENT_SAVE) - pEditor->UI()->DoLabel(&Label, "Save map", 20.0f, 0); - - View.HSplitBottom(10.0f, &View, 0); - View.HSplitBottom(20.0f, &View, &ButtonBar); - - // notification text - View.HSplitTop(30.0f, 0, &View); - View.VMargin(40.0f, &View); - View.HSplitTop(20.0f, &Label, &View); - if(pEditor->m_PopupEventType == POPEVENT_EXIT) - pEditor->UI()->DoLabel(&Label, "The map contains unsaved data, you might want to save it before you exit the editor.\nContinue anyway?", 10.0f, -1, Label.w-10.0f); - else if(pEditor->m_PopupEventType == POPEVENT_LOAD) - pEditor->UI()->DoLabel(&Label, "The map contains unsaved data, you might want to save it before you load a new map.\nContinue anyway?", 10.0f, -1, Label.w-10.0f); - else if(pEditor->m_PopupEventType == POPEVENT_NEW) - pEditor->UI()->DoLabel(&Label, "The map contains unsaved data, you might want to save it before you create a new map.\nContinue anyway?", 10.0f, -1, Label.w-10.0f); - else if(pEditor->m_PopupEventType == POPEVENT_SAVE) - pEditor->UI()->DoLabel(&Label, "The file already exists.\nDo you want to overwrite the map?", 10.0f, -1); - - // button bar - ButtonBar.VSplitLeft(30.0f, 0, &ButtonBar); - ButtonBar.VSplitLeft(110.0f, &Label, &ButtonBar); - static int s_OkButton = 0; - if(pEditor->DoButton_Editor(&s_OkButton, "Ok", 0, &Label, 0, 0)) - { - if(pEditor->m_PopupEventType == POPEVENT_EXIT) - g_Config.m_ClEditor = 0; - else if(pEditor->m_PopupEventType == POPEVENT_LOAD) - pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_MAP, "Load map", "Load", "maps", "", pEditor->CallbackOpenMap, pEditor); - else if(pEditor->m_PopupEventType == POPEVENT_NEW) - { - pEditor->Reset(); - pEditor->m_aFileName[0] = 0; - } - else if(pEditor->m_PopupEventType == POPEVENT_SAVE) - pEditor->CallbackSaveMap(pEditor->m_aFileSaveName, IStorage::TYPE_SAVE, pEditor); - return 1; - } - ButtonBar.VSplitRight(30.0f, &ButtonBar, 0); - ButtonBar.VSplitRight(110.0f, &ButtonBar, &Label); - static int s_AbortButton = 0; - if(pEditor->DoButton_Editor(&s_AbortButton, "Abort", 0, &Label, 0, 0)) - return 1; - - return 0; -} - - -static int g_SelectImageSelected = -100; -static int g_SelectImageCurrent = -100; - -int CEditor::PopupSelectImage(CEditor *pEditor, CUIRect View) -{ - CUIRect ButtonBar, ImageView; - View.VSplitLeft(80.0f, &ButtonBar, &View); - View.Margin(10.0f, &ImageView); - - int ShowImage = g_SelectImageCurrent; - - for(int i = -1; i < pEditor->m_Map.m_lImages.size(); i++) - { - CUIRect Button; - ButtonBar.HSplitTop(12.0f, &Button, &ButtonBar); - ButtonBar.HSplitTop(2.0f, 0, &ButtonBar); - - if(pEditor->UI()->MouseInside(&Button)) - ShowImage = i; - - if(i == -1) - { - if(pEditor->DoButton_MenuItem(&pEditor->m_Map.m_lImages[i], "None", i==g_SelectImageCurrent, &Button)) - g_SelectImageSelected = -1; - } - else - { - if(pEditor->DoButton_MenuItem(&pEditor->m_Map.m_lImages[i], pEditor->m_Map.m_lImages[i]->m_aName, i==g_SelectImageCurrent, &Button)) - g_SelectImageSelected = i; - } - } - - if(ShowImage >= 0 && ShowImage < pEditor->m_Map.m_lImages.size()) - pEditor->Graphics()->TextureSet(pEditor->m_Map.m_lImages[ShowImage]->m_TexID); - else - pEditor->Graphics()->TextureSet(-1); - pEditor->Graphics()->QuadsBegin(); - IGraphics::CQuadItem QuadItem(ImageView.x, ImageView.y, ImageView.w, ImageView.h); - pEditor->Graphics()->QuadsDrawTL(&QuadItem, 1); - pEditor->Graphics()->QuadsEnd(); - - return 0; -} - -void CEditor::PopupSelectImageInvoke(int Current, float x, float y) -{ - static int s_SelectImagePopupId = 0; - g_SelectImageSelected = -100; - g_SelectImageCurrent = Current; - UiInvokePopupMenu(&s_SelectImagePopupId, 0, x, y, 400, 300, PopupSelectImage); -} - -int CEditor::PopupSelectImageResult() -{ - if(g_SelectImageSelected == -100) - return -100; - - g_SelectImageCurrent = g_SelectImageSelected; - g_SelectImageSelected = -100; - return g_SelectImageCurrent; -} - -static int s_GametileOpSelected = -1; - -int CEditor::PopupSelectGametileOp(CEditor *pEditor, CUIRect View) -{ - static const char *s_pButtonNames[] = { "Clear", "Collision", "Death", "Unhookable" }; - static unsigned s_NumButtons = sizeof(s_pButtonNames) / sizeof(char*); - CUIRect Button; - - for(unsigned i = 0; i < s_NumButtons; ++i) - { - View.HSplitTop(2.0f, 0, &View); - View.HSplitTop(12.0f, &Button, &View); - if(pEditor->DoButton_Editor(&s_pButtonNames[i], s_pButtonNames[i], 0, &Button, 0, 0)) - s_GametileOpSelected = i; - } - - return 0; -} - -void CEditor::PopupSelectGametileOpInvoke(float x, float y) -{ - static int s_SelectGametileOpPopupId = 0; - s_GametileOpSelected = -1; - UiInvokePopupMenu(&s_SelectGametileOpPopupId, 0, x, y, 120.0f, 70.0f, PopupSelectGametileOp); -} - -int CEditor::PopupSelectGameTileOpResult() -{ - if(s_GametileOpSelected < 0) - return -1; - - int Result = s_GametileOpSelected; - s_GametileOpSelected = -1; - return Result; -} diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp new file mode 100644 index 00000000..e12b20bf --- /dev/null +++ b/src/game/editor/editor.cpp @@ -0,0 +1,3428 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "editor.h" +#include + +#include + +int CEditor::ms_CheckerTexture; +int CEditor::ms_BackgroundTexture; +int CEditor::ms_CursorTexture; +int CEditor::ms_EntitiesTexture; +const void* CEditor::ms_pUiGotContext; + +enum +{ + BUTTON_CONTEXT=1, +}; + +CEditorImage::~CEditorImage() +{ + m_pEditor->Graphics()->UnloadTexture(m_TexID); +} + +CLayerGroup::CLayerGroup() +{ + m_pName = ""; + m_Visible = true; + m_SaveToMap = true; + m_GameGroup = false; + m_OffsetX = 0; + m_OffsetY = 0; + m_ParallaxX = 100; + m_ParallaxY = 100; + + m_UseClipping = 0; + m_ClipX = 0; + m_ClipY = 0; + m_ClipW = 0; + m_ClipH = 0; +} + +CLayerGroup::~CLayerGroup() +{ + Clear(); +} + +void CLayerGroup::Convert(CUIRect *pRect) +{ + pRect->x += m_OffsetX; + pRect->y += m_OffsetY; +} + +void CLayerGroup::Mapping(float *pPoints) +{ + m_pMap->m_pEditor->RenderTools()->MapscreenToWorld( + m_pMap->m_pEditor->m_WorldOffsetX, m_pMap->m_pEditor->m_WorldOffsetY, + m_ParallaxX/100.0f, m_ParallaxY/100.0f, + m_OffsetX, m_OffsetY, + m_pMap->m_pEditor->Graphics()->ScreenAspect(), m_pMap->m_pEditor->m_WorldZoom, pPoints); + + pPoints[0] += m_pMap->m_pEditor->m_EditorOffsetX; + pPoints[1] += m_pMap->m_pEditor->m_EditorOffsetY; + pPoints[2] += m_pMap->m_pEditor->m_EditorOffsetX; + pPoints[3] += m_pMap->m_pEditor->m_EditorOffsetY; +} + +void CLayerGroup::MapScreen() +{ + float aPoints[4]; + Mapping(aPoints); + m_pMap->m_pEditor->Graphics()->MapScreen(aPoints[0], aPoints[1], aPoints[2], aPoints[3]); +} + +void CLayerGroup::Render() +{ + MapScreen(); + IGraphics *pGraphics = m_pMap->m_pEditor->Graphics(); + + if(m_UseClipping) + { + float aPoints[4]; + m_pMap->m_pGameGroup->Mapping(aPoints); + float x0 = (m_ClipX - aPoints[0]) / (aPoints[2]-aPoints[0]); + float y0 = (m_ClipY - aPoints[1]) / (aPoints[3]-aPoints[1]); + float x1 = ((m_ClipX+m_ClipW) - aPoints[0]) / (aPoints[2]-aPoints[0]); + float y1 = ((m_ClipY+m_ClipH) - aPoints[1]) / (aPoints[3]-aPoints[1]); + + pGraphics->ClipEnable((int)(x0*pGraphics->ScreenWidth()), (int)(y0*pGraphics->ScreenHeight()), + (int)((x1-x0)*pGraphics->ScreenWidth()), (int)((y1-y0)*pGraphics->ScreenHeight())); + } + + for(int i = 0; i < m_lLayers.size(); i++) + { + if(m_lLayers[i]->m_Visible && m_lLayers[i] != m_pMap->m_pGameLayer) + { + if(m_pMap->m_pEditor->m_ShowDetail || !(m_lLayers[i]->m_Flags&LAYERFLAG_DETAIL)) + m_lLayers[i]->Render(); + } + } + + pGraphics->ClipDisable(); +} + +void CLayerGroup::AddLayer(CLayer *l) +{ + m_pMap->m_Modified = true; + m_lLayers.add(l); +} + +void CLayerGroup::DeleteLayer(int Index) +{ + if(Index < 0 || Index >= m_lLayers.size()) return; + delete m_lLayers[Index]; + m_lLayers.remove_index(Index); + m_pMap->m_Modified = true; +} + +void CLayerGroup::GetSize(float *w, float *h) +{ + *w = 0; *h = 0; + for(int i = 0; i < m_lLayers.size(); i++) + { + float lw, lh; + m_lLayers[i]->GetSize(&lw, &lh); + *w = max(*w, lw); + *h = max(*h, lh); + } +} + + +int CLayerGroup::SwapLayers(int Index0, int Index1) +{ + if(Index0 < 0 || Index0 >= m_lLayers.size()) return Index0; + if(Index1 < 0 || Index1 >= m_lLayers.size()) return Index0; + if(Index0 == Index1) return Index0; + m_pMap->m_Modified = true; + swap(m_lLayers[Index0], m_lLayers[Index1]); + return Index1; +} + +void CEditorImage::AnalyseTileFlags() +{ + mem_zero(m_aTileFlags, sizeof(m_aTileFlags)); + + int tw = m_Width/16; // tilesizes + int th = m_Height/16; + if ( tw == th ) + { + unsigned char *pPixelData = (unsigned char *)m_pData; + + int TileID = 0; + for(int ty = 0; ty < 16; ty++) + for(int tx = 0; tx < 16; tx++, TileID++) + { + bool Opaque = true; + for(int x = 0; x < tw; x++) + for(int y = 0; y < th; y++) + { + int p = (ty*tw+y)*m_Width + tx*tw+x; + if(pPixelData[p*4+3] < 250) + { + Opaque = false; + break; + } + } + + if(Opaque) + m_aTileFlags[TileID] |= TILEFLAG_OPAQUE; + } + } + +} + +/******************************************************** + OTHER +*********************************************************/ + +// copied from gc_menu.cpp, should be more generalized +//extern int ui_do_edit_box(void *id, const CUIRect *rect, char *str, int str_size, float font_size, bool hidden=false); + +int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden) +{ + int Inside = UI()->MouseInside(pRect); + bool ReturnValue = false; + static int s_AtIndex = 0; + + if(UI()->LastActiveItem() == pID) + { + int Len = str_length(pStr); + + if(Inside && UI()->MouseButton(0)) + { + int MxRel = (int)(UI()->MouseX() - pRect->x); + + for (int i = 1; i <= Len; i++) + { + if (TextRender()->TextWidth(0, FontSize, pStr, i) + 10 > MxRel) + { + s_AtIndex = i - 1; + break; + } + + if (i == Len) + s_AtIndex = Len; + } + } + + for(int i = 0; i < Input()->NumEvents(); i++) + { + Len = str_length(pStr); + ReturnValue |= CLineInput::Manipulate(Input()->GetEvent(i), pStr, StrSize, &Len, &s_AtIndex); + } + } + + bool JustGotActive = false; + + if(UI()->ActiveItem() == pID) + { + if(!UI()->MouseButton(0)) + UI()->SetActiveItem(0); + } + else if(UI()->HotItem() == pID) + { + if(UI()->MouseButton(0)) + { + if (UI()->LastActiveItem() != pID) + JustGotActive = true; + UI()->SetActiveItem(pID); + } + } + + if(Inside) + UI()->SetHotItem(pID); + + CUIRect Textbox = *pRect; + RenderTools()->DrawUIRect(&Textbox, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 3.0f); + Textbox.VMargin(3.0f, &Textbox); + + const char *pDisplayStr = pStr; + char aStars[128]; + + if(Hidden) + { + unsigned s = str_length(pStr); + if(s >= sizeof(aStars)) + s = sizeof(aStars)-1; + for(unsigned int i = 0; i < s; ++i) + aStars[i] = '*'; + aStars[s] = 0; + pDisplayStr = aStars; + } + + UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1); + + //TODO: make it blink + if(UI()->LastActiveItem() == pID && !JustGotActive) + { + float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex); + Textbox = *pRect; + Textbox.VSplitLeft(2.0f, 0, &Textbox); + Textbox.x += w*UI()->Scale(); + Textbox.y -= FontSize/10.f; + + UI()->DoLabel(&Textbox, "|", FontSize*1.1f, -1); + } + + return ReturnValue; +} + +vec4 CEditor::ButtonColorMul(const void *pID) +{ + if(UI()->ActiveItem() == pID) + return vec4(1,1,1,0.5f); + else if(UI()->HotItem() == pID) + return vec4(1,1,1,1.5f); + return vec4(1,1,1,1); +} + +float CEditor::UiDoScrollbarV(const void *pID, const CUIRect *pRect, float Current) +{ + CUIRect Handle; + static float s_OffsetY; + pRect->HSplitTop(33, &Handle, 0); + + Handle.y += (pRect->h-Handle.h)*Current; + + // logic + float Ret = Current; + int Inside = UI()->MouseInside(&Handle); + + if(UI()->ActiveItem() == pID) + { + if(!UI()->MouseButton(0)) + UI()->SetActiveItem(0); + + float Min = pRect->y; + float Max = pRect->h-Handle.h; + float Cur = UI()->MouseY()-s_OffsetY; + Ret = (Cur-Min)/Max; + if(Ret < 0.0f) Ret = 0.0f; + if(Ret > 1.0f) Ret = 1.0f; + } + else if(UI()->HotItem() == pID) + { + if(UI()->MouseButton(0)) + { + UI()->SetActiveItem(pID); + s_OffsetY = UI()->MouseY()-Handle.y; + } + } + + if(Inside) + UI()->SetHotItem(pID); + + // render + CUIRect Rail; + pRect->VMargin(5.0f, &Rail); + RenderTools()->DrawUIRect(&Rail, vec4(1,1,1,0.25f), 0, 0.0f); + + CUIRect Slider = Handle; + Slider.w = Rail.x-Slider.x; + RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f), CUI::CORNER_L, 2.5f); + Slider.x = Rail.x+Rail.w; + RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f), CUI::CORNER_R, 2.5f); + + Slider = Handle; + Slider.Margin(5.0f, &Slider); + RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f)*ButtonColorMul(pID), CUI::CORNER_ALL, 2.5f); + + return Ret; +} + +vec4 CEditor::GetButtonColor(const void *pID, int Checked) +{ + if(Checked < 0) + return vec4(0,0,0,0.5f); + + if(Checked > 0) + { + if(UI()->HotItem() == pID) + return vec4(1,0,0,0.75f); + return vec4(1,0,0,0.5f); + } + + if(UI()->HotItem() == pID) + return vec4(1,1,1,0.75f); + return vec4(1,1,1,0.5f); +} + +int CEditor::DoButton_Editor_Common(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) +{ + if(UI()->MouseInside(pRect)) + { + if(Flags&BUTTON_CONTEXT) + ms_pUiGotContext = pID; + if(m_pTooltip) + m_pTooltip = pToolTip; + } + + if(UI()->HotItem() == pID && pToolTip) + m_pTooltip = (const char *)pToolTip; + + return UI()->DoButtonLogic(pID, pText, Checked, pRect); + + // Draw here + //return UI()->DoButton(id, text, checked, r, draw_func, 0); +} + + +int CEditor::DoButton_Editor(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) +{ + RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_ALL, 3.0f); + CUIRect NewRect = *pRect; + NewRect.y += NewRect.h/2.0f-7.0f; + float tw = min(TextRender()->TextWidth(0, 10.0f, pText, -1), NewRect.w); + CTextCursor Cursor; + TextRender()->SetCursor(&Cursor, NewRect.x + NewRect.w/2-tw/2, NewRect.y - 1.0f, 10.0f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); + Cursor.m_LineWidth = NewRect.w; + TextRender()->TextEx(&Cursor, pText, -1); + return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); +} + +int CEditor::DoButton_File(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) +{ + if(Checked) + RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_ALL, 3.0f); + + CUIRect t = *pRect; + t.VMargin(5.0f, &t); + UI()->DoLabel(&t, pText, 10, -1, -1); + return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); +} + +int CEditor::DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) +{ + CUIRect r = *pRect; + RenderTools()->DrawUIRect(&r, vec4(0.5f, 0.5f, 0.5f, 1.0f), CUI::CORNER_T, 3.0f); + + r = *pRect; + r.VMargin(5.0f, &r); + UI()->DoLabel(&r, pText, 10, -1, -1); + return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); +} + +int CEditor::DoButton_MenuItem(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) +{ + if(UI()->HotItem() == pID || Checked) + RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_ALL, 3.0f); + + CUIRect t = *pRect; + t.VMargin(5.0f, &t); + CTextCursor Cursor; + TextRender()->SetCursor(&Cursor, t.x, t.y - 1.0f, 10.0f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); + Cursor.m_LineWidth = t.w; + TextRender()->TextEx(&Cursor, pText, -1); + return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); +} + +int CEditor::DoButton_Tab(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) +{ + RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_T, 5.0f); + CUIRect NewRect = *pRect; + NewRect.y += NewRect.h/2.0f-7.0f; + UI()->DoLabel(&NewRect, pText, 10, 0, -1); + return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); +} + +int CEditor::DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners) +{ + RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), Corners, 3.0f); + CUIRect NewRect = *pRect; + NewRect.y += NewRect.h/2.0f-7.0f; + UI()->DoLabel(&NewRect, pText, 10, 0, -1); + return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); +} + +int CEditor::DoButton_ButtonInc(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) +{ + RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_R, 3.0f); + UI()->DoLabel(pRect, pText?pText:"+", 10, 0, -1); + return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); +} + +int CEditor::DoButton_ButtonDec(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip) +{ + RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), CUI::CORNER_L, 3.0f); + UI()->DoLabel(pRect, pText?pText:"-", 10, 0, -1); + return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); +} + +void CEditor::RenderBackground(CUIRect View, int Texture, float Size, float Brightness) +{ + Graphics()->TextureSet(Texture); + Graphics()->BlendNormal(); + Graphics()->QuadsBegin(); + Graphics()->SetColor(Brightness, Brightness, Brightness, 1.0f); + Graphics()->QuadsSetSubset(0,0, View.w/Size, View.h/Size); + IGraphics::CQuadItem QuadItem(View.x, View.y, View.w, View.h); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); +} + +int CEditor::UiDoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, int Current, int Min, int Max, int Step, float Scale, const char *pToolTip) +{ + // logic + static float s_Value; + int Ret = 0; + int Inside = UI()->MouseInside(pRect); + + if(UI()->ActiveItem() == pID) + { + if(!UI()->MouseButton(0)) + { + if(Inside) + Ret = 1; + m_LockMouse = false; + UI()->SetActiveItem(0); + } + else + { + if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) + s_Value += m_MouseDeltaX*0.05f; + else + s_Value += m_MouseDeltaX; + + if(absolute(s_Value) > Scale) + { + int Count = (int)(s_Value/Scale); + s_Value = fmod(s_Value, Scale); + Current += Step*Count; + if(Current < Min) + Current = Min; + if(Current > Max) + Current = Max; + } + } + if(pToolTip) + m_pTooltip = pToolTip; + } + else if(UI()->HotItem() == pID) + { + if(UI()->MouseButton(0)) + { + m_LockMouse = true; + s_Value = 0; + UI()->SetActiveItem(pID); + } + if(pToolTip) + m_pTooltip = pToolTip; + } + + if(Inside) + UI()->SetHotItem(pID); + + // render + char aBuf[128]; + str_format(aBuf, sizeof(aBuf),"%s %d", pLabel, Current); + RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, 0), CUI::CORNER_ALL, 5.0f); + pRect->y += pRect->h/2.0f-7.0f; + UI()->DoLabel(pRect, aBuf, 10, 0, -1); + + return Current; +} + +CLayerGroup *CEditor::GetSelectedGroup() +{ + if(m_SelectedGroup >= 0 && m_SelectedGroup < m_Map.m_lGroups.size()) + return m_Map.m_lGroups[m_SelectedGroup]; + return 0x0; +} + +CLayer *CEditor::GetSelectedLayer(int Index) +{ + CLayerGroup *pGroup = GetSelectedGroup(); + if(!pGroup) + return 0x0; + + if(m_SelectedLayer >= 0 && m_SelectedLayer < m_Map.m_lGroups[m_SelectedGroup]->m_lLayers.size()) + return pGroup->m_lLayers[m_SelectedLayer]; + return 0x0; +} + +CLayer *CEditor::GetSelectedLayerType(int Index, int Type) +{ + CLayer *p = GetSelectedLayer(Index); + if(p && p->m_Type == Type) + return p; + return 0x0; +} + +CQuad *CEditor::GetSelectedQuad() +{ + CLayerQuads *ql = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS); + if(!ql) + return 0; + if(m_SelectedQuad >= 0 && m_SelectedQuad < ql->m_lQuads.size()) + return &ql->m_lQuads[m_SelectedQuad]; + return 0; +} + +void CEditor::CallbackOpenMap(const char *pFileName, int StorageType, void *pUser) +{ + CEditor *pEditor = (CEditor*)pUser; + if(pEditor->Load(pFileName, StorageType)) + { + str_copy(pEditor->m_aFileName, pFileName, 512); + pEditor->m_ValidSaveFilename = StorageType == IStorage::TYPE_SAVE && pEditor->m_pFileDialogPath == pEditor->m_aFileDialogCurrentFolder; + pEditor->SortImages(); + pEditor->m_Dialog = DIALOG_NONE; + pEditor->m_Map.m_Modified = false; + } +} +void CEditor::CallbackAppendMap(const char *pFileName, int StorageType, void *pUser) +{ + CEditor *pEditor = (CEditor*)pUser; + if(pEditor->Append(pFileName, StorageType)) + pEditor->m_aFileName[0] = 0; + else + pEditor->SortImages(); + + pEditor->m_Dialog = DIALOG_NONE; +} +void CEditor::CallbackSaveMap(const char *pFileName, int StorageType, void *pUser) +{ + CEditor *pEditor = static_cast(pUser); + char aBuf[1024]; + const int Length = str_length(pFileName); + // add map extension + if(Length <= 4 || pFileName[Length-4] != '.' || str_comp_nocase(pFileName+Length-3, "map")) + { + str_format(aBuf, sizeof(aBuf), "%s.map", pFileName); + pFileName = aBuf; + } + + if(pEditor->Save(pFileName)) + { + str_copy(pEditor->m_aFileName, pFileName, sizeof(pEditor->m_aFileName)); + pEditor->m_ValidSaveFilename = StorageType == IStorage::TYPE_SAVE && pEditor->m_pFileDialogPath == pEditor->m_aFileDialogCurrentFolder; + pEditor->m_Map.m_Modified = false; + } + + pEditor->m_Dialog = DIALOG_NONE; +} + +void CEditor::DoToolbar(CUIRect ToolBar) +{ + CUIRect TB_Top, TB_Bottom; + CUIRect Button; + + ToolBar.HSplitTop(ToolBar.h/2.0f, &TB_Top, &TB_Bottom); + + TB_Top.HSplitBottom(2.5f, &TB_Top, 0); + TB_Bottom.HSplitTop(2.5f, 0, &TB_Bottom); + + // ctrl+o to open + if(Input()->KeyDown('o') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL))) + { + if(HasUnsavedData()) + { + m_PopupEventType = POPEVENT_LOAD; + m_PopupEventActivated = true; + } + else + InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_MAP, "Load map", "Load", "maps", "", CallbackOpenMap, this); + } + + // ctrl+s to save + if(Input()->KeyDown('s') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL))) + { + if(m_aFileName[0] && m_ValidSaveFilename) + { + str_copy(m_aFileSaveName, m_aFileName, sizeof(m_aFileSaveName)); + m_PopupEventType = POPEVENT_SAVE; + m_PopupEventActivated = true; + } + else + InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", "", CallbackSaveMap, this); + } + + // detail button + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_HqButton = 0; + if(DoButton_Editor(&s_HqButton, "HD", m_ShowDetail, &Button, 0, "[ctrl+h] Toggle High Detail") || + (Input()->KeyDown('h') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL)))) + { + m_ShowDetail = !m_ShowDetail; + } + + TB_Top.VSplitLeft(5.0f, 0, &TB_Top); + + // animation button + TB_Top.VSplitLeft(40.0f, &Button, &TB_Top); + static int s_AnimateButton = 0; + if(DoButton_Editor(&s_AnimateButton, "Anim", m_Animate, &Button, 0, "[ctrl+m] Toggle animation") || + (Input()->KeyDown('m') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL)))) + { + m_AnimateStart = time_get(); + m_Animate = !m_Animate; + } + + TB_Top.VSplitLeft(5.0f, 0, &TB_Top); + + // proof button + TB_Top.VSplitLeft(40.0f, &Button, &TB_Top); + static int s_ProofButton = 0; + if(DoButton_Editor(&s_ProofButton, "Proof", m_ProofBorders, &Button, 0, "[ctrl+p] Toggles proof borders. These borders represent what a player maximum can see.") || + (Input()->KeyDown('p') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL)))) + { + m_ProofBorders = !m_ProofBorders; + } + + TB_Top.VSplitLeft(5.0f, 0, &TB_Top); + + // tile info button + TB_Top.VSplitLeft(40.0f, &Button, &TB_Top); + static int s_TileInfoButton = 0; + if(DoButton_Editor(&s_TileInfoButton, "Info", m_ShowTileInfo, &Button, 0, "[ctrl+i] Show tile informations") || + (Input()->KeyDown('i') && (Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL)))) + { + m_ShowTileInfo = !m_ShowTileInfo; + } + + TB_Top.VSplitLeft(15.0f, 0, &TB_Top); + + // zoom group + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_ZoomOutButton = 0; + if(DoButton_Ex(&s_ZoomOutButton, "ZO", 0, &Button, 0, "[NumPad-] Zoom out", CUI::CORNER_L) || Input()->KeyDown(KEY_KP_MINUS)) + m_ZoomLevel += 50; + + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_ZoomNormalButton = 0; + if(DoButton_Ex(&s_ZoomNormalButton, "1:1", 0, &Button, 0, "[NumPad*] Zoom to normal and remove editor offset", 0) || Input()->KeyDown(KEY_KP_MULTIPLY)) + { + m_EditorOffsetX = 0; + m_EditorOffsetY = 0; + m_ZoomLevel = 100; + } + + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_ZoomInButton = 0; + if(DoButton_Ex(&s_ZoomInButton, "ZI", 0, &Button, 0, "[NumPad+] Zoom in", CUI::CORNER_R) || Input()->KeyDown(KEY_KP_PLUS)) + m_ZoomLevel -= 50; + + TB_Top.VSplitLeft(10.0f, 0, &TB_Top); + + // animation speed + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_AnimFasterButton = 0; + if(DoButton_Ex(&s_AnimFasterButton, "A+", 0, &Button, 0, "Increase animation speed", CUI::CORNER_L)) + m_AnimateSpeed += 0.5f; + + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_AnimNormalButton = 0; + if(DoButton_Ex(&s_AnimNormalButton, "1", 0, &Button, 0, "Normal animation speed", 0)) + m_AnimateSpeed = 1.0f; + + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_AnimSlowerButton = 0; + if(DoButton_Ex(&s_AnimSlowerButton, "A-", 0, &Button, 0, "Decrease animation speed", CUI::CORNER_R)) + { + if(m_AnimateSpeed > 0.5f) + m_AnimateSpeed -= 0.5f; + } + + if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP) && m_Dialog == DIALOG_NONE) + m_ZoomLevel -= 20; + + if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN) && m_Dialog == DIALOG_NONE) + m_ZoomLevel += 20; + + if(m_ZoomLevel < 50) + m_ZoomLevel = 50; + m_WorldZoom = m_ZoomLevel/100.0f; + + TB_Top.VSplitLeft(10.0f, &Button, &TB_Top); + + + // brush manipulation + { + int Enabled = m_Brush.IsEmpty()?-1:0; + + // flip buttons + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_FlipXButton = 0; + if(DoButton_Ex(&s_FlipXButton, "X/X", Enabled, &Button, 0, "[N] Flip brush horizontal", CUI::CORNER_L) || Input()->KeyDown('n')) + { + for(int i = 0; i < m_Brush.m_lLayers.size(); i++) + m_Brush.m_lLayers[i]->BrushFlipX(); + } + + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_FlipyButton = 0; + if(DoButton_Ex(&s_FlipyButton, "Y/Y", Enabled, &Button, 0, "[M] Flip brush vertical", CUI::CORNER_R) || Input()->KeyDown('m')) + { + for(int i = 0; i < m_Brush.m_lLayers.size(); i++) + m_Brush.m_lLayers[i]->BrushFlipY(); + } + + // rotate buttons + TB_Top.VSplitLeft(15.0f, &Button, &TB_Top); + + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_RotationAmount = 90; + bool TileLayer = false; + // check for tile layers in brush selection + for(int i = 0; i < m_Brush.m_lLayers.size(); i++) + if(m_Brush.m_lLayers[i]->m_Type == LAYERTYPE_TILES) + { + TileLayer = true; + s_RotationAmount = max(90, (s_RotationAmount/90)*90); + break; + } + s_RotationAmount = UiDoValueSelector(&s_RotationAmount, &Button, "", s_RotationAmount, TileLayer?90:1, 359, TileLayer?90:1, TileLayer?10.0f:2.0f, "Rotation of the brush in degrees. Use left mouse button to drag and change the value. Hold shift to be more precise."); + + TB_Top.VSplitLeft(5.0f, &Button, &TB_Top); + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_CcwButton = 0; + if(DoButton_Ex(&s_CcwButton, "CCW", Enabled, &Button, 0, "[R] Rotates the brush counter clockwise", CUI::CORNER_L) || Input()->KeyDown('r')) + { + for(int i = 0; i < m_Brush.m_lLayers.size(); i++) + m_Brush.m_lLayers[i]->BrushRotate(-s_RotationAmount/360.0f*pi*2); + } + + TB_Top.VSplitLeft(30.0f, &Button, &TB_Top); + static int s_CwButton = 0; + if(DoButton_Ex(&s_CwButton, "CW", Enabled, &Button, 0, "[T] Rotates the brush clockwise", CUI::CORNER_R) || Input()->KeyDown('t')) + { + for(int i = 0; i < m_Brush.m_lLayers.size(); i++) + m_Brush.m_lLayers[i]->BrushRotate(s_RotationAmount/360.0f*pi*2); + } + } + + // quad manipulation + { + // do add button + TB_Top.VSplitLeft(10.0f, &Button, &TB_Top); + TB_Top.VSplitLeft(60.0f, &Button, &TB_Top); + static int s_NewButton = 0; + + CLayerQuads *pQLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS); + //CLayerTiles *tlayer = (CLayerTiles *)get_selected_layer_type(0, LAYERTYPE_TILES); + if(DoButton_Editor(&s_NewButton, "Add Quad", pQLayer?0:-1, &Button, 0, "Adds a new quad")) + { + if(pQLayer) + { + float Mapping[4]; + CLayerGroup *g = GetSelectedGroup(); + g->Mapping(Mapping); + int AddX = f2fx(Mapping[0] + (Mapping[2]-Mapping[0])/2); + int AddY = f2fx(Mapping[1] + (Mapping[3]-Mapping[1])/2); + + CQuad *q = pQLayer->NewQuad(); + for(int i = 0; i < 5; i++) + { + q->m_aPoints[i].x += AddX; + q->m_aPoints[i].y += AddY; + } + } + } + } + + // tile manipulation + { + TB_Bottom.VSplitLeft(40.0f, &Button, &TB_Bottom); + static int s_BorderBut = 0; + CLayerTiles *pT = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES); + + if(DoButton_Editor(&s_BorderBut, "Border", pT?0:-1, &Button, 0, "Adds border tiles")) + { + if(pT) + DoMapBorder(); + } + } + + TB_Bottom.VSplitLeft(5.0f, 0, &TB_Bottom); + + // refocus button + TB_Bottom.VSplitLeft(50.0f, &Button, &TB_Bottom); + static int s_RefocusButton = 0; + if(DoButton_Editor(&s_RefocusButton, "Refocus", m_WorldOffsetX&&m_WorldOffsetY?0:-1, &Button, 0, "[HOME] Restore map focus") || Input()->KeyDown(KEY_HOME)) + { + m_WorldOffsetX = 0; + m_WorldOffsetY = 0; + } +} + +static void Rotate(CPoint *pCenter, CPoint *pPoint, float Rotation) +{ + int x = pPoint->x - pCenter->x; + int y = pPoint->y - pCenter->y; + pPoint->x = (int)(x * cosf(Rotation) - y * sinf(Rotation) + pCenter->x); + pPoint->y = (int)(x * sinf(Rotation) + y * cosf(Rotation) + pCenter->y); +} + +void CEditor::DoQuad(CQuad *q, int Index) +{ + enum + { + OP_NONE=0, + OP_MOVE_ALL, + OP_MOVE_PIVOT, + OP_ROTATE, + OP_CONTEXT_MENU, + }; + + // some basic values + void *pID = &q->m_aPoints[4]; // use pivot addr as id + static CPoint s_RotatePoints[4]; + static float s_LastWx; + static float s_LastWy; + static int s_Operation = OP_NONE; + static float s_RotateAngle = 0; + float wx = UI()->MouseWorldX(); + float wy = UI()->MouseWorldY(); + + // get pivot + float CenterX = fx2f(q->m_aPoints[4].x); + float CenterY = fx2f(q->m_aPoints[4].y); + + float dx = (CenterX - wx)/m_WorldZoom; + float dy = (CenterY - wy)/m_WorldZoom; + if(dx*dx+dy*dy < 50) + UI()->SetHotItem(pID); + + // draw selection background + if(m_SelectedQuad == Index) + { + Graphics()->SetColor(0,0,0,1); + IGraphics::CQuadItem QuadItem(CenterX, CenterY, 7.0f, 7.0f); + Graphics()->QuadsDraw(&QuadItem, 1); + } + + if(UI()->ActiveItem() == pID) + { + // check if we only should move pivot + if(s_Operation == OP_MOVE_PIVOT) + { + q->m_aPoints[4].x += f2fx(wx-s_LastWx); + q->m_aPoints[4].y += f2fx(wy-s_LastWy); + } + else if(s_Operation == OP_MOVE_ALL) + { + // move all points including pivot + for(int v = 0; v < 5; v++) + { + q->m_aPoints[v].x += f2fx(wx-s_LastWx); + q->m_aPoints[v].y += f2fx(wy-s_LastWy); + } + } + else if(s_Operation == OP_ROTATE) + { + for(int v = 0; v < 4; v++) + { + q->m_aPoints[v] = s_RotatePoints[v]; + Rotate(&q->m_aPoints[4], &q->m_aPoints[v], s_RotateAngle); + } + } + + s_RotateAngle += (m_MouseDeltaX) * 0.002f; + s_LastWx = wx; + s_LastWy = wy; + + if(s_Operation == OP_CONTEXT_MENU) + { + if(!UI()->MouseButton(1)) + { + static int s_QuadPopupID = 0; + UiInvokePopupMenu(&s_QuadPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 180, PopupQuad); + m_LockMouse = false; + s_Operation = OP_NONE; + UI()->SetActiveItem(0); + } + } + else + { + if(!UI()->MouseButton(0)) + { + m_LockMouse = false; + s_Operation = OP_NONE; + UI()->SetActiveItem(0); + } + } + + Graphics()->SetColor(1,1,1,1); + } + else if(UI()->HotItem() == pID) + { + ms_pUiGotContext = pID; + + Graphics()->SetColor(1,1,1,1); + m_pTooltip = "Left mouse button to move. Hold shift to move pivot. Hold ctrl to rotate."; + + if(UI()->MouseButton(0)) + { + if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) + s_Operation = OP_MOVE_PIVOT; + else if(Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL)) + { + m_LockMouse = true; + s_Operation = OP_ROTATE; + s_RotateAngle = 0; + s_RotatePoints[0] = q->m_aPoints[0]; + s_RotatePoints[1] = q->m_aPoints[1]; + s_RotatePoints[2] = q->m_aPoints[2]; + s_RotatePoints[3] = q->m_aPoints[3]; + } + else + s_Operation = OP_MOVE_ALL; + + UI()->SetActiveItem(pID); + m_SelectedQuad = Index; + s_LastWx = wx; + s_LastWy = wy; + } + + if(UI()->MouseButton(1)) + { + m_SelectedQuad = Index; + s_Operation = OP_CONTEXT_MENU; + UI()->SetActiveItem(pID); + } + } + else + Graphics()->SetColor(0,1,0,1); + + IGraphics::CQuadItem QuadItem(CenterX, CenterY, 5.0f*m_WorldZoom, 5.0f*m_WorldZoom); + Graphics()->QuadsDraw(&QuadItem, 1); +} + +void CEditor::DoQuadPoint(CQuad *pQuad, int QuadIndex, int V) +{ + void *pID = &pQuad->m_aPoints[V]; + + float wx = UI()->MouseWorldX(); + float wy = UI()->MouseWorldY(); + + float px = fx2f(pQuad->m_aPoints[V].x); + float py = fx2f(pQuad->m_aPoints[V].y); + + float dx = (px - wx)/m_WorldZoom; + float dy = (py - wy)/m_WorldZoom; + if(dx*dx+dy*dy < 50) + UI()->SetHotItem(pID); + + // draw selection background + if(m_SelectedQuad == QuadIndex && m_SelectedPoints&(1<SetColor(0,0,0,1); + IGraphics::CQuadItem QuadItem(px, py, 7.0f, 7.0f); + Graphics()->QuadsDraw(&QuadItem, 1); + } + + enum + { + OP_NONE=0, + OP_MOVEPOINT, + OP_MOVEUV, + OP_CONTEXT_MENU + }; + + static bool s_Moved; + static int s_Operation = OP_NONE; + + if(UI()->ActiveItem() == pID) + { + float dx = m_MouseDeltaWx; + float dy = m_MouseDeltaWy; + if(!s_Moved) + { + if(dx*dx+dy*dy > 0.5f) + s_Moved = true; + } + + if(s_Moved) + { + if(s_Operation == OP_MOVEPOINT) + { + for(int m = 0; m < 4; m++) + if(m_SelectedPoints&(1<m_aPoints[m].x += f2fx(dx); + pQuad->m_aPoints[m].y += f2fx(dy); + } + } + else if(s_Operation == OP_MOVEUV) + { + for(int m = 0; m < 4; m++) + if(m_SelectedPoints&(1<m_aTexcoords[m].x += f2fx(dx*0.001f); + pQuad->m_aTexcoords[(m+2)%4].x += f2fx(dx*0.001f); + + pQuad->m_aTexcoords[m].y += f2fx(dy*0.001f); + pQuad->m_aTexcoords[m^1].y += f2fx(dy*0.001f); + } + } + } + + if(s_Operation == OP_CONTEXT_MENU) + { + if(!UI()->MouseButton(1)) + { + static int s_PointPopupID = 0; + UiInvokePopupMenu(&s_PointPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 150, PopupPoint); + UI()->SetActiveItem(0); + } + } + else + { + if(!UI()->MouseButton(0)) + { + if(!s_Moved) + { + if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) + m_SelectedPoints ^= 1<SetActiveItem(0); + } + } + + Graphics()->SetColor(1,1,1,1); + } + else if(UI()->HotItem() == pID) + { + ms_pUiGotContext = pID; + + Graphics()->SetColor(1,1,1,1); + m_pTooltip = "Left mouse button to move. Hold shift to move the texture."; + + if(UI()->MouseButton(0)) + { + UI()->SetActiveItem(pID); + s_Moved = false; + if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) + { + s_Operation = OP_MOVEUV; + m_LockMouse = true; + } + else + s_Operation = OP_MOVEPOINT; + + if(!(m_SelectedPoints&(1<KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) + m_SelectedPoints |= 1<MouseButton(1)) + { + s_Operation = OP_CONTEXT_MENU; + m_SelectedQuad = QuadIndex; + UI()->SetActiveItem(pID); + if(!(m_SelectedPoints&(1<KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) + m_SelectedPoints |= 1<SetColor(1,0,0,1); + + IGraphics::CQuadItem QuadItem(px, py, 5.0f*m_WorldZoom, 5.0f*m_WorldZoom); + Graphics()->QuadsDraw(&QuadItem, 1); +} + +void CEditor::DoMapEditor(CUIRect View, CUIRect ToolBar, bool ShowPicker) +{ + // render all good stuff + if(!ShowPicker) + { + for(int g = 0; g < m_Map.m_lGroups.size(); g++) + { + if(m_Map.m_lGroups[g]->m_Visible) + m_Map.m_lGroups[g]->Render(); + //UI()->ClipEnable(&view); + } + + // render the game above everything else + if(m_Map.m_pGameGroup->m_Visible && m_Map.m_pGameLayer->m_Visible) + { + m_Map.m_pGameGroup->MapScreen(); + m_Map.m_pGameLayer->Render(); + } + + CLayerTiles *pT = static_cast(GetSelectedLayerType(0, LAYERTYPE_TILES)); + if(m_ShowTileInfo && pT && pT->m_Visible && m_ZoomLevel <= 300) + pT->ShowInfo(); + } + + static void *s_pEditorID = (void *)&s_pEditorID; + int Inside = UI()->MouseInside(&View); + + // fetch mouse position + float wx = UI()->MouseWorldX(); + float wy = UI()->MouseWorldY(); + float mx = UI()->MouseX(); + float my = UI()->MouseY(); + + static float s_StartWx = 0; + static float s_StartWy = 0; + static float s_StartMx = 0; + static float s_StartMy = 0; + + enum + { + OP_NONE=0, + OP_BRUSH_GRAB, + OP_BRUSH_DRAW, + OP_BRUSH_PAINT, + OP_PAN_WORLD, + OP_PAN_EDITOR, + }; + + // remap the screen so it can display the whole tileset + if(ShowPicker) + { + CUIRect Screen = *UI()->Screen(); + float Size = 32.0*16.0f; + float w = Size*(Screen.w/View.w); + float h = Size*(Screen.h/View.h); + float x = -(View.x/Screen.w)*w; + float y = -(View.y/Screen.h)*h; + wx = x+w*mx/Screen.w; + wy = y+h*my/Screen.h; + Graphics()->MapScreen(x, y, x+w, y+h); + CLayerTiles *t = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES); + if(t) + { + m_TilesetPicker.m_Image = t->m_Image; + m_TilesetPicker.m_TexID = t->m_TexID; + m_TilesetPicker.Render(); + if(m_ShowTileInfo) + m_TilesetPicker.ShowInfo(); + } + } + + static int s_Operation = OP_NONE; + + // draw layer borders + CLayer *pEditLayers[16]; + int NumEditLayers = 0; + NumEditLayers = 0; + + if(ShowPicker) + { + pEditLayers[0] = &m_TilesetPicker; + NumEditLayers++; + } + else + { + pEditLayers[0] = GetSelectedLayer(0); + if(pEditLayers[0]) + NumEditLayers++; + + CLayerGroup *g = GetSelectedGroup(); + if(g) + { + g->MapScreen(); + + for(int i = 0; i < NumEditLayers; i++) + { + if(pEditLayers[i]->m_Type != LAYERTYPE_TILES) + continue; + + float w, h; + pEditLayers[i]->GetSize(&w, &h); + + IGraphics::CLineItem Array[4] = { + IGraphics::CLineItem(0, 0, w, 0), + IGraphics::CLineItem(w, 0, w, h), + IGraphics::CLineItem(w, h, 0, h), + IGraphics::CLineItem(0, h, 0, 0)}; + Graphics()->TextureSet(-1); + Graphics()->LinesBegin(); + Graphics()->LinesDraw(Array, 4); + Graphics()->LinesEnd(); + } + } + } + + if(Inside) + { + UI()->SetHotItem(s_pEditorID); + + // do global operations like pan and zoom + if(UI()->ActiveItem() == 0 && (UI()->MouseButton(0) || UI()->MouseButton(2))) + { + s_StartWx = wx; + s_StartWy = wy; + s_StartMx = mx; + s_StartMy = my; + + if(Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL) || UI()->MouseButton(2)) + { + if(Input()->KeyPressed(KEY_LSHIFT)) + s_Operation = OP_PAN_EDITOR; + else + s_Operation = OP_PAN_WORLD; + UI()->SetActiveItem(s_pEditorID); + } + } + + // brush editing + if(UI()->HotItem() == s_pEditorID) + { + if(m_Brush.IsEmpty()) + m_pTooltip = "Use left mouse button to drag and create a brush."; + else + m_pTooltip = "Use left mouse button to paint with the brush. Right button clears the brush."; + + if(UI()->ActiveItem() == s_pEditorID) + { + CUIRect r; + r.x = s_StartWx; + r.y = s_StartWy; + r.w = wx-s_StartWx; + r.h = wy-s_StartWy; + if(r.w < 0) + { + r.x += r.w; + r.w = -r.w; + } + + if(r.h < 0) + { + r.y += r.h; + r.h = -r.h; + } + + if(s_Operation == OP_BRUSH_DRAW) + { + if(!m_Brush.IsEmpty()) + { + // draw with brush + for(int k = 0; k < NumEditLayers; k++) + { + if(pEditLayers[k]->m_Type == m_Brush.m_lLayers[0]->m_Type) + pEditLayers[k]->BrushDraw(m_Brush.m_lLayers[0], wx, wy); + } + } + } + else if(s_Operation == OP_BRUSH_GRAB) + { + if(!UI()->MouseButton(0)) + { + // grab brush + char aBuf[256]; + str_format(aBuf, sizeof(aBuf),"grabbing %f %f %f %f", r.x, r.y, r.w, r.h); + Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "editor", aBuf); + + // TODO: do all layers + int Grabs = 0; + for(int k = 0; k < NumEditLayers; k++) + Grabs += pEditLayers[k]->BrushGrab(&m_Brush, r); + if(Grabs == 0) + m_Brush.Clear(); + } + else + { + //editor.map.groups[selected_group]->mapscreen(); + for(int k = 0; k < NumEditLayers; k++) + pEditLayers[k]->BrushSelecting(r); + Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); + } + } + else if(s_Operation == OP_BRUSH_PAINT) + { + if(!UI()->MouseButton(0)) + { + for(int k = 0; k < NumEditLayers; k++) + pEditLayers[k]->FillSelection(m_Brush.IsEmpty(), m_Brush.m_lLayers[0], r); + } + else + { + //editor.map.groups[selected_group]->mapscreen(); + for(int k = 0; k < NumEditLayers; k++) + pEditLayers[k]->BrushSelecting(r); + Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); + } + } + } + else + { + if(UI()->MouseButton(1)) + m_Brush.Clear(); + + if(UI()->MouseButton(0) && s_Operation == OP_NONE) + { + UI()->SetActiveItem(s_pEditorID); + + if(m_Brush.IsEmpty()) + s_Operation = OP_BRUSH_GRAB; + else + { + s_Operation = OP_BRUSH_DRAW; + for(int k = 0; k < NumEditLayers; k++) + { + if(pEditLayers[k]->m_Type == m_Brush.m_lLayers[0]->m_Type) + pEditLayers[k]->BrushPlace(m_Brush.m_lLayers[0], wx, wy); + } + + } + + CLayerTiles *pLayer = (CLayerTiles*)GetSelectedLayerType(0, LAYERTYPE_TILES); + if((Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) && pLayer) + s_Operation = OP_BRUSH_PAINT; + } + + if(!m_Brush.IsEmpty()) + { + m_Brush.m_OffsetX = -(int)wx; + m_Brush.m_OffsetY = -(int)wy; + for(int i = 0; i < m_Brush.m_lLayers.size(); i++) + { + if(m_Brush.m_lLayers[i]->m_Type == LAYERTYPE_TILES) + { + m_Brush.m_OffsetX = -(int)(wx/32.0f)*32; + m_Brush.m_OffsetY = -(int)(wy/32.0f)*32; + break; + } + } + + CLayerGroup *g = GetSelectedGroup(); + if(g) + { + m_Brush.m_OffsetX += g->m_OffsetX; + m_Brush.m_OffsetY += g->m_OffsetY; + m_Brush.m_ParallaxX = g->m_ParallaxX; + m_Brush.m_ParallaxY = g->m_ParallaxY; + m_Brush.Render(); + float w, h; + m_Brush.GetSize(&w, &h); + + IGraphics::CLineItem Array[4] = { + IGraphics::CLineItem(0, 0, w, 0), + IGraphics::CLineItem(w, 0, w, h), + IGraphics::CLineItem(w, h, 0, h), + IGraphics::CLineItem(0, h, 0, 0)}; + Graphics()->TextureSet(-1); + Graphics()->LinesBegin(); + Graphics()->LinesDraw(Array, 4); + Graphics()->LinesEnd(); + } + } + } + } + + // quad editing + { + if(!ShowPicker && m_Brush.IsEmpty()) + { + // fetch layers + CLayerGroup *g = GetSelectedGroup(); + if(g) + g->MapScreen(); + + for(int k = 0; k < NumEditLayers; k++) + { + if(pEditLayers[k]->m_Type == LAYERTYPE_QUADS) + { + CLayerQuads *pLayer = (CLayerQuads *)pEditLayers[k]; + + Graphics()->TextureSet(-1); + Graphics()->QuadsBegin(); + for(int i = 0; i < pLayer->m_lQuads.size(); i++) + { + for(int v = 0; v < 4; v++) + DoQuadPoint(&pLayer->m_lQuads[i], i, v); + + DoQuad(&pLayer->m_lQuads[i], i); + } + Graphics()->QuadsEnd(); + } + } + + Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); + } + + // do panning + if(UI()->ActiveItem() == s_pEditorID) + { + if(s_Operation == OP_PAN_WORLD) + { + m_WorldOffsetX -= m_MouseDeltaX*m_WorldZoom; + m_WorldOffsetY -= m_MouseDeltaY*m_WorldZoom; + } + else if(s_Operation == OP_PAN_EDITOR) + { + m_EditorOffsetX -= m_MouseDeltaX*m_WorldZoom; + m_EditorOffsetY -= m_MouseDeltaY*m_WorldZoom; + } + + // release mouse + if(!UI()->MouseButton(0)) + { + s_Operation = OP_NONE; + UI()->SetActiveItem(0); + } + } + } + } + else if(UI()->ActiveItem() == s_pEditorID) + { + // release mouse + if(!UI()->MouseButton(0)) + { + s_Operation = OP_NONE; + UI()->SetActiveItem(0); + } + } + + if(GetSelectedGroup() && GetSelectedGroup()->m_UseClipping) + { + CLayerGroup *g = m_Map.m_pGameGroup; + g->MapScreen(); + + Graphics()->TextureSet(-1); + Graphics()->LinesBegin(); + + CUIRect r; + r.x = GetSelectedGroup()->m_ClipX; + r.y = GetSelectedGroup()->m_ClipY; + r.w = GetSelectedGroup()->m_ClipW; + r.h = GetSelectedGroup()->m_ClipH; + + IGraphics::CLineItem Array[4] = { + IGraphics::CLineItem(r.x, r.y, r.x+r.w, r.y), + IGraphics::CLineItem(r.x+r.w, r.y, r.x+r.w, r.y+r.h), + IGraphics::CLineItem(r.x+r.w, r.y+r.h, r.x, r.y+r.h), + IGraphics::CLineItem(r.x, r.y+r.h, r.x, r.y)}; + Graphics()->SetColor(1,0,0,1); + Graphics()->LinesDraw(Array, 4); + + Graphics()->LinesEnd(); + } + + // render screen sizes + if(m_ProofBorders) + { + CLayerGroup *g = m_Map.m_pGameGroup; + g->MapScreen(); + + Graphics()->TextureSet(-1); + Graphics()->LinesBegin(); + + float aLastPoints[4]; + float Start = 1.0f; //9.0f/16.0f; + float End = 16.0f/9.0f; + const int NumSteps = 20; + for(int i = 0; i <= NumSteps; i++) + { + float aPoints[4]; + float Aspect = Start + (End-Start)*(i/(float)NumSteps); + + RenderTools()->MapscreenToWorld( + m_WorldOffsetX, m_WorldOffsetY, + 1.0f, 1.0f, 0.0f, 0.0f, Aspect, 1.0f, aPoints); + + if(i == 0) + { + IGraphics::CLineItem Array[2] = { + IGraphics::CLineItem(aPoints[0], aPoints[1], aPoints[2], aPoints[1]), + IGraphics::CLineItem(aPoints[0], aPoints[3], aPoints[2], aPoints[3])}; + Graphics()->LinesDraw(Array, 2); + } + + if(i != 0) + { + IGraphics::CLineItem Array[4] = { + IGraphics::CLineItem(aPoints[0], aPoints[1], aLastPoints[0], aLastPoints[1]), + IGraphics::CLineItem(aPoints[2], aPoints[1], aLastPoints[2], aLastPoints[1]), + IGraphics::CLineItem(aPoints[0], aPoints[3], aLastPoints[0], aLastPoints[3]), + IGraphics::CLineItem(aPoints[2], aPoints[3], aLastPoints[2], aLastPoints[3])}; + Graphics()->LinesDraw(Array, 4); + } + + if(i == NumSteps) + { + IGraphics::CLineItem Array[2] = { + IGraphics::CLineItem(aPoints[0], aPoints[1], aPoints[0], aPoints[3]), + IGraphics::CLineItem(aPoints[2], aPoints[1], aPoints[2], aPoints[3])}; + Graphics()->LinesDraw(Array, 2); + } + + mem_copy(aLastPoints, aPoints, sizeof(aPoints)); + } + + if(1) + { + Graphics()->SetColor(1,0,0,1); + for(int i = 0; i < 2; i++) + { + float aPoints[4]; + float aAspects[] = {4.0f/3.0f, 16.0f/10.0f, 5.0f/4.0f, 16.0f/9.0f}; + float Aspect = aAspects[i]; + + RenderTools()->MapscreenToWorld( + m_WorldOffsetX, m_WorldOffsetY, + 1.0f, 1.0f, 0.0f, 0.0f, Aspect, 1.0f, aPoints); + + CUIRect r; + r.x = aPoints[0]; + r.y = aPoints[1]; + r.w = aPoints[2]-aPoints[0]; + r.h = aPoints[3]-aPoints[1]; + + IGraphics::CLineItem Array[4] = { + IGraphics::CLineItem(r.x, r.y, r.x+r.w, r.y), + IGraphics::CLineItem(r.x+r.w, r.y, r.x+r.w, r.y+r.h), + IGraphics::CLineItem(r.x+r.w, r.y+r.h, r.x, r.y+r.h), + IGraphics::CLineItem(r.x, r.y+r.h, r.x, r.y)}; + Graphics()->LinesDraw(Array, 4); + Graphics()->SetColor(0,1,0,1); + } + } + + Graphics()->LinesEnd(); + } + + Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); + //UI()->ClipDisable(); +} + + +int CEditor::DoProperties(CUIRect *pToolBox, CProperty *pProps, int *pIDs, int *pNewVal) +{ + int Change = -1; + + 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, -1, -1); + + 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_format(aBuf, sizeof(aBuf),"%d", pProps[i].m_Value); + RenderTools()->DrawUIRect(&Shifter, vec4(1,1,1,0.5f), 0, 0.0f); + UI()->DoLabel(&Shifter, aBuf, 10.0f, 0, -1); + + if(DoButton_ButtonDec(&pIDs[i], 0, 0, &Dec, 0, "Decrease")) + { + *pNewVal = pProps[i].m_Value-1; + Change = i; + } + if(DoButton_ButtonInc(((char *)&pIDs[i])+1, 0, 0, &Inc, 0, "Increase")) + { + *pNewVal = pProps[i].m_Value+1; + Change = i; + } + } + 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; + } + if(DoButton_ButtonInc(((char *)&pIDs[i])+1, "Yes", pProps[i].m_Value, &Yes, 0, "")) + { + *pNewVal = 1; + Change = i; + } + } + else if(pProps[i].m_Type == PROPTYPE_INT_SCROLL) + { + int NewValue = 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."); + if(NewValue != pProps[i].m_Value) + { + *pNewVal = NewValue; + Change = i; + } + } + else if(pProps[i].m_Type == PROPTYPE_COLOR) + { + static const char *s_paTexts[4] = {"R", "G", "B", "A"}; + static int s_aShift[] = {24, 16, 8, 0}; + int NewColor = 0; + + for(int c = 0; c < 4; c++) + { + int v = (pProps[i].m_Value >> s_aShift[c])&0xff; + NewColor |= UiDoValueSelector(((char *)&pIDs[i])+c, &Shifter, s_paTexts[c], v, 0, 255, 1, 1.0f, "Use left mouse button to drag and change the color value. Hold shift to be more precise.")<HSplitTop(13.0f, &Slot, pToolBox); + Slot.VSplitMid(0, &Shifter); + Shifter.HMargin(1.0f, &Shifter); + } + } + + if(NewColor != pProps[i].m_Value) + { + *pNewVal = NewColor; + Change = i; + } + } + else if(pProps[i].m_Type == PROPTYPE_IMAGE) + { + char aBuf[64]; + if(pProps[i].m_Value < 0) + str_copy(aBuf, "None", sizeof(aBuf)); + else + str_format(aBuf, sizeof(aBuf),"%s", m_Map.m_lImages[pProps[i].m_Value]->m_aName); + + if(DoButton_Editor(&pIDs[i], aBuf, 0, &Shifter, 0, 0)) + PopupSelectImageInvoke(pProps[i].m_Value, UI()->MouseX(), UI()->MouseY()); + + int r = PopupSelectImageResult(); + if(r >= -1) + { + *pNewVal = r; + Change = i; + } + } + else if(pProps[i].m_Type == PROPTYPE_SHIFT) + { + CUIRect Left, Right, Up, Down; + Shifter.VSplitMid(&Left, &Up); + Left.VSplitRight(1.0f, &Left, 0); + Up.VSplitLeft(1.0f, 0, &Up); + Left.VSplitLeft(10.0f, &Left, &Shifter); + Shifter.VSplitRight(10.0f, &Shifter, &Right); + RenderTools()->DrawUIRect(&Shifter, vec4(1,1,1,0.5f), 0, 0.0f); + UI()->DoLabel(&Shifter, "X", 10.0f, 0, -1); + Up.VSplitLeft(10.0f, &Up, &Shifter); + Shifter.VSplitRight(10.0f, &Shifter, &Down); + RenderTools()->DrawUIRect(&Shifter, vec4(1,1,1,0.5f), 0, 0.0f); + UI()->DoLabel(&Shifter, "Y", 10.0f, 0, -1); + if(DoButton_ButtonDec(&pIDs[i], "-", 0, &Left, 0, "Left")) + { + *pNewVal = 1; + Change = i; + } + if(DoButton_ButtonInc(((char *)&pIDs[i])+3, "+", 0, &Right, 0, "Right")) + { + *pNewVal = 2; + Change = i; + } + if(DoButton_ButtonDec(((char *)&pIDs[i])+1, "-", 0, &Up, 0, "Up")) + { + *pNewVal = 4; + Change = i; + } + if(DoButton_ButtonInc(((char *)&pIDs[i])+2, "+", 0, &Down, 0, "Down")) + { + *pNewVal = 8; + Change = i; + } + } + } + + return Change; +} + +void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) +{ + CUIRect LayersBox = ToolBox; + + if(!m_GuiActive) + return; + + CUIRect Slot, Button; + char aBuf[64]; + + int ValidGroup = 0; + int ValidLayer = 0; + if(m_SelectedGroup >= 0 && m_SelectedGroup < m_Map.m_lGroups.size()) + ValidGroup = 1; + + if(ValidGroup && m_SelectedLayer >= 0 && m_SelectedLayer < m_Map.m_lGroups[m_SelectedGroup]->m_lLayers.size()) + ValidLayer = 1; + + float LayersHeight = 12.0f; // Height of AddGroup button + static int s_ScrollBar = 0; + static float s_ScrollValue = 0; + + for(int g = 0; g < m_Map.m_lGroups.size(); g++) + // Each group is 19.0f + // Each layer is 14.0f + LayersHeight += 19.0f + m_Map.m_lGroups[g]->m_lLayers.size() * 14.0f; + + float ScrollDifference = LayersHeight - LayersBox.h; + + if(LayersHeight > LayersBox.h) // Do we even need a scrollbar? + { + CUIRect Scroll; + LayersBox.VSplitRight(15.0f, &LayersBox, &Scroll); + LayersBox.VSplitRight(3.0f, &LayersBox, 0); // extra spacing + Scroll.HMargin(5.0f, &Scroll); + s_ScrollValue = UiDoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue); + } + + float LayerStartAt = ScrollDifference * s_ScrollValue; + if(LayerStartAt < 0.0f) + LayerStartAt = 0.0f; + + float LayerStopAt = LayersHeight - ScrollDifference * (1 - s_ScrollValue); + float LayerCur = 0; + + // render layers + { + for(int g = 0; g < m_Map.m_lGroups.size(); g++) + { + if(LayerCur > LayerStopAt) + break; + else if(LayerCur + m_Map.m_lGroups[g]->m_lLayers.size() * 14.0f + 19.0f < LayerStartAt) + { + LayerCur += m_Map.m_lGroups[g]->m_lLayers.size() * 14.0f + 19.0f; + continue; + } + + CUIRect VisibleToggle, SaveCheck; + if(LayerCur >= LayerStartAt) + { + LayersBox.HSplitTop(12.0f, &Slot, &LayersBox); + Slot.VSplitLeft(12, &VisibleToggle, &Slot); + if(DoButton_Ex(&m_Map.m_lGroups[g]->m_Visible, m_Map.m_lGroups[g]->m_Visible?"V":"H", 0, &VisibleToggle, 0, "Toggle group visibility", CUI::CORNER_L)) + m_Map.m_lGroups[g]->m_Visible = !m_Map.m_lGroups[g]->m_Visible; + + Slot.VSplitRight(12.0f, &Slot, &SaveCheck); + if(DoButton_Ex(&m_Map.m_lGroups[g]->m_SaveToMap, "S", m_Map.m_lGroups[g]->m_SaveToMap, &SaveCheck, 0, "Enable/disable group for saving", CUI::CORNER_R)) + if(!m_Map.m_lGroups[g]->m_GameGroup) + m_Map.m_lGroups[g]->m_SaveToMap = !m_Map.m_lGroups[g]->m_SaveToMap; + + str_format(aBuf, sizeof(aBuf),"#%d %s", g, m_Map.m_lGroups[g]->m_pName); + if(int Result = DoButton_Ex(&m_Map.m_lGroups[g], aBuf, g==m_SelectedGroup, &Slot, + BUTTON_CONTEXT, "Select group. Right click for properties.", 0)) + { + m_SelectedGroup = g; + m_SelectedLayer = 0; + + static int s_GroupPopupId = 0; + if(Result == 2) + UiInvokePopupMenu(&s_GroupPopupId, 0, UI()->MouseX(), UI()->MouseY(), 120, 200, PopupGroup); + } + LayersBox.HSplitTop(2.0f, &Slot, &LayersBox); + } + LayerCur += 14.0f; + + for(int i = 0; i < m_Map.m_lGroups[g]->m_lLayers.size(); i++) + { + if(LayerCur > LayerStopAt) + break; + else if(LayerCur < LayerStartAt) + { + LayerCur += 14.0f; + continue; + } + + //visible + LayersBox.HSplitTop(12.0f, &Slot, &LayersBox); + Slot.VSplitLeft(12.0f, 0, &Button); + Button.VSplitLeft(15, &VisibleToggle, &Button); + + if(DoButton_Ex(&m_Map.m_lGroups[g]->m_lLayers[i]->m_Visible, m_Map.m_lGroups[g]->m_lLayers[i]->m_Visible?"V":"H", 0, &VisibleToggle, 0, "Toggle layer visibility", CUI::CORNER_L)) + m_Map.m_lGroups[g]->m_lLayers[i]->m_Visible = !m_Map.m_lGroups[g]->m_lLayers[i]->m_Visible; + + Button.VSplitRight(12.0f, &Button, &SaveCheck); + if(DoButton_Ex(&m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap, "S", m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap, &SaveCheck, 0, "Enable/disable layer for saving", CUI::CORNER_R)) + if(m_Map.m_lGroups[g]->m_lLayers[i] != m_Map.m_pGameLayer) + m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap = !m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap; + + str_format(aBuf, sizeof(aBuf),"#%d %s ", i, m_Map.m_lGroups[g]->m_lLayers[i]->m_pTypeName); + if(int Result = DoButton_Ex(m_Map.m_lGroups[g]->m_lLayers[i], aBuf, g==m_SelectedGroup&&i==m_SelectedLayer, &Button, + BUTTON_CONTEXT, "Select layer. Right click for properties.", 0)) + { + m_SelectedLayer = i; + m_SelectedGroup = g; + static int s_LayerPopupID = 0; + if(Result == 2) + UiInvokePopupMenu(&s_LayerPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 220, PopupLayer); + } + + LayerCur += 14.0f; + LayersBox.HSplitTop(2.0f, &Slot, &LayersBox); + } + if(LayerCur > LayerStartAt && LayerCur < LayerStopAt) + LayersBox.HSplitTop(5.0f, &Slot, &LayersBox); + LayerCur += 5.0f; + } + } + + if(LayerCur <= LayerStopAt) + { + LayersBox.HSplitTop(12.0f, &Slot, &LayersBox); + + static int s_NewGroupButton = 0; + if(DoButton_Editor(&s_NewGroupButton, "Add group", 0, &Slot, 0, "Adds a new group")) + { + m_Map.NewGroup(); + m_SelectedGroup = m_Map.m_lGroups.size()-1; + } + } +} + +void CEditor::ReplaceImage(const char *pFileName, int StorageType, void *pUser) +{ + CEditor *pEditor = (CEditor *)pUser; + CEditorImage ImgInfo(pEditor); + if(!pEditor->Graphics()->LoadPNG(&ImgInfo, pFileName, StorageType)) + return; + + CEditorImage *pImg = pEditor->m_Map.m_lImages[pEditor->m_SelectedImage]; + int External = pImg->m_External; + pEditor->Graphics()->UnloadTexture(pImg->m_TexID); + *pImg = ImgInfo; + pImg->m_External = External; + pEditor->ExtractName(pFileName, pImg->m_aName, sizeof(pImg->m_aName)); + pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0); + pEditor->SortImages(); + for(int i = 0; i < pEditor->m_Map.m_lImages.size(); ++i) + { + if(!str_comp(pEditor->m_Map.m_lImages[i]->m_aName, pImg->m_aName)) + pEditor->m_SelectedImage = i; + } + pEditor->m_Dialog = DIALOG_NONE; +} + +void CEditor::AddImage(const char *pFileName, int StorageType, void *pUser) +{ + CEditor *pEditor = (CEditor *)pUser; + CEditorImage ImgInfo(pEditor); + if(!pEditor->Graphics()->LoadPNG(&ImgInfo, pFileName, StorageType)) + return; + + // check if we have that image already + char aBuf[128]; + ExtractName(pFileName, aBuf, sizeof(aBuf)); + for(int i = 0; i < pEditor->m_Map.m_lImages.size(); ++i) + { + if(!str_comp(pEditor->m_Map.m_lImages[i]->m_aName, aBuf)) + return; + } + + CEditorImage *pImg = new CEditorImage(pEditor); + *pImg = ImgInfo; + pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0); + pImg->m_External = 1; // external by default + str_copy(pImg->m_aName, aBuf, sizeof(pImg->m_aName)); + pEditor->m_Map.m_lImages.add(pImg); + pEditor->SortImages(); + if(pEditor->m_SelectedImage > -1 && pEditor->m_SelectedImage < pEditor->m_Map.m_lImages.size()) + { + for(int i = 0; i <= pEditor->m_SelectedImage; ++i) + if(!str_comp(pEditor->m_Map.m_lImages[i]->m_aName, aBuf)) + { + pEditor->m_SelectedImage++; + break; + } + } + pEditor->m_Dialog = DIALOG_NONE; +} + + +static int gs_ModifyIndexDeletedIndex; +static void ModifyIndexDeleted(int *pIndex) +{ + if(*pIndex == gs_ModifyIndexDeletedIndex) + *pIndex = -1; + else if(*pIndex > gs_ModifyIndexDeletedIndex) + *pIndex = *pIndex - 1; +} + +int CEditor::PopupImage(CEditor *pEditor, CUIRect View) +{ + static int s_ReplaceButton = 0; + static int s_RemoveButton = 0; + + CUIRect Slot; + View.HSplitTop(2.0f, &Slot, &View); + View.HSplitTop(12.0f, &Slot, &View); + CEditorImage *pImg = pEditor->m_Map.m_lImages[pEditor->m_SelectedImage]; + + static int s_ExternalButton = 0; + if(pImg->m_External) + { + if(pEditor->DoButton_MenuItem(&s_ExternalButton, "Embed", 0, &Slot, 0, "Embeds the image into the map file.")) + { + pImg->m_External = 0; + return 1; + } + } + else + { + if(pEditor->DoButton_MenuItem(&s_ExternalButton, "Make external", 0, &Slot, 0, "Removes the image from the map file.")) + { + pImg->m_External = 1; + return 1; + } + } + + View.HSplitTop(10.0f, &Slot, &View); + View.HSplitTop(12.0f, &Slot, &View); + if(pEditor->DoButton_MenuItem(&s_ReplaceButton, "Replace", 0, &Slot, 0, "Replaces the image with a new one")) + { + pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Replace Image", "Replace", "mapres", "", ReplaceImage, pEditor); + return 1; + } + + View.HSplitTop(10.0f, &Slot, &View); + View.HSplitTop(12.0f, &Slot, &View); + if(pEditor->DoButton_MenuItem(&s_RemoveButton, "Remove", 0, &Slot, 0, "Removes the image from the map")) + { + delete pImg; + pEditor->m_Map.m_lImages.remove_index(pEditor->m_SelectedImage); + gs_ModifyIndexDeletedIndex = pEditor->m_SelectedImage; + pEditor->m_Map.ModifyImageIndex(ModifyIndexDeleted); + return 1; + } + + return 0; +} + +static int CompareImageName(const void *pObject1, const void *pObject2) +{ + CEditorImage *pImage1 = *(CEditorImage**)pObject1; + CEditorImage *pImage2 = *(CEditorImage**)pObject2; + + return str_comp(pImage1->m_aName, pImage2->m_aName); +} + +static int *gs_pSortedIndex = 0; +static void ModifySortedIndex(int *pIndex) +{ + if(*pIndex > -1) + *pIndex = gs_pSortedIndex[*pIndex]; +} + +void CEditor::SortImages() +{ + bool Sorted = true; + for(int i = 1; i < m_Map.m_lImages.size(); i++) + if( str_comp(m_Map.m_lImages[i]->m_aName, m_Map.m_lImages[i-1]->m_aName) < 0 ) + { + Sorted = false; + break; + } + + if(!Sorted) + { + array lTemp = array(m_Map.m_lImages); + gs_pSortedIndex = new int[lTemp.size()]; + + qsort(m_Map.m_lImages.base_ptr(), m_Map.m_lImages.size(), sizeof(CEditorImage*), CompareImageName); + + for(int OldIndex = 0; OldIndex < lTemp.size(); OldIndex++) + for(int NewIndex = 0; NewIndex < m_Map.m_lImages.size(); NewIndex++) + if(lTemp[OldIndex] == m_Map.m_lImages[NewIndex]) + gs_pSortedIndex[OldIndex] = NewIndex; + + m_Map.ModifyImageIndex(ModifySortedIndex); + + delete [] gs_pSortedIndex; + gs_pSortedIndex = 0; + } +} + + +void CEditor::RenderImages(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) +{ + static int s_ScrollBar = 0; + static float s_ScrollValue = 0; + float ImagesHeight = 30.0f + 14.0f * m_Map.m_lImages.size() + 27.0f; + float ScrollDifference = ImagesHeight - ToolBox.h; + + if(ImagesHeight > ToolBox.h) // Do we even need a scrollbar? + { + CUIRect Scroll; + ToolBox.VSplitRight(15.0f, &ToolBox, &Scroll); + ToolBox.VSplitRight(3.0f, &ToolBox, 0); // extra spacing + Scroll.HMargin(5.0f, &Scroll); + s_ScrollValue = UiDoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue); + } + + float ImageStartAt = ScrollDifference * s_ScrollValue; + if(ImageStartAt < 0.0f) + ImageStartAt = 0.0f; + + float ImageStopAt = ImagesHeight - ScrollDifference * (1 - s_ScrollValue); + float ImageCur = 0.0f; + + for(int e = 0; e < 2; e++) // two passes, first embedded, then external + { + CUIRect Slot; + + if(ImageCur > ImageStopAt) + break; + else if(ImageCur >= ImageStartAt) + { + + ToolBox.HSplitTop(15.0f, &Slot, &ToolBox); + if(e == 0) + UI()->DoLabel(&Slot, "Embedded", 12.0f, 0); + else + UI()->DoLabel(&Slot, "External", 12.0f, 0); + } + ImageCur += 15.0f; + + for(int i = 0; i < m_Map.m_lImages.size(); i++) + { + if((e && !m_Map.m_lImages[i]->m_External) || + (!e && m_Map.m_lImages[i]->m_External)) + { + continue; + } + + if(ImageCur > ImageStopAt) + break; + else if(ImageCur < ImageStartAt) + { + ImageCur += 14.0f; + continue; + } + ImageCur += 14.0f; + + char aBuf[128]; + str_copy(aBuf, m_Map.m_lImages[i]->m_aName, sizeof(aBuf)); + ToolBox.HSplitTop(12.0f, &Slot, &ToolBox); + + if(int Result = DoButton_Editor(&m_Map.m_lImages[i], aBuf, m_SelectedImage == i, &Slot, + BUTTON_CONTEXT, "Select image")) + { + m_SelectedImage = i; + + static int s_PopupImageID = 0; + if(Result == 2) + UiInvokePopupMenu(&s_PopupImageID, 0, UI()->MouseX(), UI()->MouseY(), 120, 80, PopupImage); + } + + ToolBox.HSplitTop(2.0f, 0, &ToolBox); + + // render image + if(m_SelectedImage == i) + { + CUIRect r; + View.Margin(10.0f, &r); + if(r.h < r.w) + r.w = r.h; + else + r.h = r.w; + Graphics()->TextureSet(m_Map.m_lImages[i]->m_TexID); + Graphics()->BlendNormal(); + Graphics()->QuadsBegin(); + IGraphics::CQuadItem QuadItem(r.x, r.y, r.w, r.h); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); + + } + } + } + + if(ImageCur + 27.0f > ImageStopAt) + return; + + CUIRect Slot; + ToolBox.HSplitTop(5.0f, &Slot, &ToolBox); + + // new image + static int s_NewImageButton = 0; + ToolBox.HSplitTop(10.0f, &Slot, &ToolBox); + ToolBox.HSplitTop(12.0f, &Slot, &ToolBox); + if(DoButton_Editor(&s_NewImageButton, "Add", 0, &Slot, 0, "Load a new image to use in the map")) + InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Add Image", "Add", "mapres", "", AddImage, this); +} + + +static int EditorListdirCallback(const char *pName, int IsDir, int StorageType, void *pUser) +{ + CEditor *pEditor = (CEditor*)pUser; + int Length = str_length(pName); + if((pName[0] == '.' && (pName[1] == 0 || + (pName[1] == '.' && pName[2] == 0 && (!str_comp(pEditor->m_pFileDialogPath, "maps") || !str_comp(pEditor->m_pFileDialogPath, "mapres"))))) || + (!IsDir && ((pEditor->m_FileDialogFileType == CEditor::FILETYPE_MAP && (Length < 4 || str_comp(pName+Length-4, ".map"))) || + (pEditor->m_FileDialogFileType == CEditor::FILETYPE_IMG && (Length < 4 || str_comp(pName+Length-4, ".png")))))) + return 0; + + CEditor::CFilelistItem Item; + str_copy(Item.m_aFilename, pName, sizeof(Item.m_aFilename)); + if(IsDir) + str_format(Item.m_aName, sizeof(Item.m_aName), "%s/", pName); + else + str_copy(Item.m_aName, pName, min(static_cast(sizeof(Item.m_aName)), Length-3)); + Item.m_IsDir = IsDir != 0; + Item.m_IsLink = false; + Item.m_StorageType = StorageType; + pEditor->m_FileList.add(Item); + + return 0; +} + +void CEditor::AddFileDialogEntry(int Index, CUIRect *pView) +{ + m_FilesCur++; + if(m_FilesCur-1 < m_FilesStartAt || m_FilesCur >= m_FilesStopAt) + return; + + CUIRect Button, FileIcon; + pView->HSplitTop(15.0f, &Button, pView); + pView->HSplitTop(2.0f, 0, pView); + Button.VSplitLeft(Button.h, &FileIcon, &Button); + Button.VSplitLeft(5.0f, 0, &Button); + + Graphics()->TextureSet(g_pData->m_aImages[IMAGE_FILEICONS].m_Id); + Graphics()->QuadsBegin(); + RenderTools()->SelectSprite(m_FileList[Index].m_IsDir?SPRITE_FILE_FOLDER:SPRITE_FILE_MAP2); + IGraphics::CQuadItem QuadItem(FileIcon.x, FileIcon.y, FileIcon.w, FileIcon.h); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); + + if(DoButton_File((void*)(10+(int)Button.y), m_FileList[Index].m_aName, m_FilesSelectedIndex == Index, &Button, 0, 0)) + { + if(!m_FileList[Index].m_IsDir) + str_copy(m_aFileDialogFileName, m_FileList[Index].m_aFilename, sizeof(m_aFileDialogFileName)); + else + m_aFileDialogFileName[0] = 0; + m_FilesSelectedIndex = Index; + + if(Input()->MouseDoubleClick()) + m_aFileDialogActivate = true; + } +} + +void CEditor::RenderFileDialog() +{ + // GUI coordsys + Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); + CUIRect View = *UI()->Screen(); + float Width = View.w, Height = View.h; + + RenderTools()->DrawUIRect(&View, vec4(0,0,0,0.25f), 0, 0); + View.VMargin(150.0f, &View); + View.HMargin(50.0f, &View); + RenderTools()->DrawUIRect(&View, vec4(0,0,0,0.75f), CUI::CORNER_ALL, 5.0f); + View.Margin(10.0f, &View); + + CUIRect Title, FileBox, FileBoxLabel, ButtonBar, Scroll; + View.HSplitTop(18.0f, &Title, &View); + View.HSplitTop(5.0f, 0, &View); // some spacing + View.HSplitBottom(14.0f, &View, &ButtonBar); + View.HSplitBottom(10.0f, &View, 0); // some spacing + View.HSplitBottom(14.0f, &View, &FileBox); + FileBox.VSplitLeft(55.0f, &FileBoxLabel, &FileBox); + View.HSplitBottom(10.0f, &View, 0); // some spacing + View.VSplitRight(15.0f, &View, &Scroll); + + // title + RenderTools()->DrawUIRect(&Title, vec4(1, 1, 1, 0.25f), CUI::CORNER_ALL, 4.0f); + Title.VMargin(10.0f, &Title); + UI()->DoLabel(&Title, m_pFileDialogTitle, 12.0f, -1, -1); + + // filebox + if(m_FileDialogStorageType == IStorage::TYPE_SAVE) + { + static int s_FileBoxID = 0; + UI()->DoLabel(&FileBoxLabel, "Filename:", 10.0f, -1, -1); + if(DoEditBox(&s_FileBoxID, &FileBox, m_aFileDialogFileName, sizeof(m_aFileDialogFileName), 10.0f)) + { + // remove '/' and '\' + for(int i = 0; m_aFileDialogFileName[i]; ++i) + if(m_aFileDialogFileName[i] == '/' || m_aFileDialogFileName[i] == '\\') + str_copy(&m_aFileDialogFileName[i], &m_aFileDialogFileName[i+1], (int)(sizeof(m_aFileDialogFileName))-i); + m_FilesSelectedIndex = -1; + } + } + + int Num = (int)(View.h/17.0f)+1; + static int ScrollBar = 0; + Scroll.HMargin(5.0f, &Scroll); + m_FileDialogScrollValue = UiDoScrollbarV(&ScrollBar, &Scroll, m_FileDialogScrollValue); + + int ScrollNum = m_FileList.size()-Num+1; + if(ScrollNum > 0) + { + if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP)) + m_FileDialogScrollValue -= 3.0f/ScrollNum; + if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN)) + m_FileDialogScrollValue += 3.0f/ScrollNum; + } + else + ScrollNum = 0; + + if(m_FilesSelectedIndex > -1) + { + for(int i = 0; i < Input()->NumEvents(); i++) + { + int NewIndex = -1; + if(Input()->GetEvent(i).m_Flags&IInput::FLAG_PRESS) + { + if(Input()->GetEvent(i).m_Key == KEY_DOWN) NewIndex = m_FilesSelectedIndex + 1; + if(Input()->GetEvent(i).m_Key == KEY_UP) NewIndex = m_FilesSelectedIndex - 1; + } + if(NewIndex > -1 && NewIndex < m_FileList.size()) + { + //scroll + float IndexY = View.y - m_FileDialogScrollValue*ScrollNum*17.0f + NewIndex*17.0f; + int Scroll = View.y > IndexY ? -1 : View.y+View.h < IndexY+17.0f ? 1 : 0; + if(Scroll) + { + if(Scroll < 0) + m_FileDialogScrollValue = ((float)(NewIndex)+0.5f)/ScrollNum; + else + m_FileDialogScrollValue = ((float)(NewIndex-Num)+2.5f)/ScrollNum; + } + + if(!m_FileList[NewIndex].m_IsDir) + str_copy(m_aFileDialogFileName, m_FileList[NewIndex].m_aFilename, sizeof(m_aFileDialogFileName)); + else + m_aFileDialogFileName[0] = 0; + m_FilesSelectedIndex = NewIndex; + } + } + } + + for(int i = 0; i < Input()->NumEvents(); i++) + { + if(Input()->GetEvent(i).m_Flags&IInput::FLAG_PRESS) + { + if(Input()->GetEvent(i).m_Key == KEY_RETURN || Input()->GetEvent(i).m_Key == KEY_KP_ENTER) + m_aFileDialogActivate = true; + } + } + + if(m_FileDialogScrollValue < 0) m_FileDialogScrollValue = 0; + if(m_FileDialogScrollValue > 1) m_FileDialogScrollValue = 1; + + m_FilesStartAt = (int)(ScrollNum*m_FileDialogScrollValue); + if(m_FilesStartAt < 0) + m_FilesStartAt = 0; + + m_FilesStopAt = m_FilesStartAt+Num; + + m_FilesCur = 0; + + // set clipping + UI()->ClipEnable(&View); + + for(int i = 0; i < m_FileList.size(); i++) + AddFileDialogEntry(i, &View); + + // disable clipping again + UI()->ClipDisable(); + + // the buttons + static int s_OkButton = 0; + static int s_CancelButton = 0; + static int s_NewFolderButton = 0; + + CUIRect Button; + ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button); + bool IsDir = m_FilesSelectedIndex >= 0 && m_FileList[m_FilesSelectedIndex].m_IsDir; + if(DoButton_Editor(&s_OkButton, IsDir ? "Open" : m_pFileDialogButtonText, 0, &Button, 0, 0) || m_aFileDialogActivate) + { + m_aFileDialogActivate = false; + if(IsDir) // folder + { + if(str_comp(m_FileList[m_FilesSelectedIndex].m_aFilename, "..") == 0) // parent folder + { + if(fs_parent_dir(m_pFileDialogPath)) + m_pFileDialogPath = m_aFileDialogCurrentFolder; // leave the link + } + else // sub folder + { + if(m_FileList[m_FilesSelectedIndex].m_IsLink) + { + m_pFileDialogPath = m_aFileDialogCurrentLink; // follow the link + str_copy(m_aFileDialogCurrentLink, m_FileList[m_FilesSelectedIndex].m_aFilename, sizeof(m_aFileDialogCurrentLink)); + } + else + { + char aTemp[MAX_PATH_LENGTH]; + str_copy(aTemp, m_pFileDialogPath, sizeof(aTemp)); + str_format(m_pFileDialogPath, MAX_PATH_LENGTH, "%s/%s", aTemp, m_FileList[m_FilesSelectedIndex].m_aFilename); + } + } + FilelistPopulate(!str_comp(m_pFileDialogPath, "maps") || !str_comp(m_pFileDialogPath, "mapres") ? m_FileDialogStorageType : + m_FileList[m_FilesSelectedIndex].m_StorageType); + if(m_FilesSelectedIndex >= 0 && !m_FileList[m_FilesSelectedIndex].m_IsDir) + str_copy(m_aFileDialogFileName, m_FileList[m_FilesSelectedIndex].m_aFilename, sizeof(m_aFileDialogFileName)); + else + m_aFileDialogFileName[0] = 0; + } + else // file + { + str_format(m_aFileSaveName, sizeof(m_aFileSaveName), "%s/%s", m_pFileDialogPath, m_aFileDialogFileName); + if(!str_comp(m_pFileDialogButtonText, "Save")) + { + IOHANDLE File = Storage()->OpenFile(m_aFileSaveName, IOFLAG_READ, IStorage::TYPE_SAVE); + if(File) + { + io_close(File); + m_PopupEventType = POPEVENT_SAVE; + m_PopupEventActivated = true; + } + else + if(m_pfnFileDialogFunc) + m_pfnFileDialogFunc(m_aFileSaveName, m_FilesSelectedIndex >= 0 ? m_FileList[m_FilesSelectedIndex].m_StorageType : m_FileDialogStorageType, m_pFileDialogUser); + } + else + if(m_pfnFileDialogFunc) + m_pfnFileDialogFunc(m_aFileSaveName, m_FilesSelectedIndex >= 0 ? m_FileList[m_FilesSelectedIndex].m_StorageType : m_FileDialogStorageType, m_pFileDialogUser); + } + } + + ButtonBar.VSplitRight(40.0f, &ButtonBar, &Button); + ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button); + if(DoButton_Editor(&s_CancelButton, "Cancel", 0, &Button, 0, 0) || Input()->KeyPressed(KEY_ESCAPE)) + m_Dialog = DIALOG_NONE; + + if(m_FileDialogStorageType == IStorage::TYPE_SAVE) + { + ButtonBar.VSplitLeft(40.0f, 0, &ButtonBar); + ButtonBar.VSplitLeft(70.0f, &Button, &ButtonBar); + if(DoButton_Editor(&s_NewFolderButton, "New folder", 0, &Button, 0, 0)) + { + m_FileDialogNewFolderName[0] = 0; + m_FileDialogErrString[0] = 0; + static int s_NewFolderPopupID = 0; + UiInvokePopupMenu(&s_NewFolderPopupID, 0, Width/2.0f-200.0f, Height/2.0f-100.0f, 400.0f, 200.0f, PopupNewFolder); + UI()->SetActiveItem(0); + } + } +} + +void CEditor::FilelistPopulate(int StorageType) +{ + m_FileList.clear(); + if(m_FileDialogStorageType != IStorage::TYPE_SAVE && !str_comp(m_pFileDialogPath, "maps")) + { + CFilelistItem Item; + str_copy(Item.m_aFilename, "downloadedmaps", sizeof(Item.m_aFilename)); + str_copy(Item.m_aName, "downloadedmaps/", sizeof(Item.m_aName)); + Item.m_IsDir = true; + Item.m_IsLink = true; + Item.m_StorageType = IStorage::TYPE_SAVE; + m_FileList.add(Item); + } + Storage()->ListDirectory(StorageType, m_pFileDialogPath, EditorListdirCallback, this); + m_FilesSelectedIndex = m_FileList.size() ? 0 : -1; + m_aFileDialogActivate = false; +} + +void CEditor::InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText, + const char *pBasePath, const char *pDefaultName, + void (*pfnFunc)(const char *pFileName, int StorageType, void *pUser), void *pUser) +{ + m_FileDialogStorageType = StorageType; + m_pFileDialogTitle = pTitle; + m_pFileDialogButtonText = pButtonText; + m_pfnFileDialogFunc = pfnFunc; + m_pFileDialogUser = pUser; + m_aFileDialogFileName[0] = 0; + m_aFileDialogCurrentFolder[0] = 0; + m_aFileDialogCurrentLink[0] = 0; + m_pFileDialogPath = m_aFileDialogCurrentFolder; + m_FileDialogFileType = FileType; + m_FileDialogScrollValue = 0.0f; + + if(pDefaultName) + str_copy(m_aFileDialogFileName, pDefaultName, sizeof(m_aFileDialogFileName)); + if(pBasePath) + str_copy(m_aFileDialogCurrentFolder, pBasePath, sizeof(m_aFileDialogCurrentFolder)); + + FilelistPopulate(m_FileDialogStorageType); + + m_Dialog = DIALOG_FILE; +} + + + +void CEditor::RenderModebar(CUIRect View) +{ + CUIRect Button; + + // mode buttons + { + View.VSplitLeft(65.0f, &Button, &View); + Button.HSplitTop(30.0f, 0, &Button); + static int s_Button = 0; + const char *pButName = m_Mode == MODE_LAYERS ? "Layers" : "Images"; + if(DoButton_Tab(&s_Button, pButName, 0, &Button, 0, "Switch between images and layers managment.")) + { + if(m_Mode == MODE_LAYERS) + m_Mode = MODE_IMAGES; + else + m_Mode = MODE_LAYERS; + } + } + + View.VSplitLeft(5.0f, 0, &View); +} + +void CEditor::RenderStatusbar(CUIRect View) +{ + CUIRect Button; + View.VSplitRight(60.0f, &View, &Button); + static int s_EnvelopeButton = 0; + if(DoButton_Editor(&s_EnvelopeButton, "Envelopes", m_ShowEnvelopeEditor, &Button, 0, "Toggles the envelope editor.")) + m_ShowEnvelopeEditor = (m_ShowEnvelopeEditor+1)%4; + + if(m_pTooltip) + { + if(ms_pUiGotContext && ms_pUiGotContext == UI()->HotItem()) + { + char aBuf[512]; + str_format(aBuf, sizeof(aBuf), "%s Right click for context menu.", m_pTooltip); + UI()->DoLabel(&View, aBuf, 10.0f, -1, -1); + } + else + UI()->DoLabel(&View, m_pTooltip, 10.0f, -1, -1); + } +} + +void CEditor::RenderEnvelopeEditor(CUIRect View) +{ + if(m_SelectedEnvelope < 0) m_SelectedEnvelope = 0; + if(m_SelectedEnvelope >= m_Map.m_lEnvelopes.size()) m_SelectedEnvelope = m_Map.m_lEnvelopes.size()-1; + + CEnvelope *pEnvelope = 0; + if(m_SelectedEnvelope >= 0 && m_SelectedEnvelope < m_Map.m_lEnvelopes.size()) + pEnvelope = m_Map.m_lEnvelopes[m_SelectedEnvelope]; + + CUIRect ToolBar, CurveBar, ColorBar; + View.HSplitTop(15.0f, &ToolBar, &View); + View.HSplitTop(15.0f, &CurveBar, &View); + ToolBar.Margin(2.0f, &ToolBar); + CurveBar.Margin(2.0f, &CurveBar); + + // do the toolbar + { + CUIRect Button; + CEnvelope *pNewEnv = 0; + + ToolBar.VSplitRight(50.0f, &ToolBar, &Button); + static int s_New4dButton = 0; + if(DoButton_Editor(&s_New4dButton, "Color+", 0, &Button, 0, "Creates a new color envelope")) + { + m_Map.m_Modified = true; + pNewEnv = m_Map.NewEnvelope(4); + } + + ToolBar.VSplitRight(5.0f, &ToolBar, &Button); + ToolBar.VSplitRight(50.0f, &ToolBar, &Button); + static int s_New2dButton = 0; + if(DoButton_Editor(&s_New2dButton, "Pos.+", 0, &Button, 0, "Creates a new pos envelope")) + { + m_Map.m_Modified = true; + pNewEnv = m_Map.NewEnvelope(3); + } + + // Delete button + if(m_SelectedEnvelope >= 0) + { + ToolBar.VSplitRight(10.0f, &ToolBar, &Button); + ToolBar.VSplitRight(50.0f, &ToolBar, &Button); + static int s_DelButton = 0; + if(DoButton_Editor(&s_DelButton, "Delete", 0, &Button, 0, "Delete this envelope")) + { + m_Map.m_Modified = true; + m_Map.DeleteEnvelope(m_SelectedEnvelope); + if(m_SelectedEnvelope >= m_Map.m_lEnvelopes.size()) + m_SelectedEnvelope = m_Map.m_lEnvelopes.size()-1; + pEnvelope = m_SelectedEnvelope >= 0 ? m_Map.m_lEnvelopes[m_SelectedEnvelope] : 0; + } + } + + if(pNewEnv) // add the default points + { + if(pNewEnv->m_Channels == 4) + { + pNewEnv->AddPoint(0, 1,1,1,1); + pNewEnv->AddPoint(1000, 1,1,1,1); + } + else + { + pNewEnv->AddPoint(0, 0); + pNewEnv->AddPoint(1000, 0); + } + } + + CUIRect Shifter, Inc, Dec; + ToolBar.VSplitLeft(60.0f, &Shifter, &ToolBar); + Shifter.VSplitRight(15.0f, &Shifter, &Inc); + Shifter.VSplitLeft(15.0f, &Dec, &Shifter); + char aBuf[512]; + str_format(aBuf, sizeof(aBuf),"%d/%d", m_SelectedEnvelope+1, m_Map.m_lEnvelopes.size()); + RenderTools()->DrawUIRect(&Shifter, vec4(1,1,1,0.5f), 0, 0.0f); + UI()->DoLabel(&Shifter, aBuf, 10.0f, 0, -1); + + static int s_PrevButton = 0; + if(DoButton_ButtonDec(&s_PrevButton, 0, 0, &Dec, 0, "Previous Envelope")) + m_SelectedEnvelope--; + + static int s_NextButton = 0; + if(DoButton_ButtonInc(&s_NextButton, 0, 0, &Inc, 0, "Next Envelope")) + m_SelectedEnvelope++; + + if(pEnvelope) + { + ToolBar.VSplitLeft(15.0f, &Button, &ToolBar); + ToolBar.VSplitLeft(35.0f, &Button, &ToolBar); + UI()->DoLabel(&Button, "Name:", 10.0f, -1, -1); + + ToolBar.VSplitLeft(80.0f, &Button, &ToolBar); + + static int s_NameBox = 0; + if(DoEditBox(&s_NameBox, &Button, pEnvelope->m_aName, sizeof(pEnvelope->m_aName), 10.0f)) + m_Map.m_Modified = true; + } + } + + bool ShowColorBar = false; + if(pEnvelope && pEnvelope->m_Channels == 4) + { + ShowColorBar = true; + View.HSplitTop(20.0f, &ColorBar, &View); + ColorBar.Margin(2.0f, &ColorBar); + RenderBackground(ColorBar, ms_CheckerTexture, 16.0f, 1.0f); + } + + RenderBackground(View, ms_CheckerTexture, 32.0f, 0.1f); + + if(pEnvelope) + { + static array Selection; + static int sEnvelopeEditorID = 0; + static int s_ActiveChannels = 0xf; + + if(pEnvelope) + { + CUIRect Button; + + ToolBar.VSplitLeft(15.0f, &Button, &ToolBar); + + static const char *s_paNames[2][4] = { + {"X", "Y", "R", ""}, + {"R", "G", "B", "A"}, + }; + + const char *paDescriptions[2][4] = { + {"X-axis of the envelope", "Y-axis of the envelope", "Rotation of the envelope", ""}, + {"Red value of the envelope", "Green value of the envelope", "Blue value of the envelope", "Alpha value of the envelope"}, + }; + + static int s_aChannelButtons[4] = {0}; + int Bit = 1; + //ui_draw_button_func draw_func; + + for(int i = 0; i < pEnvelope->m_Channels; i++, Bit<<=1) + { + ToolBar.VSplitLeft(15.0f, &Button, &ToolBar); + + /*if(i == 0) draw_func = draw_editor_button_l; + else if(i == envelope->channels-1) draw_func = draw_editor_button_r; + else draw_func = draw_editor_button_m;*/ + + if(DoButton_Editor(&s_aChannelButtons[i], s_paNames[pEnvelope->m_Channels-3][i], s_ActiveChannels&Bit, &Button, 0, paDescriptions[pEnvelope->m_Channels-3][i])) + s_ActiveChannels ^= Bit; + } + } + + float EndTime = pEnvelope->EndTime(); + if(EndTime < 1) + EndTime = 1; + + pEnvelope->FindTopBottom(s_ActiveChannels); + float Top = pEnvelope->m_Top; + float Bottom = pEnvelope->m_Bottom; + + if(Top < 1) + Top = 1; + if(Bottom >= 0) + Bottom = 0; + + float TimeScale = EndTime/View.w; + float ValueScale = (Top-Bottom)/View.h; + + if(UI()->MouseInside(&View)) + UI()->SetHotItem(&sEnvelopeEditorID); + + if(UI()->HotItem() == &sEnvelopeEditorID) + { + // do stuff + if(pEnvelope) + { + if(UI()->MouseButtonClicked(1)) + { + // add point + int Time = (int)(((UI()->MouseX()-View.x)*TimeScale)*1000.0f); + //float env_y = (UI()->MouseY()-view.y)/TimeScale; + float aChannels[4]; + pEnvelope->Eval(Time, aChannels); + pEnvelope->AddPoint(Time, + f2fx(aChannels[0]), f2fx(aChannels[1]), + f2fx(aChannels[2]), f2fx(aChannels[3])); + m_Map.m_Modified = true; + } + + m_pTooltip = "Press right mouse button to create a new point"; + } + } + + vec3 aColors[] = {vec3(1,0.2f,0.2f), vec3(0.2f,1,0.2f), vec3(0.2f,0.2f,1), vec3(1,1,0.2f)}; + + // render lines + { + UI()->ClipEnable(&View); + Graphics()->TextureSet(-1); + Graphics()->LinesBegin(); + for(int c = 0; c < pEnvelope->m_Channels; c++) + { + if(s_ActiveChannels&(1<SetColor(aColors[c].r,aColors[c].g,aColors[c].b,1); + else + Graphics()->SetColor(aColors[c].r*0.5f,aColors[c].g*0.5f,aColors[c].b*0.5f,1); + + float PrevX = 0; + float aResults[4]; + pEnvelope->Eval(0.000001f, aResults); + float PrevValue = aResults[c]; + + int Steps = (int)((View.w/UI()->Screen()->w) * Graphics()->ScreenWidth()); + for(int i = 1; i <= Steps; i++) + { + float a = i/(float)Steps; + pEnvelope->Eval(a*EndTime, aResults); + float v = aResults[c]; + v = (v-Bottom)/(Top-Bottom); + + IGraphics::CLineItem LineItem(View.x + PrevX*View.w, View.y+View.h - PrevValue*View.h, View.x + a*View.w, View.y+View.h - v*View.h); + Graphics()->LinesDraw(&LineItem, 1); + PrevX = a; + PrevValue = v; + } + } + Graphics()->LinesEnd(); + UI()->ClipDisable(); + } + + // render curve options + { + for(int i = 0; i < pEnvelope->m_lPoints.size()-1; i++) + { + float t0 = pEnvelope->m_lPoints[i].m_Time/1000.0f/EndTime; + float t1 = pEnvelope->m_lPoints[i+1].m_Time/1000.0f/EndTime; + + //dbg_msg("", "%f", end_time); + + CUIRect v; + v.x = CurveBar.x + (t0+(t1-t0)*0.5f) * CurveBar.w; + v.y = CurveBar.y; + v.h = CurveBar.h; + v.w = CurveBar.h; + v.x -= v.w/2; + void *pID = &pEnvelope->m_lPoints[i].m_Curvetype; + const char *paTypeName[] = { + "N", "L", "S", "F", "M" + }; + + if(DoButton_Editor(pID, paTypeName[pEnvelope->m_lPoints[i].m_Curvetype], 0, &v, 0, "Switch curve type")) + pEnvelope->m_lPoints[i].m_Curvetype = (pEnvelope->m_lPoints[i].m_Curvetype+1)%NUM_CURVETYPES; + } + } + + // render colorbar + if(ShowColorBar) + { + Graphics()->TextureSet(-1); + Graphics()->QuadsBegin(); + for(int i = 0; i < pEnvelope->m_lPoints.size()-1; i++) + { + float r0 = fx2f(pEnvelope->m_lPoints[i].m_aValues[0]); + float g0 = fx2f(pEnvelope->m_lPoints[i].m_aValues[1]); + float b0 = fx2f(pEnvelope->m_lPoints[i].m_aValues[2]); + float a0 = fx2f(pEnvelope->m_lPoints[i].m_aValues[3]); + float r1 = fx2f(pEnvelope->m_lPoints[i+1].m_aValues[0]); + float g1 = fx2f(pEnvelope->m_lPoints[i+1].m_aValues[1]); + float b1 = fx2f(pEnvelope->m_lPoints[i+1].m_aValues[2]); + float a1 = fx2f(pEnvelope->m_lPoints[i+1].m_aValues[3]); + + IGraphics::CColorVertex Array[4] = {IGraphics::CColorVertex(0, r0, g0, b0, a0), + IGraphics::CColorVertex(1, r1, g1, b1, a1), + IGraphics::CColorVertex(2, r1, g1, b1, a1), + IGraphics::CColorVertex(3, r0, g0, b0, a0)}; + Graphics()->SetColorVertex(Array, 4); + + float x0 = pEnvelope->m_lPoints[i].m_Time/1000.0f/EndTime; +// float y0 = (fx2f(envelope->points[i].values[c])-bottom)/(top-bottom); + float x1 = pEnvelope->m_lPoints[i+1].m_Time/1000.0f/EndTime; + //float y1 = (fx2f(envelope->points[i+1].values[c])-bottom)/(top-bottom); + CUIRect v; + v.x = ColorBar.x + x0*ColorBar.w; + v.y = ColorBar.y; + v.w = (x1-x0)*ColorBar.w; + v.h = ColorBar.h; + + IGraphics::CQuadItem QuadItem(v.x, v.y, v.w, v.h); + Graphics()->QuadsDrawTL(&QuadItem, 1); + } + Graphics()->QuadsEnd(); + } + + // render handles + { + static bool s_Move = false; + + int CurrentValue = 0, CurrentTime = 0; + + Graphics()->TextureSet(-1); + Graphics()->QuadsBegin(); + for(int c = 0; c < pEnvelope->m_Channels; c++) + { + if(!(s_ActiveChannels&(1<m_lPoints.size(); i++) + { + float x0 = pEnvelope->m_lPoints[i].m_Time/1000.0f/EndTime; + float y0 = (fx2f(pEnvelope->m_lPoints[i].m_aValues[c])-Bottom)/(Top-Bottom); + CUIRect Final; + Final.x = View.x + x0*View.w; + Final.y = View.y+View.h - y0*View.h; + Final.x -= 2.0f; + Final.y -= 2.0f; + Final.w = 4.0f; + Final.h = 4.0f; + + void *pID = &pEnvelope->m_lPoints[i].m_aValues[c]; + + if(UI()->MouseInside(&Final)) + UI()->SetHotItem(pID); + + float ColorMod = 1.0f; + + if(UI()->ActiveItem() == pID) + { + if(!UI()->MouseButton(0)) + { + UI()->SetActiveItem(0); + s_Move = false; + } + else + { + if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) + { + if(i != 0) + { + if((Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL))) + pEnvelope->m_lPoints[i].m_Time += (int)((m_MouseDeltaX)); + else + pEnvelope->m_lPoints[i].m_Time += (int)((m_MouseDeltaX*TimeScale)*1000.0f); + if(pEnvelope->m_lPoints[i].m_Time < pEnvelope->m_lPoints[i-1].m_Time) + pEnvelope->m_lPoints[i].m_Time = pEnvelope->m_lPoints[i-1].m_Time + 1; + if(i+1 != pEnvelope->m_lPoints.size() && pEnvelope->m_lPoints[i].m_Time > pEnvelope->m_lPoints[i+1].m_Time) + pEnvelope->m_lPoints[i].m_Time = pEnvelope->m_lPoints[i+1].m_Time - 1; + } + } + else + { + if((Input()->KeyPressed(KEY_LCTRL) || Input()->KeyPressed(KEY_RCTRL))) + pEnvelope->m_lPoints[i].m_aValues[c] -= f2fx(m_MouseDeltaY*0.001f); + else + pEnvelope->m_lPoints[i].m_aValues[c] -= f2fx(m_MouseDeltaY*ValueScale); + } + m_Map.m_Modified = true; + } + + ColorMod = 100.0f; + Graphics()->SetColor(1,1,1,1); + } + else if(UI()->HotItem() == pID) + { + if(UI()->MouseButton(0)) + { + Selection.clear(); + Selection.add(i); + UI()->SetActiveItem(pID); + } + + // remove point + if(UI()->MouseButtonClicked(1)) + { + pEnvelope->m_lPoints.remove_index(i); + m_Map.m_Modified = true; + } + + ColorMod = 100.0f; + Graphics()->SetColor(1,0.75f,0.75f,1); + m_pTooltip = "Left mouse to drag. Hold ctrl to be more precise. Hold shift to alter time point aswell. Right click to delete."; + } + + if(UI()->ActiveItem() == pID || UI()->HotItem() == pID) + { + CurrentTime = pEnvelope->m_lPoints[i].m_Time; + CurrentValue = pEnvelope->m_lPoints[i].m_aValues[c]; + } + + Graphics()->SetColor(aColors[c].r*ColorMod, aColors[c].g*ColorMod, aColors[c].b*ColorMod, 1.0f); + IGraphics::CQuadItem QuadItem(Final.x, Final.y, Final.w, Final.h); + Graphics()->QuadsDrawTL(&QuadItem, 1); + } + } + Graphics()->QuadsEnd(); + + char aBuf[512]; + str_format(aBuf, sizeof(aBuf),"%.3f %.3f", CurrentTime/1000.0f, fx2f(CurrentValue)); + UI()->DoLabel(&ToolBar, aBuf, 10.0f, 0, -1); + } + } +} + +int CEditor::PopupMenuFile(CEditor *pEditor, CUIRect View) +{ + static int s_NewMapButton = 0; + static int s_SaveButton = 0; + static int s_SaveAsButton = 0; + static int s_OpenButton = 0; + static int s_AppendButton = 0; + static int s_ExitButton = 0; + + CUIRect Slot; + View.HSplitTop(2.0f, &Slot, &View); + View.HSplitTop(12.0f, &Slot, &View); + if(pEditor->DoButton_MenuItem(&s_NewMapButton, "New", 0, &Slot, 0, "Creates a new map")) + { + if(pEditor->HasUnsavedData()) + { + pEditor->m_PopupEventType = POPEVENT_NEW; + pEditor->m_PopupEventActivated = true; + } + else + { + pEditor->Reset(); + pEditor->m_aFileName[0] = 0; + } + return 1; + } + + View.HSplitTop(10.0f, &Slot, &View); + View.HSplitTop(12.0f, &Slot, &View); + if(pEditor->DoButton_MenuItem(&s_OpenButton, "Load", 0, &Slot, 0, "Opens a map for editing")) + { + if(pEditor->HasUnsavedData()) + { + pEditor->m_PopupEventType = POPEVENT_LOAD; + pEditor->m_PopupEventActivated = true; + } + else + pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_MAP, "Load map", "Load", "maps", "", pEditor->CallbackOpenMap, pEditor); + return 1; + } + + View.HSplitTop(10.0f, &Slot, &View); + View.HSplitTop(12.0f, &Slot, &View); + if(pEditor->DoButton_MenuItem(&s_AppendButton, "Append", 0, &Slot, 0, "Opens a map and adds everything from that map to the current one")) + { + pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_MAP, "Append map", "Append", "maps", "", pEditor->CallbackAppendMap, pEditor); + return 1; + } + + View.HSplitTop(10.0f, &Slot, &View); + View.HSplitTop(12.0f, &Slot, &View); + if(pEditor->DoButton_MenuItem(&s_SaveButton, "Save", 0, &Slot, 0, "Saves the current map")) + { + if(pEditor->m_aFileName[0] && pEditor->m_ValidSaveFilename) + { + str_copy(pEditor->m_aFileSaveName, pEditor->m_aFileName, sizeof(pEditor->m_aFileSaveName)); + pEditor->m_PopupEventType = POPEVENT_SAVE; + pEditor->m_PopupEventActivated = true; + } + else + pEditor->InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", "", pEditor->CallbackSaveMap, pEditor); + return 1; + } + + View.HSplitTop(2.0f, &Slot, &View); + View.HSplitTop(12.0f, &Slot, &View); + if(pEditor->DoButton_MenuItem(&s_SaveAsButton, "Save As", 0, &Slot, 0, "Saves the current map under a new name")) + { + pEditor->InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", "", pEditor->CallbackSaveMap, pEditor); + return 1; + } + + View.HSplitTop(10.0f, &Slot, &View); + View.HSplitTop(12.0f, &Slot, &View); + if(pEditor->DoButton_MenuItem(&s_ExitButton, "Exit", 0, &Slot, 0, "Exits from the editor")) + { + if(pEditor->HasUnsavedData()) + { + pEditor->m_PopupEventType = POPEVENT_EXIT; + pEditor->m_PopupEventActivated = true; + } + else + g_Config.m_ClEditor = 0; + return 1; + } + + return 0; +} + +void CEditor::RenderMenubar(CUIRect MenuBar) +{ + static CUIRect s_File /*, view, help*/; + + MenuBar.VSplitLeft(60.0f, &s_File, &MenuBar); + if(DoButton_Menu(&s_File, "File", 0, &s_File, 0, 0)) + UiInvokePopupMenu(&s_File, 1, s_File.x, s_File.y+s_File.h-1.0f, 120, 150, PopupMenuFile, this); + + /* + menubar.VSplitLeft(5.0f, 0, &menubar); + menubar.VSplitLeft(60.0f, &view, &menubar); + if(do_editor_button(&view, "View", 0, &view, draw_editor_button_menu, 0, 0)) + (void)0; + + menubar.VSplitLeft(5.0f, 0, &menubar); + menubar.VSplitLeft(60.0f, &help, &menubar); + if(do_editor_button(&help, "Help", 0, &help, draw_editor_button_menu, 0, 0)) + (void)0; + */ + + MenuBar.VSplitLeft(40.0f, 0, &MenuBar); + char aBuf[128]; + str_format(aBuf, sizeof(aBuf), "File: %s", m_aFileName); + UI()->DoLabel(&MenuBar, aBuf, 10.0f, -1, -1); +} + +void CEditor::Render() +{ + // basic start + Graphics()->Clear(1.0f, 0.0f, 1.0f); + CUIRect View = *UI()->Screen(); + Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); + + float Width = View.w; + float Height = View.h; + + // reset tip + m_pTooltip = 0; + + // render checker + RenderBackground(View, ms_CheckerTexture, 32.0f, 1.0f); + + CUIRect MenuBar, CModeBar, ToolBar, StatusBar, EnvelopeEditor, ToolBox; + bool ShowPicker = Input()->KeyPressed(KEY_SPACE) != 0 && m_Dialog == DIALOG_NONE; + + if(m_GuiActive) + { + + View.HSplitTop(16.0f, &MenuBar, &View); + View.HSplitTop(53.0f, &ToolBar, &View); + View.VSplitLeft(100.0f, &ToolBox, &View); + View.HSplitBottom(16.0f, &View, &StatusBar); + + if(m_ShowEnvelopeEditor && !ShowPicker) + { + float size = 125.0f; + if(m_ShowEnvelopeEditor == 2) + size *= 2.0f; + else if(m_ShowEnvelopeEditor == 3) + size *= 3.0f; + View.HSplitBottom(size, &View, &EnvelopeEditor); + } + } + + // a little hack for now + if(m_Mode == MODE_LAYERS) + DoMapEditor(View, ToolBar, ShowPicker); + + if(m_GuiActive) + { + float Brightness = 0.25f; + RenderBackground(MenuBar, ms_BackgroundTexture, 128.0f, Brightness*0); + MenuBar.Margin(2.0f, &MenuBar); + + RenderBackground(ToolBox, ms_BackgroundTexture, 128.0f, Brightness); + ToolBox.Margin(2.0f, &ToolBox); + + RenderBackground(ToolBar, ms_BackgroundTexture, 128.0f, Brightness); + ToolBar.Margin(2.0f, &ToolBar); + ToolBar.VSplitLeft(100.0f, &CModeBar, &ToolBar); + + RenderBackground(StatusBar, ms_BackgroundTexture, 128.0f, Brightness); + StatusBar.Margin(2.0f, &StatusBar); + + // do the toolbar + if(m_Mode == MODE_LAYERS) + DoToolbar(ToolBar); + + if(m_ShowEnvelopeEditor) + { + RenderBackground(EnvelopeEditor, ms_BackgroundTexture, 128.0f, Brightness); + EnvelopeEditor.Margin(2.0f, &EnvelopeEditor); + } + } + + + if(m_Mode == MODE_LAYERS) + RenderLayers(ToolBox, ToolBar, View); + else if(m_Mode == MODE_IMAGES) + RenderImages(ToolBox, ToolBar, View); + + Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); + + if(m_GuiActive) + { + RenderMenubar(MenuBar); + + RenderModebar(CModeBar); + if(m_ShowEnvelopeEditor) + RenderEnvelopeEditor(EnvelopeEditor); + } + + if(m_Dialog == DIALOG_FILE) + { + static int s_NullUiTarget = 0; + UI()->SetHotItem(&s_NullUiTarget); + RenderFileDialog(); + } + + if(m_PopupEventActivated) + { + static int s_PopupID = 0; + UiInvokePopupMenu(&s_PopupID, 0, Width/2.0f-200.0f, Height/2.0f-100.0f, 400.0f, 200.0f, PopupEvent); + m_PopupEventActivated = false; + } + + + UiDoPopupMenu(); + + if(m_GuiActive) + RenderStatusbar(StatusBar); + + // + if(g_Config.m_EdShowkeys) + { + Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h); + CTextCursor Cursor; + TextRender()->SetCursor(&Cursor, View.x+10, View.y+View.h-24-10, 24.0f, TEXTFLAG_RENDER); + + int NKeys = 0; + for(int i = 0; i < KEY_LAST; i++) + { + if(Input()->KeyPressed(i)) + { + if(NKeys) + TextRender()->TextEx(&Cursor, " + ", -1); + TextRender()->TextEx(&Cursor, Input()->KeyName(i), -1); + NKeys++; + } + } + } + + if(m_ShowMousePointer) + { + // render butt ugly mouse cursor + float mx = UI()->MouseX(); + float my = UI()->MouseY(); + Graphics()->TextureSet(ms_CursorTexture); + Graphics()->QuadsBegin(); + if(ms_pUiGotContext == UI()->HotItem()) + Graphics()->SetColor(1,0,0,1); + IGraphics::CQuadItem QuadItem(mx,my, 16.0f, 16.0f); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); + } + +} + +void CEditor::Reset(bool CreateDefault) +{ + m_Map.Clean(); + + // create default layers + if(CreateDefault) + m_Map.CreateDefault(ms_EntitiesTexture); + + /* + { + }*/ + + m_SelectedLayer = 0; + m_SelectedGroup = 0; + m_SelectedQuad = -1; + m_SelectedPoints = 0; + m_SelectedEnvelope = 0; + m_SelectedImage = 0; + + m_WorldOffsetX = 0; + m_WorldOffsetY = 0; + m_EditorOffsetX = 0.0f; + m_EditorOffsetY = 0.0f; + + m_WorldZoom = 1.0f; + m_ZoomLevel = 200; + + m_MouseDeltaX = 0; + m_MouseDeltaY = 0; + m_MouseDeltaWx = 0; + m_MouseDeltaWy = 0; + + m_Map.m_Modified = false; +} + +void CEditorMap::DeleteEnvelope(int Index) +{ + if(Index < 0 || Index >= m_lEnvelopes.size()) + return; + + m_Modified = true; + + // fix links between envelopes and quads + for(int i = 0; i < m_lGroups.size(); ++i) + for(int j = 0; j < m_lGroups[i]->m_lLayers.size(); ++j) + if(m_lGroups[i]->m_lLayers[j]->m_Type == LAYERTYPE_QUADS) + { + CLayerQuads *Layer = static_cast(m_lGroups[i]->m_lLayers[j]); + for(int k = 0; k < Layer->m_lQuads.size(); ++k) + { + if(Layer->m_lQuads[k].m_PosEnv == Index) + Layer->m_lQuads[k].m_PosEnv = -1; + else if(Layer->m_lQuads[k].m_PosEnv > Index) + Layer->m_lQuads[k].m_PosEnv--; + if(Layer->m_lQuads[k].m_ColorEnv == Index) + Layer->m_lQuads[k].m_ColorEnv = -1; + else if(Layer->m_lQuads[k].m_ColorEnv > Index) + Layer->m_lQuads[k].m_ColorEnv--; + } + } + + m_lEnvelopes.remove_index(Index); +} + +void CEditorMap::MakeGameLayer(CLayer *pLayer) +{ + m_pGameLayer = (CLayerGame *)pLayer; + m_pGameLayer->m_pEditor = m_pEditor; + m_pGameLayer->m_TexID = m_pEditor->ms_EntitiesTexture; +} + +void CEditorMap::MakeGameGroup(CLayerGroup *pGroup) +{ + m_pGameGroup = pGroup; + m_pGameGroup->m_GameGroup = true; + m_pGameGroup->m_pName = "Game"; +} + + + +void CEditorMap::Clean() +{ + m_lGroups.delete_all(); + m_lEnvelopes.delete_all(); + m_lImages.delete_all(); + + m_pGameLayer = 0x0; + m_pGameGroup = 0x0; + + m_Modified = false; +} + +void CEditorMap::CreateDefault(int EntitiesTexture) +{ + // add background + CLayerGroup *pGroup = NewGroup(); + pGroup->m_ParallaxX = 0; + pGroup->m_ParallaxY = 0; + CLayerQuads *pLayer = new CLayerQuads; + pLayer->m_pEditor = m_pEditor; + CQuad *pQuad = pLayer->NewQuad(); + const int Width = 800000; + const int Height = 600000; + pQuad->m_aPoints[0].x = pQuad->m_aPoints[2].x = -Width; + pQuad->m_aPoints[1].x = pQuad->m_aPoints[3].x = Width; + pQuad->m_aPoints[0].y = pQuad->m_aPoints[1].y = -Height; + pQuad->m_aPoints[2].y = pQuad->m_aPoints[3].y = Height; + pQuad->m_aColors[0].r = pQuad->m_aColors[1].r = 94; + pQuad->m_aColors[0].g = pQuad->m_aColors[1].g = 132; + pQuad->m_aColors[0].b = pQuad->m_aColors[1].b = 174; + pQuad->m_aColors[2].r = pQuad->m_aColors[3].r = 204; + pQuad->m_aColors[2].g = pQuad->m_aColors[3].g = 232; + pQuad->m_aColors[2].b = pQuad->m_aColors[3].b = 255; + pGroup->AddLayer(pLayer); + + // add game layer + MakeGameGroup(NewGroup()); + MakeGameLayer(new CLayerGame(50, 50)); + m_pGameGroup->AddLayer(m_pGameLayer); +} + +void CEditor::Init() +{ + m_pInput = Kernel()->RequestInterface(); + m_pClient = Kernel()->RequestInterface(); + m_pConsole = Kernel()->RequestInterface(); + m_pGraphics = Kernel()->RequestInterface(); + m_pTextRender = Kernel()->RequestInterface(); + m_pStorage = Kernel()->RequestInterface(); + m_RenderTools.m_pGraphics = m_pGraphics; + m_RenderTools.m_pUI = &m_UI; + m_UI.SetGraphics(m_pGraphics, m_pTextRender); + m_Map.m_pEditor = this; + + ms_CheckerTexture = Graphics()->LoadTexture("editor/checker.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); + ms_BackgroundTexture = Graphics()->LoadTexture("editor/background.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); + ms_CursorTexture = Graphics()->LoadTexture("editor/cursor.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); + ms_EntitiesTexture = Graphics()->LoadTexture("editor/entities.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); + + m_TilesetPicker.m_pEditor = this; + m_TilesetPicker.MakePalette(); + m_TilesetPicker.m_Readonly = true; + + m_Brush.m_pMap = &m_Map; + + Reset(); + m_Map.m_Modified = false; +} + +void CEditor::DoMapBorder() +{ + CLayerTiles *pT = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES); + + for(int i = 0; i < pT->m_Width*2; ++i) + pT->m_pTiles[i].m_Index = 1; + + for(int i = 0; i < pT->m_Width*pT->m_Height; ++i) + { + if(i%pT->m_Width < 2 || i%pT->m_Width > pT->m_Width-3) + pT->m_pTiles[i].m_Index = 1; + } + + for(int i = (pT->m_Width*(pT->m_Height-2)); i < pT->m_Width*pT->m_Height; ++i) + pT->m_pTiles[i].m_Index = 1; +} + +void CEditor::UpdateAndRender() +{ + static float s_MouseX = 0.0f; + static float s_MouseY = 0.0f; + + if(m_Animate) + m_AnimateTime = (time_get()-m_AnimateStart)/(float)time_freq(); + else + m_AnimateTime = 0; + ms_pUiGotContext = 0; + + // handle mouse movement + float mx, my, Mwx, Mwy; + float rx, ry; + { + Input()->MouseRelative(&rx, &ry); + m_MouseDeltaX = rx; + m_MouseDeltaY = ry; + + if(!m_LockMouse) + { + s_MouseX += rx; + s_MouseY += ry; + } + + s_MouseX = clamp(s_MouseX, 0.0f, UI()->Screen()->w); + s_MouseY = clamp(s_MouseY, 0.0f, UI()->Screen()->h); + + // update the ui + mx = s_MouseX; + my = s_MouseY; + Mwx = 0; + Mwy = 0; + + // fix correct world x and y + CLayerGroup *g = GetSelectedGroup(); + if(g) + { + float aPoints[4]; + g->Mapping(aPoints); + + float WorldWidth = aPoints[2]-aPoints[0]; + float WorldHeight = aPoints[3]-aPoints[1]; + + Mwx = aPoints[0] + WorldWidth * (s_MouseX/UI()->Screen()->w); + Mwy = aPoints[1] + WorldHeight * (s_MouseY/UI()->Screen()->h); + m_MouseDeltaWx = m_MouseDeltaX*(WorldWidth / UI()->Screen()->w); + m_MouseDeltaWy = m_MouseDeltaY*(WorldHeight / UI()->Screen()->h); + } + + int Buttons = 0; + if(Input()->KeyPressed(KEY_MOUSE_1)) Buttons |= 1; + if(Input()->KeyPressed(KEY_MOUSE_2)) Buttons |= 2; + if(Input()->KeyPressed(KEY_MOUSE_3)) Buttons |= 4; + + UI()->Update(mx,my,Mwx,Mwy,Buttons); + } + + // toggle gui + if(Input()->KeyDown(KEY_TAB)) + m_GuiActive = !m_GuiActive; + + if(Input()->KeyDown(KEY_F5)) + Save("maps/debug_test2.map"); + + if(Input()->KeyDown(KEY_F6)) + Load("maps/debug_test2.map", IStorage::TYPE_ALL); + + if(Input()->KeyDown(KEY_F8)) + Load("maps/debug_test.map", IStorage::TYPE_ALL); + + if(Input()->KeyDown(KEY_F7)) + Save("maps/quicksave.map"); + + if(Input()->KeyDown(KEY_F10)) + m_ShowMousePointer = false; + + Render(); + + if(Input()->KeyDown(KEY_F10)) + { + Graphics()->TakeScreenshot(0); + m_ShowMousePointer = true; + } + + Input()->ClearEvents(); +} + +IEditor *CreateEditor() { return new CEditor; } diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h new file mode 100644 index 00000000..22e8c32d --- /dev/null +++ b/src/game/editor/editor.h @@ -0,0 +1,741 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#ifndef GAME_EDITOR_EDITOR_H +#define GAME_EDITOR_EDITOR_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +typedef void (*INDEX_MODIFY_FUNC)(int *pIndex); + +//CRenderTools m_RenderTools; + +// CEditor SPECIFIC +enum +{ + MODE_LAYERS=0, + MODE_IMAGES, + + DIALOG_NONE=0, + DIALOG_FILE, +}; + +struct CEntity +{ + CPoint m_Position; + int m_Type; +}; + +class CEnvelope +{ +public: + int m_Channels; + array m_lPoints; + char m_aName[32]; + float m_Bottom, m_Top; + + CEnvelope(int Chan) + { + m_Channels = Chan; + m_aName[0] = 0; + m_Bottom = 0; + m_Top = 0; + } + + void Resort() + { + sort(m_lPoints.all()); + FindTopBottom(0xf); + } + + void FindTopBottom(int ChannelMask) + { + m_Top = -1000000000.0f; + m_Bottom = 1000000000.0f; + for(int i = 0; i < m_lPoints.size(); i++) + { + for(int c = 0; c < m_Channels; c++) + { + if(ChannelMask&(1< m_Top) m_Top = v; + if(v < m_Bottom) m_Bottom = v; + } + } + } + } + + int Eval(float Time, float *pResult) + { + CRenderTools::RenderEvalEnvelope(m_lPoints.base_ptr(), m_lPoints.size(), m_Channels, Time, pResult); + return m_Channels; + } + + void AddPoint(int Time, int v0, int v1=0, int v2=0, int v3=0) + { + CEnvPoint p; + p.m_Time = Time; + p.m_aValues[0] = v0; + p.m_aValues[1] = v1; + p.m_aValues[2] = v2; + p.m_aValues[3] = v3; + p.m_Curvetype = CURVETYPE_LINEAR; + m_lPoints.add(p); + Resort(); + } + + float EndTime() + { + if(m_lPoints.size()) + return m_lPoints[m_lPoints.size()-1].m_Time*(1.0f/1000.0f); + return 0; + } +}; + + +class CLayer; +class CLayerGroup; +class CEditorMap; + +class CLayer +{ +public: + class CEditor *m_pEditor; + class IGraphics *Graphics(); + class ITextRender *TextRender(); + + CLayer() + { + m_Type = LAYERTYPE_INVALID; + m_pTypeName = "(invalid)"; + m_Visible = true; + m_Readonly = false; + m_SaveToMap = true; + m_Flags = 0; + m_pEditor = 0; + } + + virtual ~CLayer() + { + } + + + virtual void BrushSelecting(CUIRect Rect) {} + virtual int BrushGrab(CLayerGroup *pBrush, CUIRect Rect) { return 0; } + virtual void FillSelection(bool Empty, CLayer *pBrush, CUIRect Rect) {} + virtual void BrushDraw(CLayer *pBrush, float x, float y) {} + virtual void BrushPlace(CLayer *pBrush, float x, float y) {} + virtual void BrushFlipX() {} + virtual void BrushFlipY() {} + virtual void BrushRotate(float Amount) {} + + virtual void Render() {} + virtual int RenderProperties(CUIRect *pToolbox) { return 0; } + + virtual void ModifyImageIndex(INDEX_MODIFY_FUNC pfnFunc) {} + virtual void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc) {} + + virtual void GetSize(float *w, float *h) { *w = 0; *h = 0;} + + const char *m_pTypeName; + int m_Type; + int m_Flags; + + bool m_Readonly; + bool m_Visible; + bool m_SaveToMap; +}; + +class CLayerGroup +{ +public: + class CEditorMap *m_pMap; + + array m_lLayers; + + int m_OffsetX; + int m_OffsetY; + + int m_ParallaxX; + int m_ParallaxY; + + int m_UseClipping; + int m_ClipX; + int m_ClipY; + int m_ClipW; + int m_ClipH; + + const char *m_pName; + bool m_GameGroup; + bool m_Visible; + bool m_SaveToMap; + + CLayerGroup(); + ~CLayerGroup(); + + void Convert(CUIRect *pRect); + void Render(); + void MapScreen(); + void Mapping(float *pPoints); + + void GetSize(float *w, float *h); + + void DeleteLayer(int Index); + int SwapLayers(int Index0, int Index1); + + bool IsEmpty() const + { + return m_lLayers.size() == 0; + } + + void Clear() + { + m_lLayers.delete_all(); + } + + void AddLayer(CLayer *l); + + void ModifyImageIndex(INDEX_MODIFY_FUNC Func) + { + for(int i = 0; i < m_lLayers.size(); i++) + m_lLayers[i]->ModifyImageIndex(Func); + } + + void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC Func) + { + for(int i = 0; i < m_lLayers.size(); i++) + m_lLayers[i]->ModifyEnvelopeIndex(Func); + } +}; + +class CEditorImage : public CImageInfo +{ +public: + CEditor *m_pEditor; + + CEditorImage(CEditor *pEditor) + { + m_pEditor = pEditor; + m_TexID = -1; + m_aName[0] = 0; + m_External = 0; + m_Width = 0; + m_Height = 0; + m_pData = 0; + m_Format = 0; + } + + ~CEditorImage(); + + void AnalyseTileFlags(); + + int m_TexID; + int m_External; + char m_aName[128]; + unsigned char m_aTileFlags[256]; +}; + +class CEditorMap +{ + void MakeGameGroup(CLayerGroup *pGroup); + void MakeGameLayer(CLayer *pLayer); +public: + CEditor *m_pEditor; + bool m_Modified; + + CEditorMap() + { + Clean(); + } + + array m_lGroups; + array m_lImages; + array m_lEnvelopes; + + class CLayerGame *m_pGameLayer; + CLayerGroup *m_pGameGroup; + + CEnvelope *NewEnvelope(int Channels) + { + m_Modified = true; + CEnvelope *e = new CEnvelope(Channels); + m_lEnvelopes.add(e); + return e; + } + + void DeleteEnvelope(int Index); + + CLayerGroup *NewGroup() + { + m_Modified = true; + CLayerGroup *g = new CLayerGroup; + g->m_pMap = this; + m_lGroups.add(g); + return g; + } + + int SwapGroups(int Index0, int Index1) + { + if(Index0 < 0 || Index0 >= m_lGroups.size()) return Index0; + if(Index1 < 0 || Index1 >= m_lGroups.size()) return Index0; + if(Index0 == Index1) return Index0; + m_Modified = true; + swap(m_lGroups[Index0], m_lGroups[Index1]); + return Index1; + } + + void DeleteGroup(int Index) + { + if(Index < 0 || Index >= m_lGroups.size()) return; + m_Modified = true; + delete m_lGroups[Index]; + m_lGroups.remove_index(Index); + } + + void ModifyImageIndex(INDEX_MODIFY_FUNC pfnFunc) + { + m_Modified = true; + for(int i = 0; i < m_lGroups.size(); i++) + m_lGroups[i]->ModifyImageIndex(pfnFunc); + } + + void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc) + { + m_Modified = true; + for(int i = 0; i < m_lGroups.size(); i++) + m_lGroups[i]->ModifyEnvelopeIndex(pfnFunc); + } + + void Clean(); + void CreateDefault(int EntitiesTexture); + + // io + int Save(class IStorage *pStorage, const char *pFilename); + int Load(class IStorage *pStorage, const char *pFilename, int StorageType); +}; + + +struct CProperty +{ + const char *m_pName; + int m_Value; + int m_Type; + int m_Min; + int m_Max; +}; + +enum +{ + PROPTYPE_NULL=0, + PROPTYPE_BOOL, + PROPTYPE_INT_STEP, + PROPTYPE_INT_SCROLL, + PROPTYPE_COLOR, + PROPTYPE_IMAGE, + PROPTYPE_ENVELOPE, + PROPTYPE_SHIFT, +}; + +typedef struct +{ + int x, y; + int w, h; +} RECTi; + +class CLayerTiles : public CLayer +{ +public: + CLayerTiles(int w, int h); + ~CLayerTiles(); + + void Resize(int NewW, int NewH); + void Shift(int Direction); + + void MakePalette(); + virtual void Render(); + + int ConvertX(float x) const; + int ConvertY(float y) const; + void Convert(CUIRect Rect, RECTi *pOut); + void Snap(CUIRect *pRect); + void Clamp(RECTi *pRect); + + virtual void BrushSelecting(CUIRect Rect); + virtual int BrushGrab(CLayerGroup *pBrush, CUIRect Rect); + virtual void FillSelection(bool Empty, CLayer *pBrush, CUIRect Rect); + virtual void BrushDraw(CLayer *pBrush, float wx, float wy); + virtual void BrushFlipX(); + virtual void BrushFlipY(); + virtual void BrushRotate(float Amount); + + virtual void ShowInfo(); + virtual int RenderProperties(CUIRect *pToolbox); + + virtual void ModifyImageIndex(INDEX_MODIFY_FUNC pfnFunc); + virtual void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc); + + void PrepareForSave(); + + void GetSize(float *w, float *h) { *w = m_Width*32.0f; *h = m_Height*32.0f; } + + int m_TexID; + int m_Game; + int m_Image; + int m_Width; + int m_Height; + CColor m_Color; + CTile *m_pTiles; +}; + +class CLayerQuads : public CLayer +{ +public: + CLayerQuads(); + ~CLayerQuads(); + + virtual void Render(); + CQuad *NewQuad(); + + virtual void BrushSelecting(CUIRect Rect); + virtual int BrushGrab(CLayerGroup *pBrush, CUIRect Rect); + virtual void BrushPlace(CLayer *pBrush, float wx, float wy); + virtual void BrushFlipX(); + virtual void BrushFlipY(); + virtual void BrushRotate(float Amount); + + virtual int RenderProperties(CUIRect *pToolbox); + + virtual void ModifyImageIndex(INDEX_MODIFY_FUNC pfnFunc); + virtual void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc); + + void GetSize(float *w, float *h); + + int m_Image; + array m_lQuads; +}; + +class CLayerGame : public CLayerTiles +{ +public: + CLayerGame(int w, int h); + ~CLayerGame(); + + virtual int RenderProperties(CUIRect *pToolbox); +}; + +class CEditor : public IEditor +{ + class IInput *m_pInput; + class IClient *m_pClient; + class IConsole *m_pConsole; + class IGraphics *m_pGraphics; + class ITextRender *m_pTextRender; + class IStorage *m_pStorage; + CRenderTools m_RenderTools; + CUI m_UI; +public: + class IInput *Input() { return m_pInput; }; + class IClient *Client() { return m_pClient; }; + class IConsole *Console() { return m_pConsole; }; + class IGraphics *Graphics() { return m_pGraphics; }; + class ITextRender *TextRender() { return m_pTextRender; }; + class IStorage *Storage() { return m_pStorage; }; + CUI *UI() { return &m_UI; } + CRenderTools *RenderTools() { return &m_RenderTools; } + + CEditor() : m_TilesetPicker(16, 16) + { + m_pInput = 0; + m_pClient = 0; + m_pGraphics = 0; + m_pTextRender = 0; + + m_Mode = MODE_LAYERS; + m_Dialog = 0; + m_pTooltip = 0; + + m_aFileName[0] = 0; + m_aFileSaveName[0] = 0; + m_ValidSaveFilename = false; + + m_PopupEventActivated = false; + + m_FileDialogStorageType = 0; + m_pFileDialogTitle = 0; + m_pFileDialogButtonText = 0; + m_pFileDialogUser = 0; + m_aFileDialogFileName[0] = 0; + m_aFileDialogCurrentFolder[0] = 0; + m_aFileDialogCurrentLink[0] = 0; + m_pFileDialogPath = m_aFileDialogCurrentFolder; + m_aFileDialogActivate = false; + m_FileDialogScrollValue = 0.0f; + m_FilesSelectedIndex = -1; + m_FilesStartAt = 0; + m_FilesCur = 0; + m_FilesStopAt = 999; + + m_WorldOffsetX = 0; + m_WorldOffsetY = 0; + m_EditorOffsetX = 0.0f; + m_EditorOffsetY = 0.0f; + + m_WorldZoom = 1.0f; + m_ZoomLevel = 200; + m_LockMouse = false; + m_ShowMousePointer = true; + m_MouseDeltaX = 0; + m_MouseDeltaY = 0; + m_MouseDeltaWx = 0; + m_MouseDeltaWy = 0; + + m_GuiActive = true; + m_ProofBorders = false; + + m_ShowTileInfo = false; + m_ShowDetail = true; + m_Animate = false; + m_AnimateStart = 0; + m_AnimateTime = 0; + m_AnimateSpeed = 1; + + m_ShowEnvelopeEditor = 0; + + ms_CheckerTexture = 0; + ms_BackgroundTexture = 0; + ms_CursorTexture = 0; + ms_EntitiesTexture = 0; + + ms_pUiGotContext = 0; + } + + virtual void Init(); + virtual void UpdateAndRender(); + virtual bool HasUnsavedData() { return m_Map.m_Modified; } + + void FilelistPopulate(int StorageType); + void InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText, + const char *pBasepath, const char *pDefaultName, + void (*pfnFunc)(const char *pFilename, int StorageType, void *pUser), void *pUser); + + void Reset(bool CreateDefault=true); + int Save(const char *pFilename); + int Load(const char *pFilename, int StorageType); + int Append(const char *pFilename, int StorageType); + void Render(); + + CQuad *GetSelectedQuad(); + CLayer *GetSelectedLayerType(int Index, int Type); + CLayer *GetSelectedLayer(int Index); + CLayerGroup *GetSelectedGroup(); + + int DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal); + + int m_Mode; + int m_Dialog; + const char *m_pTooltip; + + char m_aFileName[512]; + char m_aFileSaveName[512]; + bool m_ValidSaveFilename; + + enum + { + POPEVENT_EXIT=0, + POPEVENT_LOAD, + POPEVENT_NEW, + POPEVENT_SAVE, + }; + + int m_PopupEventType; + int m_PopupEventActivated; + + enum + { + FILETYPE_MAP, + FILETYPE_IMG, + + MAX_PATH_LENGTH = 512 + }; + + int m_FileDialogStorageType; + const char *m_pFileDialogTitle; + const char *m_pFileDialogButtonText; + void (*m_pfnFileDialogFunc)(const char *pFileName, int StorageType, void *pUser); + void *m_pFileDialogUser; + char m_aFileDialogFileName[MAX_PATH_LENGTH]; + char m_aFileDialogCurrentFolder[MAX_PATH_LENGTH]; + char m_aFileDialogCurrentLink[MAX_PATH_LENGTH]; + char *m_pFileDialogPath; + bool m_aFileDialogActivate; + int m_FileDialogFileType; + float m_FileDialogScrollValue; + int m_FilesSelectedIndex; + char m_FileDialogNewFolderName[64]; + char m_FileDialogErrString[64]; + + struct CFilelistItem + { + char m_aFilename[128]; + char m_aName[128]; + bool m_IsDir; + bool m_IsLink; + int m_StorageType; + + bool operator<(const CFilelistItem &Other) { return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false : + m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false : + str_comp_filenames(m_aFilename, Other.m_aFilename) < 0; } + }; + sorted_array m_FileList; + int m_FilesStartAt; + int m_FilesCur; + int m_FilesStopAt; + + float m_WorldOffsetX; + float m_WorldOffsetY; + float m_EditorOffsetX; + float m_EditorOffsetY; + float m_WorldZoom; + int m_ZoomLevel; + bool m_LockMouse; + bool m_ShowMousePointer; + bool m_GuiActive; + bool m_ProofBorders; + float m_MouseDeltaX; + float m_MouseDeltaY; + float m_MouseDeltaWx; + float m_MouseDeltaWy; + + bool m_ShowTileInfo; + bool m_ShowDetail; + bool m_Animate; + int64 m_AnimateStart; + float m_AnimateTime; + float m_AnimateSpeed; + + int m_ShowEnvelopeEditor; + + int m_SelectedLayer; + int m_SelectedGroup; + int m_SelectedQuad; + int m_SelectedPoints; + int m_SelectedEnvelope; + int m_SelectedImage; + + static int ms_CheckerTexture; + static int ms_BackgroundTexture; + static int ms_CursorTexture; + static int ms_EntitiesTexture; + + CLayerGroup m_Brush; + CLayerTiles m_TilesetPicker; + + static const void *ms_pUiGotContext; + + CEditorMap m_Map; + + void DoMapBorder(); + int DoButton_Editor_Common(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); + int DoButton_Editor(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); + + int DoButton_Tab(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); + int DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners); + int DoButton_ButtonDec(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); + int DoButton_ButtonInc(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); + + int DoButton_File(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); + + int DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); + int DoButton_MenuItem(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags=0, const char *pToolTip=0); + + int DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden=false); + + void RenderBackground(CUIRect View, int Texture, float Size, float Brightness); + + void UiInvokePopupMenu(void *pID, int Flags, float X, float Y, float W, float H, int (*pfnFunc)(CEditor *pEditor, CUIRect Rect), void *pExtra=0); + void UiDoPopupMenu(); + + int UiDoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, int Current, int Min, int Max, int Step, float Scale, const char *pToolTip); + + static int PopupGroup(CEditor *pEditor, CUIRect View); + static int PopupLayer(CEditor *pEditor, CUIRect View); + static int PopupQuad(CEditor *pEditor, CUIRect View); + static int PopupPoint(CEditor *pEditor, CUIRect View); + static int PopupNewFolder(CEditor *pEditor, CUIRect View); + static int PopupEvent(CEditor *pEditor, CUIRect View); + static int PopupSelectImage(CEditor *pEditor, CUIRect View); + static int PopupSelectGametileOp(CEditor *pEditor, CUIRect View); + static int PopupImage(CEditor *pEditor, CUIRect View); + static int PopupMenuFile(CEditor *pEditor, CUIRect View); + + static void CallbackOpenMap(const char *pFileName, int StorageType, void *pUser); + static void CallbackAppendMap(const char *pFileName, int StorageType, void *pUser); + static void CallbackSaveMap(const char *pFileName, int StorageType, void *pUser); + + void PopupSelectImageInvoke(int Current, float x, float y); + int PopupSelectImageResult(); + + void PopupSelectGametileOpInvoke(float x, float y); + int PopupSelectGameTileOpResult(); + + vec4 ButtonColorMul(const void *pID); + + void DoQuadPoint(CQuad *pQuad, int QuadIndex, int v); + void DoMapEditor(CUIRect View, CUIRect Toolbar, bool ShowPicker); + void DoToolbar(CUIRect Toolbar); + void DoQuad(CQuad *pQuad, int Index); + float UiDoScrollbarV(const void *pID, const CUIRect *pRect, float Current); + vec4 GetButtonColor(const void *pID, int Checked); + + static void ReplaceImage(const char *pFilename, int StorageType, void *pUser); + static void AddImage(const char *pFilename, int StorageType, void *pUser); + + void RenderImages(CUIRect Toolbox, CUIRect Toolbar, CUIRect View); + void RenderLayers(CUIRect Toolbox, CUIRect Toolbar, CUIRect View); + void RenderModebar(CUIRect View); + void RenderStatusbar(CUIRect View); + void RenderEnvelopeEditor(CUIRect View); + + void RenderMenubar(CUIRect Menubar); + void RenderFileDialog(); + + void AddFileDialogEntry(int Index, CUIRect *pView); + void SortImages(); + static void ExtractName(const char *pFileName, char *pName, int BufferSize) + { + const char *pExtractedName = pFileName; + const char *pEnd = 0; + for(; *pFileName; ++pFileName) + { + if(*pFileName == '/' || *pFileName == '\\') + pExtractedName = pFileName+1; + else if(*pFileName == '.') + pEnd = pFileName; + } + + int Length = pEnd > pExtractedName ? min(BufferSize, (int)(pEnd-pExtractedName+1)) : BufferSize; + str_copy(pName, pExtractedName, Length); + } +}; + +// make sure to inline this function +inline class IGraphics *CLayer::Graphics() { return m_pEditor->Graphics(); } +inline class ITextRender *CLayer::TextRender() { return m_pEditor->TextRender(); } + +#endif diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp new file mode 100644 index 00000000..7207e49f --- /dev/null +++ b/src/game/editor/io.cpp @@ -0,0 +1,638 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include +#include +#include +#include +#include +#include +#include "editor.h" + +template +static int MakeVersion(int i, const T &v) +{ return (i<<16)+sizeof(T); } + +// backwards compatiblity +/* +void editor_load_old(DATAFILE *df, MAP *map) +{ + class mapres_image + { + public: + int width; + int height; + int image_data; + }; + + struct mapres_tilemap + { + int image; + int width; + int height; + int x, y; + int scale; + int data; + int main; + }; + + struct mapres_entity + { + int x, y; + int data[1]; + }; + + struct mapres_spawnpoint + { + int x, y; + }; + + struct mapres_item + { + int x, y; + int type; + }; + + struct mapres_flagstand + { + int x, y; + }; + + enum + { + MAPRES_ENTS_START=1, + MAPRES_SPAWNPOINT=1, + MAPRES_ITEM=2, + MAPRES_SPAWNPOINT_RED=3, + MAPRES_SPAWNPOINT_BLUE=4, + MAPRES_FLAGSTAND_RED=5, + MAPRES_FLAGSTAND_BLUE=6, + MAPRES_ENTS_END, + + ITEM_NULL=0, + ITEM_WEAPON_GUN=0x00010001, + ITEM_WEAPON_SHOTGUN=0x00010002, + ITEM_WEAPON_ROCKET=0x00010003, + ITEM_WEAPON_SNIPER=0x00010004, + ITEM_WEAPON_HAMMER=0x00010005, + ITEM_HEALTH =0x00020001, + ITEM_ARMOR=0x00030001, + ITEM_NINJA=0x00040001, + }; + + enum + { + MAPRES_REGISTERED=0x8000, + MAPRES_IMAGE=0x8001, + MAPRES_TILEMAP=0x8002, + MAPRES_COLLISIONMAP=0x8003, + MAPRES_TEMP_THEME=0x8fff, + }; + + // load tilemaps + int game_width = 0; + int game_height = 0; + { + int start, num; + datafile_get_type(df, MAPRES_TILEMAP, &start, &num); + for(int t = 0; t < num; t++) + { + mapres_tilemap *tmap = (mapres_tilemap *)datafile_get_item(df, start+t,0,0); + + CLayerTiles *l = new CLayerTiles(tmap->width, tmap->height); + + if(tmap->main) + { + // move game layer to correct position + for(int i = 0; i < map->groups[0]->layers.len()-1; i++) + { + if(map->groups[0]->layers[i] == pEditor->map.game_layer) + map->groups[0]->swap_layers(i, i+1); + } + + game_width = tmap->width; + game_height = tmap->height; + } + + // add new layer + map->groups[0]->add_layer(l); + + // process the data + unsigned char *src_data = (unsigned char *)datafile_get_data(df, tmap->data); + CTile *dst_data = l->tiles; + + for(int y = 0; y < tmap->height; y++) + for(int x = 0; x < tmap->width; x++, dst_data++, src_data+=2) + { + dst_data->index = src_data[0]; + dst_data->flags = src_data[1]; + } + + l->image = tmap->image; + } + } + + // load images + { + int start, count; + datafile_get_type(df, MAPRES_IMAGE, &start, &count); + for(int i = 0; i < count; i++) + { + mapres_image *imgres = (mapres_image *)datafile_get_item(df, start+i, 0, 0); + void *data = datafile_get_data(df, imgres->image_data); + + EDITOR_IMAGE *img = new EDITOR_IMAGE; + img->width = imgres->width; + img->height = imgres->height; + img->format = CImageInfo::FORMAT_RGBA; + + // copy image data + img->data = mem_alloc(img->width*img->height*4, 1); + mem_copy(img->data, data, img->width*img->height*4); + img->tex_id = Graphics()->LoadTextureRaw(img->width, img->height, img->format, img->data, CImageInfo::FORMAT_AUTO, 0); + map->images.add(img); + + // unload image + datafile_unload_data(df, imgres->image_data); + } + } + + // load entities + { + CLayerGame *g = map->game_layer; + g->resize(game_width, game_height); + for(int t = MAPRES_ENTS_START; t < MAPRES_ENTS_END; t++) + { + // fetch entities of this class + int start, num; + datafile_get_type(df, t, &start, &num); + + + for(int i = 0; i < num; i++) + { + mapres_entity *e = (mapres_entity *)datafile_get_item(df, start+i,0,0); + int x = e->x/32; + int y = e->y/32; + int id = -1; + + if(t == MAPRES_SPAWNPOINT) id = ENTITY_SPAWN; + else if(t == MAPRES_SPAWNPOINT_RED) id = ENTITY_SPAWN_RED; + else if(t == MAPRES_SPAWNPOINT_BLUE) id = ENTITY_SPAWN_BLUE; + else if(t == MAPRES_FLAGSTAND_RED) id = ENTITY_FLAGSTAND_RED; + else if(t == MAPRES_FLAGSTAND_BLUE) id = ENTITY_FLAGSTAND_BLUE; + else if(t == MAPRES_ITEM) + { + if(e->data[0] == ITEM_WEAPON_SHOTGUN) id = ENTITY_WEAPON_SHOTGUN; + else if(e->data[0] == ITEM_WEAPON_ROCKET) id = ENTITY_WEAPON_GRENADE; + else if(e->data[0] == ITEM_NINJA) id = ENTITY_POWERUP_NINJA; + else if(e->data[0] == ITEM_ARMOR) id = ENTITY_ARMOR_1; + else if(e->data[0] == ITEM_HEALTH) id = ENTITY_HEALTH_1; + } + + if(id > 0 && x >= 0 && x < g->width && y >= 0 && y < g->height) + g->tiles[y*g->width+x].index = id+ENTITY_OFFSET; + } + } + } +}*/ + +int CEditor::Save(const char *pFilename) +{ + return m_Map.Save(Kernel()->RequestInterface(), pFilename); +} + +int CEditorMap::Save(class IStorage *pStorage, const char *pFileName) +{ + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "saving to '%s'...", pFileName); + m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "editor", aBuf); + CDataFileWriter df; + if(!df.Open(pStorage, pFileName)) + { + str_format(aBuf, sizeof(aBuf), "failed to open file '%s'...", pFileName); + m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "editor", aBuf); + return 0; + } + + // save version + { + CMapItemVersion Item; + Item.m_Version = 1; + df.AddItem(MAPITEMTYPE_VERSION, 0, sizeof(Item), &Item); + } + + // save images + for(int i = 0; i < m_lImages.size(); i++) + { + CEditorImage *pImg = m_lImages[i]; + + // analyse the image for when saving (should be done when we load the image) + // TODO! + pImg->AnalyseTileFlags(); + + CMapItemImage Item; + Item.m_Version = 1; + + Item.m_Width = pImg->m_Width; + Item.m_Height = pImg->m_Height; + Item.m_External = pImg->m_External; + Item.m_ImageName = df.AddData(str_length(pImg->m_aName)+1, pImg->m_aName); + if(pImg->m_External) + Item.m_ImageData = -1; + else + Item.m_ImageData = df.AddData(Item.m_Width*Item.m_Height*4, pImg->m_pData); + df.AddItem(MAPITEMTYPE_IMAGE, i, sizeof(Item), &Item); + } + + // save layers + int LayerCount = 0, GroupCount = 0; + for(int g = 0; g < m_lGroups.size(); g++) + { + CLayerGroup *pGroup = m_lGroups[g]; + if(!pGroup->m_SaveToMap) + continue; + + CMapItemGroup GItem; + GItem.m_Version = CMapItemGroup::CURRENT_VERSION; + + GItem.m_ParallaxX = pGroup->m_ParallaxX; + GItem.m_ParallaxY = pGroup->m_ParallaxY; + GItem.m_OffsetX = pGroup->m_OffsetX; + GItem.m_OffsetY = pGroup->m_OffsetY; + GItem.m_UseClipping = pGroup->m_UseClipping; + GItem.m_ClipX = pGroup->m_ClipX; + GItem.m_ClipY = pGroup->m_ClipY; + GItem.m_ClipW = pGroup->m_ClipW; + GItem.m_ClipH = pGroup->m_ClipH; + GItem.m_StartLayer = LayerCount; + GItem.m_NumLayers = 0; + + for(int l = 0; l < pGroup->m_lLayers.size(); l++) + { + if(!pGroup->m_lLayers[l]->m_SaveToMap) + continue; + + if(pGroup->m_lLayers[l]->m_Type == LAYERTYPE_TILES) + { + m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "editor", "saving tiles layer"); + CLayerTiles *pLayer = (CLayerTiles *)pGroup->m_lLayers[l]; + pLayer->PrepareForSave(); + + CMapItemLayerTilemap Item; + Item.m_Version = 2; + + Item.m_Layer.m_Flags = pLayer->m_Flags; + Item.m_Layer.m_Type = pLayer->m_Type; + + Item.m_Color.r = pLayer->m_Color.r; + Item.m_Color.g = pLayer->m_Color.g; + Item.m_Color.b = pLayer->m_Color.b; + Item.m_Color.a = pLayer->m_Color.a; + Item.m_ColorEnv = -1; // not in use right now + Item.m_ColorEnvOffset = 0; + + Item.m_Width = pLayer->m_Width; + Item.m_Height = pLayer->m_Height; + Item.m_Flags = pLayer->m_Game; + Item.m_Image = pLayer->m_Image; + Item.m_Data = df.AddData(pLayer->m_Width*pLayer->m_Height*sizeof(CTile), pLayer->m_pTiles); + df.AddItem(MAPITEMTYPE_LAYER, LayerCount, sizeof(Item), &Item); + + GItem.m_NumLayers++; + LayerCount++; + } + else if(pGroup->m_lLayers[l]->m_Type == LAYERTYPE_QUADS) + { + m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "editor", "saving quads layer"); + CLayerQuads *pLayer = (CLayerQuads *)pGroup->m_lLayers[l]; + if(pLayer->m_lQuads.size()) + { + CMapItemLayerQuads Item; + Item.m_Version = 1; + Item.m_Layer.m_Flags = pLayer->m_Flags; + Item.m_Layer.m_Type = pLayer->m_Type; + Item.m_Image = pLayer->m_Image; + + // add the data + Item.m_NumQuads = pLayer->m_lQuads.size(); + Item.m_Data = df.AddDataSwapped(pLayer->m_lQuads.size()*sizeof(CQuad), pLayer->m_lQuads.base_ptr()); + df.AddItem(MAPITEMTYPE_LAYER, LayerCount, sizeof(Item), &Item); + + // clean up + //mem_free(quads); + + GItem.m_NumLayers++; + LayerCount++; + } + } + } + + df.AddItem(MAPITEMTYPE_GROUP, GroupCount++, sizeof(GItem), &GItem); + } + + // save envelopes + int PointCount = 0; + for(int e = 0; e < m_lEnvelopes.size(); e++) + { + CMapItemEnvelope Item; + Item.m_Version = 1; + Item.m_Channels = m_lEnvelopes[e]->m_Channels; + Item.m_StartPoint = PointCount; + Item.m_NumPoints = m_lEnvelopes[e]->m_lPoints.size(); + StrToInts(Item.m_aName, sizeof(Item.m_aName)/sizeof(int), m_lEnvelopes[e]->m_aName); + + df.AddItem(MAPITEMTYPE_ENVELOPE, e, sizeof(Item), &Item); + PointCount += Item.m_NumPoints; + } + + // save points + int TotalSize = sizeof(CEnvPoint) * PointCount; + CEnvPoint *pPoints = (CEnvPoint *)mem_alloc(TotalSize, 1); + PointCount = 0; + + for(int e = 0; e < m_lEnvelopes.size(); e++) + { + int Count = m_lEnvelopes[e]->m_lPoints.size(); + mem_copy(&pPoints[PointCount], m_lEnvelopes[e]->m_lPoints.base_ptr(), sizeof(CEnvPoint)*Count); + PointCount += Count; + } + + df.AddItem(MAPITEMTYPE_ENVPOINTS, 0, TotalSize, pPoints); + + // finish the data file + df.Finish(); + m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "editor", "saving done"); + + // send rcon.. if we can + if(m_pEditor->Client()->RconAuthed()) + { + CServerInfo CurrentServerInfo; + m_pEditor->Client()->GetServerInfo(&CurrentServerInfo); + char aMapName[128]; + m_pEditor->ExtractName(pFileName, aMapName, sizeof(aMapName)); + if(!str_comp(aMapName, CurrentServerInfo.m_aMap)) + m_pEditor->Client()->Rcon("reload"); + } + + return 1; +} + +int CEditor::Load(const char *pFileName, int StorageType) +{ + Reset(); + return m_Map.Load(Kernel()->RequestInterface(), pFileName, StorageType); +} + +int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int StorageType) +{ + CDataFileReader DataFile; + //DATAFILE *df = datafile_load(filename); + if(!DataFile.Open(pStorage, pFileName, StorageType)) + return 0; + + Clean(); + + // check version + CMapItemVersion *pItem = (CMapItemVersion *)DataFile.FindItem(MAPITEMTYPE_VERSION, 0); + if(!pItem) + { + // import old map + /*MAP old_mapstuff; + editor->reset(); + editor_load_old(df, this); + */ + } + else if(pItem->m_Version == 1) + { + //editor.reset(false); + + // load images + { + int Start, Num; + DataFile.GetType( MAPITEMTYPE_IMAGE, &Start, &Num); + for(int i = 0; i < Num; i++) + { + CMapItemImage *pItem = (CMapItemImage *)DataFile.GetItem(Start+i, 0, 0); + char *pName = (char *)DataFile.GetData(pItem->m_ImageName); + + // copy base info + CEditorImage *pImg = new CEditorImage(m_pEditor); + pImg->m_External = pItem->m_External; + + if(pItem->m_External) + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf),"mapres/%s.png", pName); + + // load external + CEditorImage ImgInfo(m_pEditor); + if(m_pEditor->Graphics()->LoadPNG(&ImgInfo, aBuf, IStorage::TYPE_ALL)) + { + *pImg = ImgInfo; + pImg->m_TexID = m_pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0); + pImg->m_External = 1; + } + } + else + { + pImg->m_Width = pItem->m_Width; + pImg->m_Height = pItem->m_Height; + pImg->m_Format = CImageInfo::FORMAT_RGBA; + + // copy image data + void *pData = DataFile.GetData(pItem->m_ImageData); + pImg->m_pData = mem_alloc(pImg->m_Width*pImg->m_Height*4, 1); + mem_copy(pImg->m_pData, pData, pImg->m_Width*pImg->m_Height*4); + pImg->m_TexID = m_pEditor->Graphics()->LoadTextureRaw(pImg->m_Width, pImg->m_Height, pImg->m_Format, pImg->m_pData, CImageInfo::FORMAT_AUTO, 0); + } + + // copy image name + if(pName) + str_copy(pImg->m_aName, pName, 128); + + m_lImages.add(pImg); + + // unload image + DataFile.UnloadData(pItem->m_ImageData); + DataFile.UnloadData(pItem->m_ImageName); + } + } + + // load groups + { + int LayersStart, LayersNum; + DataFile.GetType(MAPITEMTYPE_LAYER, &LayersStart, &LayersNum); + + int Start, Num; + DataFile.GetType(MAPITEMTYPE_GROUP, &Start, &Num); + for(int g = 0; g < Num; g++) + { + CMapItemGroup *pGItem = (CMapItemGroup *)DataFile.GetItem(Start+g, 0, 0); + + if(pGItem->m_Version < 1 || pGItem->m_Version > CMapItemGroup::CURRENT_VERSION) + continue; + + CLayerGroup *pGroup = NewGroup(); + pGroup->m_ParallaxX = pGItem->m_ParallaxX; + pGroup->m_ParallaxY = pGItem->m_ParallaxY; + pGroup->m_OffsetX = pGItem->m_OffsetX; + pGroup->m_OffsetY = pGItem->m_OffsetY; + + if(pGItem->m_Version >= 2) + { + pGroup->m_UseClipping = pGItem->m_UseClipping; + pGroup->m_ClipX = pGItem->m_ClipX; + pGroup->m_ClipY = pGItem->m_ClipY; + pGroup->m_ClipW = pGItem->m_ClipW; + pGroup->m_ClipH = pGItem->m_ClipH; + } + + for(int l = 0; l < pGItem->m_NumLayers; l++) + { + CLayer *pLayer = 0; + CMapItemLayer *pLayerItem = (CMapItemLayer *)DataFile.GetItem(LayersStart+pGItem->m_StartLayer+l, 0, 0); + if(!pLayerItem) + continue; + + if(pLayerItem->m_Type == LAYERTYPE_TILES) + { + CMapItemLayerTilemap *pTilemapItem = (CMapItemLayerTilemap *)pLayerItem; + CLayerTiles *pTiles = 0; + + if(pTilemapItem->m_Flags&1) + { + pTiles = new CLayerGame(pTilemapItem->m_Width, pTilemapItem->m_Height); + MakeGameLayer(pTiles); + MakeGameGroup(pGroup); + } + else + { + pTiles = new CLayerTiles(pTilemapItem->m_Width, pTilemapItem->m_Height); + pTiles->m_pEditor = m_pEditor; + pTiles->m_Color.r = pTilemapItem->m_Color.r; + pTiles->m_Color.g = pTilemapItem->m_Color.g; + pTiles->m_Color.b = pTilemapItem->m_Color.b; + pTiles->m_Color.a = pTilemapItem->m_Color.a; + } + + pLayer = pTiles; + + pGroup->AddLayer(pTiles); + void *pData = DataFile.GetData(pTilemapItem->m_Data); + pTiles->m_Image = pTilemapItem->m_Image; + pTiles->m_Game = pTilemapItem->m_Flags&1; + + mem_copy(pTiles->m_pTiles, pData, pTiles->m_Width*pTiles->m_Height*sizeof(CTile)); + + if(pTiles->m_Game && pTilemapItem->m_Version == MakeVersion(1, *pTilemapItem)) + { + for(int i = 0; i < pTiles->m_Width*pTiles->m_Height; i++) + { + if(pTiles->m_pTiles[i].m_Index) + pTiles->m_pTiles[i].m_Index += ENTITY_OFFSET; + } + } + + DataFile.UnloadData(pTilemapItem->m_Data); + } + else if(pLayerItem->m_Type == LAYERTYPE_QUADS) + { + CMapItemLayerQuads *pQuadsItem = (CMapItemLayerQuads *)pLayerItem; + CLayerQuads *pQuads = new CLayerQuads; + pQuads->m_pEditor = m_pEditor; + pLayer = pQuads; + pQuads->m_Image = pQuadsItem->m_Image; + if(pQuads->m_Image < -1 || pQuads->m_Image >= m_lImages.size()) + pQuads->m_Image = -1; + void *pData = DataFile.GetDataSwapped(pQuadsItem->m_Data); + pGroup->AddLayer(pQuads); + pQuads->m_lQuads.set_size(pQuadsItem->m_NumQuads); + mem_copy(pQuads->m_lQuads.base_ptr(), pData, sizeof(CQuad)*pQuadsItem->m_NumQuads); + DataFile.UnloadData(pQuadsItem->m_Data); + } + + if(pLayer) + pLayer->m_Flags = pLayerItem->m_Flags; + } + } + } + + // load envelopes + { + CEnvPoint *pPoints = 0; + + { + int Start, Num; + DataFile.GetType(MAPITEMTYPE_ENVPOINTS, &Start, &Num); + if(Num) + pPoints = (CEnvPoint *)DataFile.GetItem(Start, 0, 0); + } + + int Start, Num; + DataFile.GetType(MAPITEMTYPE_ENVELOPE, &Start, &Num); + for(int e = 0; e < Num; e++) + { + CMapItemEnvelope *pItem = (CMapItemEnvelope *)DataFile.GetItem(Start+e, 0, 0); + CEnvelope *pEnv = new CEnvelope(pItem->m_Channels); + pEnv->m_lPoints.set_size(pItem->m_NumPoints); + mem_copy(pEnv->m_lPoints.base_ptr(), &pPoints[pItem->m_StartPoint], sizeof(CEnvPoint)*pItem->m_NumPoints); + if(pItem->m_aName[0] != -1) // compatibility with old maps + IntsToStr(pItem->m_aName, sizeof(pItem->m_aName)/sizeof(int), pEnv->m_aName); + m_lEnvelopes.add(pEnv); + } + } + } + + return 1; +} + +static int gs_ModifyAddAmount = 0; +static void ModifyAdd(int *pIndex) +{ + if(*pIndex >= 0) + *pIndex += gs_ModifyAddAmount; +} + +int CEditor::Append(const char *pFileName, int StorageType) +{ + CEditorMap NewMap; + NewMap.m_pEditor = this; + + int Err; + Err = NewMap.Load(Kernel()->RequestInterface(), pFileName, StorageType); + if(!Err) + return Err; + + // modify indecies + gs_ModifyAddAmount = m_Map.m_lImages.size(); + NewMap.ModifyImageIndex(ModifyAdd); + + gs_ModifyAddAmount = m_Map.m_lEnvelopes.size(); + NewMap.ModifyEnvelopeIndex(ModifyAdd); + + // transfer images + for(int i = 0; i < NewMap.m_lImages.size(); i++) + m_Map.m_lImages.add(NewMap.m_lImages[i]); + NewMap.m_lImages.clear(); + + // transfer envelopes + for(int i = 0; i < NewMap.m_lEnvelopes.size(); i++) + m_Map.m_lEnvelopes.add(NewMap.m_lEnvelopes[i]); + NewMap.m_lEnvelopes.clear(); + + // transfer groups + + for(int i = 0; i < NewMap.m_lGroups.size(); i++) + { + if(NewMap.m_lGroups[i] == NewMap.m_pGameGroup) + delete NewMap.m_lGroups[i]; + else + { + NewMap.m_lGroups[i]->m_pMap = &m_Map; + m_Map.m_lGroups.add(NewMap.m_lGroups[i]); + } + } + NewMap.m_lGroups.clear(); + + // all done \o/ + return 0; +} diff --git a/src/game/editor/layer_game.cpp b/src/game/editor/layer_game.cpp new file mode 100644 index 00000000..f4a5fb76 --- /dev/null +++ b/src/game/editor/layer_game.cpp @@ -0,0 +1,22 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include "editor.h" + + +CLayerGame::CLayerGame(int w, int h) +: CLayerTiles(w, h) +{ + m_pTypeName = "Game"; + m_Game = 1; +} + +CLayerGame::~CLayerGame() +{ +} + +int CLayerGame::RenderProperties(CUIRect *pToolbox) +{ + int r = CLayerTiles::RenderProperties(pToolbox); + m_Image = -1; + return r; +} diff --git a/src/game/editor/layer_quads.cpp b/src/game/editor/layer_quads.cpp new file mode 100644 index 00000000..d2a8a1e5 --- /dev/null +++ b/src/game/editor/layer_quads.cpp @@ -0,0 +1,263 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include + +#include +#include + +#include "editor.h" +#include +#include +#include + +CLayerQuads::CLayerQuads() +{ + m_Type = LAYERTYPE_QUADS; + m_pTypeName = "Quads"; + m_Image = -1; +} + +CLayerQuads::~CLayerQuads() +{ +} + +static void EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser) +{ + CEditor *pEditor = (CEditor *)pUser; + if(Env < 0 || Env > pEditor->m_Map.m_lEnvelopes.size()) + { + pChannels[0] = 0; + pChannels[1] = 0; + pChannels[2] = 0; + pChannels[3] = 0; + return; + } + + CEnvelope *e = pEditor->m_Map.m_lEnvelopes[Env]; + float t = pEditor->m_AnimateTime+TimeOffset; + t *= pEditor->m_AnimateSpeed; + e->Eval(t, pChannels); +} + +void CLayerQuads::Render() +{ + Graphics()->TextureSet(-1); + if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size()) + Graphics()->TextureSet(m_pEditor->m_Map.m_lImages[m_Image]->m_TexID); + + m_pEditor->RenderTools()->RenderQuads(m_lQuads.base_ptr(), m_lQuads.size(), LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, m_pEditor); +} + +CQuad *CLayerQuads::NewQuad() +{ + m_pEditor->m_Map.m_Modified = true; + + CQuad *q = &m_lQuads[m_lQuads.add(CQuad())]; + + q->m_PosEnv = -1; + q->m_ColorEnv = -1; + q->m_PosEnvOffset = 0; + q->m_ColorEnvOffset = 0; + int x = 0, y = 0; + q->m_aPoints[0].x = x; + q->m_aPoints[0].y = y; + q->m_aPoints[1].x = x+64; + q->m_aPoints[1].y = y; + q->m_aPoints[2].x = x; + q->m_aPoints[2].y = y+64; + q->m_aPoints[3].x = x+64; + q->m_aPoints[3].y = y+64; + + q->m_aPoints[4].x = x+32; // pivot + q->m_aPoints[4].y = y+32; + + for(int i = 0; i < 5; i++) + { + q->m_aPoints[i].x <<= 10; + q->m_aPoints[i].y <<= 10; + } + + + q->m_aTexcoords[0].x = 0; + q->m_aTexcoords[0].y = 0; + + q->m_aTexcoords[1].x = 1<<10; + q->m_aTexcoords[1].y = 0; + + q->m_aTexcoords[2].x = 0; + q->m_aTexcoords[2].y = 1<<10; + + q->m_aTexcoords[3].x = 1<<10; + q->m_aTexcoords[3].y = 1<<10; + + q->m_aColors[0].r = 255; q->m_aColors[0].g = 255; q->m_aColors[0].b = 255; q->m_aColors[0].a = 255; + q->m_aColors[1].r = 255; q->m_aColors[1].g = 255; q->m_aColors[1].b = 255; q->m_aColors[1].a = 255; + q->m_aColors[2].r = 255; q->m_aColors[2].g = 255; q->m_aColors[2].b = 255; q->m_aColors[2].a = 255; + q->m_aColors[3].r = 255; q->m_aColors[3].g = 255; q->m_aColors[3].b = 255; q->m_aColors[3].a = 255; + + return q; +} + +void CLayerQuads::BrushSelecting(CUIRect Rect) +{ + // draw selection rectangle + IGraphics::CLineItem Array[4] = { + IGraphics::CLineItem(Rect.x, Rect.y, Rect.x+Rect.w, Rect.y), + IGraphics::CLineItem(Rect.x+Rect.w, Rect.y, Rect.x+Rect.w, Rect.y+Rect.h), + IGraphics::CLineItem(Rect.x+Rect.w, Rect.y+Rect.h, Rect.x, Rect.y+Rect.h), + IGraphics::CLineItem(Rect.x, Rect.y+Rect.h, Rect.x, Rect.y)}; + Graphics()->TextureSet(-1); + Graphics()->LinesBegin(); + Graphics()->LinesDraw(Array, 4); + Graphics()->LinesEnd(); +} + +int CLayerQuads::BrushGrab(CLayerGroup *pBrush, CUIRect Rect) +{ + // create new layers + CLayerQuads *pGrabbed = new CLayerQuads(); + pGrabbed->m_pEditor = m_pEditor; + pGrabbed->m_Image = m_Image; + pBrush->AddLayer(pGrabbed); + + //dbg_msg("", "%f %f %f %f", rect.x, rect.y, rect.w, rect.h); + for(int i = 0; i < m_lQuads.size(); i++) + { + CQuad *q = &m_lQuads[i]; + float px = fx2f(q->m_aPoints[4].x); + float py = fx2f(q->m_aPoints[4].y); + + if(px > Rect.x && px < Rect.x+Rect.w && py > Rect.y && py < Rect.y+Rect.h) + { + CQuad n; + n = *q; + + for(int p = 0; p < 5; p++) + { + n.m_aPoints[p].x -= f2fx(Rect.x); + n.m_aPoints[p].y -= f2fx(Rect.y); + } + + pGrabbed->m_lQuads.add(n); + } + } + + return pGrabbed->m_lQuads.size()?1:0; +} + +void CLayerQuads::BrushPlace(CLayer *pBrush, float wx, float wy) +{ + CLayerQuads *l = (CLayerQuads *)pBrush; + for(int i = 0; i < l->m_lQuads.size(); i++) + { + CQuad n = l->m_lQuads[i]; + + for(int p = 0; p < 5; p++) + { + n.m_aPoints[p].x += f2fx(wx); + n.m_aPoints[p].y += f2fx(wy); + } + + m_lQuads.add(n); + } + m_pEditor->m_Map.m_Modified = true; +} + +void CLayerQuads::BrushFlipX() +{ +} + +void CLayerQuads::BrushFlipY() +{ +} + +void Rotate(vec2 *pCenter, vec2 *pPoint, float Rotation) +{ + float x = pPoint->x - pCenter->x; + float y = pPoint->y - pCenter->y; + pPoint->x = x * cosf(Rotation) - y * sinf(Rotation) + pCenter->x; + pPoint->y = x * sinf(Rotation) + y * cosf(Rotation) + pCenter->y; +} + +void CLayerQuads::BrushRotate(float Amount) +{ + vec2 Center; + GetSize(&Center.x, &Center.y); + Center.x /= 2; + Center.y /= 2; + + for(int i = 0; i < m_lQuads.size(); i++) + { + CQuad *q = &m_lQuads[i]; + + for(int p = 0; p < 5; p++) + { + vec2 Pos(fx2f(q->m_aPoints[p].x), fx2f(q->m_aPoints[p].y)); + Rotate(&Center, &Pos, Amount); + q->m_aPoints[p].x = f2fx(Pos.x); + q->m_aPoints[p].y = f2fx(Pos.y); + } + } +} + +void CLayerQuads::GetSize(float *w, float *h) +{ + *w = 0; *h = 0; + + for(int i = 0; i < m_lQuads.size(); i++) + { + for(int p = 0; p < 5; p++) + { + *w = max(*w, fx2f(m_lQuads[i].m_aPoints[p].x)); + *h = max(*h, fx2f(m_lQuads[i].m_aPoints[p].y)); + } + } +} + +extern int gs_SelectedPoints; + +int CLayerQuads::RenderProperties(CUIRect *pToolBox) +{ + // layer props + enum + { + PROP_IMAGE=0, + NUM_PROPS, + }; + + CProperty aProps[] = { + {"Image", m_Image, PROPTYPE_IMAGE, -1, 0}, + {0}, + }; + + static int s_aIds[NUM_PROPS] = {0}; + int NewVal = 0; + int Prop = m_pEditor->DoProperties(pToolBox, aProps, s_aIds, &NewVal); + if(Prop != -1) + m_pEditor->m_Map.m_Modified = true; + + if(Prop == PROP_IMAGE) + { + if(NewVal >= 0) + m_Image = NewVal%m_pEditor->m_Map.m_lImages.size(); + else + m_Image = -1; + } + + return 0; +} + + +void CLayerQuads::ModifyImageIndex(INDEX_MODIFY_FUNC Func) +{ + Func(&m_Image); +} + +void CLayerQuads::ModifyEnvelopeIndex(INDEX_MODIFY_FUNC Func) +{ + for(int i = 0; i < m_lQuads.size(); i++) + { + Func(&m_lQuads[i].m_PosEnv); + Func(&m_lQuads[i].m_ColorEnv); + } +} diff --git a/src/game/editor/layer_tiles.cpp b/src/game/editor/layer_tiles.cpp new file mode 100644 index 00000000..db020351 --- /dev/null +++ b/src/game/editor/layer_tiles.cpp @@ -0,0 +1,460 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include + +#include +#include +#include + +#include +#include +#include "editor.h" + +#include + +CLayerTiles::CLayerTiles(int w, int h) +{ + m_Type = LAYERTYPE_TILES; + m_pTypeName = "Tiles"; + m_Width = w; + m_Height = h; + m_Image = -1; + m_TexID = -1; + m_Game = 0; + m_Color.r = 255; + m_Color.g = 255; + m_Color.b = 255; + m_Color.a = 255; + + m_pTiles = new CTile[m_Width*m_Height]; + mem_zero(m_pTiles, m_Width*m_Height*sizeof(CTile)); +} + +CLayerTiles::~CLayerTiles() +{ + delete [] m_pTiles; +} + +void CLayerTiles::PrepareForSave() +{ + for(int y = 0; y < m_Height; y++) + for(int x = 0; x < m_Width; x++) + m_pTiles[y*m_Width+x].m_Flags &= TILEFLAG_VFLIP|TILEFLAG_HFLIP|TILEFLAG_ROTATE; + + if(m_Image != -1 && m_Color.a == 255) + { + for(int y = 0; y < m_Height; y++) + for(int x = 0; x < m_Width; x++) + m_pTiles[y*m_Width+x].m_Flags |= m_pEditor->m_Map.m_lImages[m_Image]->m_aTileFlags[m_pTiles[y*m_Width+x].m_Index]; + } +} + +void CLayerTiles::MakePalette() +{ + for(int y = 0; y < m_Height; y++) + for(int x = 0; x < m_Width; x++) + m_pTiles[y*m_Width+x].m_Index = y*16+x; +} + +void CLayerTiles::Render() +{ + if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size()) + m_TexID = m_pEditor->m_Map.m_lImages[m_Image]->m_TexID; + Graphics()->TextureSet(m_TexID); + vec4 Color = vec4(m_Color.r/255.0f, m_Color.g/255.0f, m_Color.b/255.0f, m_Color.a/255.0f); + m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT); +} + +int CLayerTiles::ConvertX(float x) const { return (int)(x/32.0f); } +int CLayerTiles::ConvertY(float y) const { return (int)(y/32.0f); } + +void CLayerTiles::Convert(CUIRect Rect, RECTi *pOut) +{ + pOut->x = ConvertX(Rect.x); + pOut->y = ConvertY(Rect.y); + pOut->w = ConvertX(Rect.x+Rect.w+31) - pOut->x; + pOut->h = ConvertY(Rect.y+Rect.h+31) - pOut->y; +} + +void CLayerTiles::Snap(CUIRect *pRect) +{ + RECTi Out; + Convert(*pRect, &Out); + pRect->x = Out.x*32.0f; + pRect->y = Out.y*32.0f; + pRect->w = Out.w*32.0f; + pRect->h = Out.h*32.0f; +} + +void CLayerTiles::Clamp(RECTi *pRect) +{ + if(pRect->x < 0) + { + pRect->w += pRect->x; + pRect->x = 0; + } + + if(pRect->y < 0) + { + pRect->h += pRect->y; + pRect->y = 0; + } + + if(pRect->x+pRect->w > m_Width) + pRect->w = m_Width - pRect->x; + + if(pRect->y+pRect->h > m_Height) + pRect->h = m_Height - pRect->y; + + if(pRect->h < 0) + pRect->h = 0; + if(pRect->w < 0) + pRect->w = 0; +} + +void CLayerTiles::BrushSelecting(CUIRect Rect) +{ + Graphics()->TextureSet(-1); + m_pEditor->Graphics()->QuadsBegin(); + m_pEditor->Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f); + Snap(&Rect); + IGraphics::CQuadItem QuadItem(Rect.x, Rect.y, Rect.w, Rect.h); + m_pEditor->Graphics()->QuadsDrawTL(&QuadItem, 1); + m_pEditor->Graphics()->QuadsEnd(); + char aBuf[16]; + str_format(aBuf, sizeof(aBuf), "%d,%d", ConvertX(Rect.w), ConvertY(Rect.h)); + TextRender()->Text(0, Rect.x+3.0f, Rect.y+3.0f, 15.0f*m_pEditor->m_WorldZoom, aBuf, -1); +} + +int CLayerTiles::BrushGrab(CLayerGroup *pBrush, CUIRect Rect) +{ + RECTi r; + Convert(Rect, &r); + Clamp(&r); + + if(!r.w || !r.h) + return 0; + + // create new layers + CLayerTiles *pGrabbed = new CLayerTiles(r.w, r.h); + pGrabbed->m_pEditor = m_pEditor; + pGrabbed->m_TexID = m_TexID; + pGrabbed->m_Image = m_Image; + pGrabbed->m_Game = m_Game; + pBrush->AddLayer(pGrabbed); + + // copy the tiles + for(int y = 0; y < r.h; y++) + for(int x = 0; x < r.w; x++) + pGrabbed->m_pTiles[y*pGrabbed->m_Width+x] = m_pTiles[(r.y+y)*m_Width+(r.x+x)]; + + return 1; +} + +void CLayerTiles::FillSelection(bool Empty, CLayer *pBrush, CUIRect Rect) +{ + if(m_Readonly) + return; + + int sx = ConvertX(Rect.x); + int sy = ConvertY(Rect.y); + int w = ConvertX(Rect.w); + int h = ConvertY(Rect.h); + + CLayerTiles *pLt = static_cast(pBrush); + + for(int y = 0; y <= h; y++) + { + for(int x = 0; x <= w; x++) + { + int fx = x+sx; + int fy = y+sy; + + if(fx < 0 || fx >= m_Width || fy < 0 || fy >= m_Height) + continue; + + if(Empty) + m_pTiles[fy*m_Width+fx].m_Index = 1; + else + m_pTiles[fy*m_Width+fx] = pLt->m_pTiles[(y*pLt->m_Width + x%pLt->m_Width) % (pLt->m_Width*pLt->m_Height)]; + } + } + m_pEditor->m_Map.m_Modified = true; +} + +void CLayerTiles::BrushDraw(CLayer *pBrush, float wx, float wy) +{ + if(m_Readonly) + return; + + // + CLayerTiles *l = (CLayerTiles *)pBrush; + int sx = ConvertX(wx); + int sy = ConvertY(wy); + + for(int y = 0; y < l->m_Height; y++) + for(int x = 0; x < l->m_Width; x++) + { + int fx = x+sx; + int fy = y+sy; + if(fx<0 || fx >= m_Width || fy < 0 || fy >= m_Height) + continue; + + m_pTiles[fy*m_Width+fx] = l->m_pTiles[y*l->m_Width+x]; + } + m_pEditor->m_Map.m_Modified = true; +} + +void CLayerTiles::BrushFlipX() +{ + for(int y = 0; y < m_Height; y++) + for(int x = 0; x < m_Width/2; x++) + { + CTile Tmp = m_pTiles[y*m_Width+x]; + m_pTiles[y*m_Width+x] = m_pTiles[y*m_Width+m_Width-1-x]; + m_pTiles[y*m_Width+m_Width-1-x] = Tmp; + } + + if(!m_Game) + for(int y = 0; y < m_Height; y++) + for(int x = 0; x < m_Width; x++) + m_pTiles[y*m_Width+x].m_Flags ^= m_pTiles[y*m_Width+x].m_Flags&TILEFLAG_ROTATE ? TILEFLAG_HFLIP : TILEFLAG_VFLIP; +} + +void CLayerTiles::BrushFlipY() +{ + for(int y = 0; y < m_Height/2; y++) + for(int x = 0; x < m_Width; x++) + { + CTile Tmp = m_pTiles[y*m_Width+x]; + m_pTiles[y*m_Width+x] = m_pTiles[(m_Height-1-y)*m_Width+x]; + m_pTiles[(m_Height-1-y)*m_Width+x] = Tmp; + } + + if(!m_Game) + for(int y = 0; y < m_Height; y++) + for(int x = 0; x < m_Width; x++) + m_pTiles[y*m_Width+x].m_Flags ^= m_pTiles[y*m_Width+x].m_Flags&TILEFLAG_ROTATE ? TILEFLAG_VFLIP : TILEFLAG_HFLIP; +} + +void CLayerTiles::BrushRotate(float Amount) +{ + int Rotation = (round(360.0f*Amount/(pi*2))/90)%4; // 0=0°, 1=90°, 2=180°, 3=270° + if(Rotation < 0) + Rotation +=4; + + if(Rotation == 1 || Rotation == 3) + { + // 90° rotation + CTile *pTempData = new CTile[m_Width*m_Height]; + mem_copy(pTempData, m_pTiles, m_Width*m_Height*sizeof(CTile)); + CTile *pDst = m_pTiles; + for(int x = 0; x < m_Width; ++x) + for(int y = m_Height-1; y >= 0; --y, ++pDst) + { + *pDst = pTempData[y*m_Width+x]; + if(!m_Game) + { + if(pDst->m_Flags&TILEFLAG_ROTATE) + pDst->m_Flags ^= (TILEFLAG_HFLIP|TILEFLAG_VFLIP); + pDst->m_Flags ^= TILEFLAG_ROTATE; + } + } + + int Temp = m_Width; + m_Width = m_Height; + m_Height = Temp; + delete[] pTempData; + } + + if(Rotation == 2 || Rotation == 3) + { + BrushFlipX(); + BrushFlipY(); + } +} + +void CLayerTiles::Resize(int NewW, int NewH) +{ + CTile *pNewData = new CTile[NewW*NewH]; + mem_zero(pNewData, NewW*NewH*sizeof(CTile)); + + // copy old data + for(int y = 0; y < min(NewH, m_Height); y++) + mem_copy(&pNewData[y*NewW], &m_pTiles[y*m_Width], min(m_Width, NewW)*sizeof(CTile)); + + // replace old + delete [] m_pTiles; + m_pTiles = pNewData; + m_Width = NewW; + m_Height = NewH; +} + +void CLayerTiles::Shift(int Direction) +{ + switch(Direction) + { + case 1: + { + // left + for(int y = 0; y < m_Height; ++y) + mem_move(&m_pTiles[y*m_Width], &m_pTiles[y*m_Width+1], (m_Width-1)*sizeof(CTile)); + } + break; + case 2: + { + // right + for(int y = 0; y < m_Height; ++y) + mem_move(&m_pTiles[y*m_Width+1], &m_pTiles[y*m_Width], (m_Width-1)*sizeof(CTile)); + } + break; + case 4: + { + // up + for(int y = 0; y < m_Height-1; ++y) + mem_copy(&m_pTiles[y*m_Width], &m_pTiles[(y+1)*m_Width], m_Width*sizeof(CTile)); + } + break; + case 8: + { + // down + for(int y = m_Height-1; y > 0; --y) + mem_copy(&m_pTiles[y*m_Width], &m_pTiles[(y-1)*m_Width], m_Width*sizeof(CTile)); + } + } +} + +void CLayerTiles::ShowInfo() +{ + float ScreenX0, ScreenY0, ScreenX1, ScreenY1; + Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1); + Graphics()->TextureSet(m_pEditor->Client()->GetDebugFont()); + + int StartY = max(0, (int)(ScreenY0/32.0f)-1); + int StartX = max(0, (int)(ScreenX0/32.0f)-1); + int EndY = min((int)(ScreenY1/32.0f)+1, m_Height); + int EndX = min((int)(ScreenX1/32.0f)+1, m_Width); + + for(int y = StartY; y < EndY; y++) + for(int x = StartX; x < EndX; x++) + { + int c = x + y*m_Width; + if(m_pTiles[c].m_Index) + { + char aBuf[64]; + str_format(aBuf, sizeof(aBuf), "%i", m_pTiles[c].m_Index); + m_pEditor->Graphics()->QuadsText(x*32, y*32, 16.0f, 1,1,1,1, aBuf); + + char aFlags[4] = { m_pTiles[c].m_Flags&TILEFLAG_VFLIP ? 'V' : ' ', + m_pTiles[c].m_Flags&TILEFLAG_HFLIP ? 'H' : ' ', + m_pTiles[c].m_Flags&TILEFLAG_ROTATE? 'R' : ' ', + 0}; + m_pEditor->Graphics()->QuadsText(x*32, y*32+16, 16.0f, 1,1,1,1, aFlags); + } + x += m_pTiles[c].m_Skip; + } +} + +int CLayerTiles::RenderProperties(CUIRect *pToolBox) +{ + CUIRect Button; + pToolBox->HSplitBottom(12.0f, pToolBox, &Button); + + bool InGameGroup = !find_linear(m_pEditor->m_Map.m_pGameGroup->m_lLayers.all(), this).empty(); + if(m_pEditor->m_Map.m_pGameLayer == this) + InGameGroup = false; + + if(InGameGroup) + { + static int s_ColclButton = 0; + if(m_pEditor->DoButton_Editor(&s_ColclButton, "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(); + if(Result > -1) + { + CLayerTiles *gl = m_pEditor->m_Map.m_pGameLayer; + int w = min(gl->m_Width, m_Width); + int h = min(gl->m_Height, m_Height); + for(int y = 0; y < h; y++) + for(int x = 0; x < w; x++) + if(m_pTiles[y*m_Width+x].m_Index) + gl->m_pTiles[y*gl->m_Width+x].m_Index = TILE_AIR+Result; + + return 1; + } + } + + enum + { + PROP_WIDTH=0, + PROP_HEIGHT, + PROP_SHIFT, + PROP_IMAGE, + PROP_COLOR, + NUM_PROPS, + }; + + int Color = 0; + Color |= m_Color.r<<24; + Color |= m_Color.g<<16; + Color |= m_Color.b<<8; + Color |= m_Color.a; + + CProperty aProps[] = { + {"Width", m_Width, PROPTYPE_INT_SCROLL, 1, 1000000000}, + {"Height", m_Height, PROPTYPE_INT_SCROLL, 1, 1000000000}, + {"Shift", 0, PROPTYPE_SHIFT, 0, 0}, + {"Image", m_Image, PROPTYPE_IMAGE, 0, 0}, + {"Color", Color, PROPTYPE_COLOR, 0, 0}, + {0}, + }; + + if(m_pEditor->m_Map.m_pGameLayer == this) // remove the image and color properties if this is the game layer + { + aProps[3].m_pName = 0; + aProps[4].m_pName = 0; + } + + static int s_aIds[NUM_PROPS] = {0}; + int NewVal = 0; + int Prop = m_pEditor->DoProperties(pToolBox, aProps, s_aIds, &NewVal); + if(Prop != -1) + m_pEditor->m_Map.m_Modified = true; + + if(Prop == PROP_WIDTH && NewVal > 1) + Resize(NewVal, m_Height); + else if(Prop == PROP_HEIGHT && NewVal > 1) + Resize(m_Width, NewVal); + else if(Prop == PROP_SHIFT) + Shift(NewVal); + else if(Prop == PROP_IMAGE) + { + if (NewVal == -1) + { + m_TexID = -1; + m_Image = -1; + } + else + m_Image = NewVal%m_pEditor->m_Map.m_lImages.size(); + } + else if(Prop == 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; + } + + return 0; +} + + +void CLayerTiles::ModifyImageIndex(INDEX_MODIFY_FUNC Func) +{ + Func(&m_Image); +} + +void CLayerTiles::ModifyEnvelopeIndex(INDEX_MODIFY_FUNC Func) +{ +} diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp new file mode 100644 index 00000000..3ae29725 --- /dev/null +++ b/src/game/editor/popups.cpp @@ -0,0 +1,739 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include +#include +#include +#include +#include +#include "editor.h" + + +// popup menu handling +static struct +{ + CUIRect m_Rect; + void *m_pId; + int (*m_pfnFunc)(CEditor *pEditor, CUIRect Rect); + int m_IsMenu; + void *m_pExtra; +} s_UiPopups[8]; + +static int g_UiNumPopups = 0; + +void CEditor::UiInvokePopupMenu(void *pID, int Flags, float x, float y, float Width, float Height, int (*pfnFunc)(CEditor *pEditor, CUIRect Rect), void *pExtra) +{ + Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "editor", "invoked"); + if(x + Width > UI()->Screen()->w) + x -= Width; + if(y + Height > UI()->Screen()->h) + y -= Height; + s_UiPopups[g_UiNumPopups].m_pId = pID; + s_UiPopups[g_UiNumPopups].m_IsMenu = Flags; + s_UiPopups[g_UiNumPopups].m_Rect.x = x; + s_UiPopups[g_UiNumPopups].m_Rect.y = y; + s_UiPopups[g_UiNumPopups].m_Rect.w = Width; + s_UiPopups[g_UiNumPopups].m_Rect.h = Height; + s_UiPopups[g_UiNumPopups].m_pfnFunc = pfnFunc; + s_UiPopups[g_UiNumPopups].m_pExtra = pExtra; + g_UiNumPopups++; +} + +void CEditor::UiDoPopupMenu() +{ + for(int i = 0; i < g_UiNumPopups; i++) + { + bool Inside = UI()->MouseInside(&s_UiPopups[i].m_Rect); + UI()->SetHotItem(&s_UiPopups[i].m_pId); + + if(UI()->ActiveItem() == &s_UiPopups[i].m_pId) + { + if(!UI()->MouseButton(0)) + { + if(!Inside) + g_UiNumPopups--; + UI()->SetActiveItem(0); + } + } + else if(UI()->HotItem() == &s_UiPopups[i].m_pId) + { + if(UI()->MouseButton(0)) + UI()->SetActiveItem(&s_UiPopups[i].m_pId); + } + + int Corners = CUI::CORNER_ALL; + if(s_UiPopups[i].m_IsMenu) + Corners = CUI::CORNER_R|CUI::CORNER_B; + + CUIRect r = s_UiPopups[i].m_Rect; + RenderTools()->DrawUIRect(&r, vec4(0.5f,0.5f,0.5f,0.75f), Corners, 3.0f); + r.Margin(1.0f, &r); + RenderTools()->DrawUIRect(&r, vec4(0,0,0,0.75f), Corners, 3.0f); + r.Margin(4.0f, &r); + + if(s_UiPopups[i].m_pfnFunc(this, r)) + g_UiNumPopups--; + + if(Input()->KeyDown(KEY_ESCAPE)) + g_UiNumPopups--; + } +} + + +int CEditor::PopupGroup(CEditor *pEditor, CUIRect View) +{ + // remove group button + CUIRect Button; + View.HSplitBottom(12.0f, &View, &Button); + static int s_DeleteButton = 0; + + // don't allow deletion of game group + if(pEditor->m_Map.m_pGameGroup != pEditor->GetSelectedGroup()) + { + if(pEditor->DoButton_Editor(&s_DeleteButton, "Delete group", 0, &Button, 0, "Delete group")) + { + pEditor->m_Map.DeleteGroup(pEditor->m_SelectedGroup); + pEditor->m_SelectedGroup = max(0, pEditor->m_SelectedGroup-1); + return 1; + } + } + else + { + if(pEditor->DoButton_Editor(&s_DeleteButton, "Clean-up game tiles", 0, &Button, 0, "Removes game tiles that aren't based on a layer")) + { + // gather all tile layers + array Layers; + for(int i = 0; i < pEditor->m_Map.m_pGameGroup->m_lLayers.size(); ++i) + { + if(pEditor->m_Map.m_pGameGroup->m_lLayers[i] != pEditor->m_Map.m_pGameLayer && pEditor->m_Map.m_pGameGroup->m_lLayers[i]->m_Type == LAYERTYPE_TILES) + Layers.add(static_cast(pEditor->m_Map.m_pGameGroup->m_lLayers[i])); + } + + // search for unneeded game tiles + CLayerTiles *gl = pEditor->m_Map.m_pGameLayer; + for(int y = 0; y < gl->m_Height; ++y) + for(int x = 0; x < gl->m_Width; ++x) + { + if(gl->m_pTiles[y*gl->m_Width+x].m_Index > static_cast(TILE_NOHOOK)) + continue; + + bool Found = false; + for(int i = 0; i < Layers.size(); ++i) + { + if(x < Layers[i]->m_Width && y < Layers[i]->m_Height && Layers[i]->m_pTiles[y*Layers[i]->m_Width+x].m_Index) + { + Found = true; + break; + } + } + + if(!Found) + { + gl->m_pTiles[y*gl->m_Width+x].m_Index = TILE_AIR; + pEditor->m_Map.m_Modified = true; + } + } + + return 1; + } + } + + // new tile layer + View.HSplitBottom(10.0f, &View, &Button); + View.HSplitBottom(12.0f, &View, &Button); + static int s_NewQuadLayerButton = 0; + if(pEditor->DoButton_Editor(&s_NewQuadLayerButton, "Add quads layer", 0, &Button, 0, "Creates a new quad layer")) + { + CLayer *l = new CLayerQuads; + l->m_pEditor = pEditor; + pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->AddLayer(l); + pEditor->m_SelectedLayer = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_lLayers.size()-1; + return 1; + } + + // new quad layer + View.HSplitBottom(5.0f, &View, &Button); + View.HSplitBottom(12.0f, &View, &Button); + static int s_NewTileLayerButton = 0; + if(pEditor->DoButton_Editor(&s_NewTileLayerButton, "Add tile layer", 0, &Button, 0, "Creates a new tile layer")) + { + CLayer *l = new CLayerTiles(50, 50); + l->m_pEditor = pEditor; + pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->AddLayer(l); + pEditor->m_SelectedLayer = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_lLayers.size()-1; + return 1; + } + + 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, pEditor->m_Map.m_lGroups.size()-1}, + {"Pos X", -pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_OffsetX, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {"Pos Y", -pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_OffsetY, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {"Para X", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ParallaxX, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {"Para Y", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ParallaxY, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + + {"Use Clipping", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_UseClipping, PROPTYPE_BOOL, 0, 1}, + {"Clip X", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipX, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {"Clip Y", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipY, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {"Clip W", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipW, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {"Clip H", pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipH, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {0}, + }; + + static int s_aIds[NUM_PROPS] = {0}; + int NewVal = 0; + + // cut the properties that isn't needed + if(pEditor->GetSelectedGroup()->m_GameGroup) + aProps[PROP_POS_X].m_pName = 0; + + int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal); + if(Prop != -1) + pEditor->m_Map.m_Modified = true; + + if(Prop == PROP_ORDER) + pEditor->m_SelectedGroup = pEditor->m_Map.SwapGroups(pEditor->m_SelectedGroup, NewVal); + + // these can not be changed on the game group + if(!pEditor->GetSelectedGroup()->m_GameGroup) + { + if(Prop == PROP_PARA_X) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ParallaxX = NewVal; + else if(Prop == PROP_PARA_Y) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ParallaxY = NewVal; + else if(Prop == PROP_POS_X) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_OffsetX = -NewVal; + else if(Prop == PROP_POS_Y) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_OffsetY = -NewVal; + else if(Prop == PROP_USE_CLIPPING) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_UseClipping = NewVal; + else if(Prop == PROP_CLIP_X) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipX = NewVal; + else if(Prop == PROP_CLIP_Y) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipY = NewVal; + else if(Prop == PROP_CLIP_W) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipW = NewVal; + else if(Prop == PROP_CLIP_H) pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_ClipH = NewVal; + } + + return 0; +} + +int CEditor::PopupLayer(CEditor *pEditor, CUIRect View) +{ + // remove layer button + CUIRect Button; + View.HSplitBottom(12.0f, &View, &Button); + static int s_DeleteButton = 0; + + // don't allow deletion of game layer + if(pEditor->m_Map.m_pGameLayer != pEditor->GetSelectedLayer(0) && + pEditor->DoButton_Editor(&s_DeleteButton, "Delete layer", 0, &Button, 0, "Deletes the layer")) + { + pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->DeleteLayer(pEditor->m_SelectedLayer); + return 1; + } + + View.HSplitBottom(10.0f, &View, 0); + + CLayerGroup *pCurrentGroup = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]; + CLayer *pCurrentLayer = pEditor->GetSelectedLayer(0); + + enum + { + PROP_GROUP=0, + PROP_ORDER, + PROP_HQ, + NUM_PROPS, + }; + + CProperty aProps[] = { + {"Group", pEditor->m_SelectedGroup, PROPTYPE_INT_STEP, 0, pEditor->m_Map.m_lGroups.size()-1}, + {"Order", pEditor->m_SelectedLayer, PROPTYPE_INT_STEP, 0, pCurrentGroup->m_lLayers.size()}, + {"Detail", pCurrentLayer->m_Flags&LAYERFLAG_DETAIL, PROPTYPE_BOOL, 0, 1}, + {0}, + }; + + if(pEditor->m_Map.m_pGameLayer == pEditor->GetSelectedLayer(0)) // dont use Group and Detail from the selection if this is the game layer + { + aProps[0].m_Type = PROPTYPE_NULL; + aProps[2].m_Type = PROPTYPE_NULL; + } + + static int s_aIds[NUM_PROPS] = {0}; + int NewVal = 0; + int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal); + if(Prop != -1) + pEditor->m_Map.m_Modified = true; + + if(Prop == PROP_ORDER) + pEditor->m_SelectedLayer = pCurrentGroup->SwapLayers(pEditor->m_SelectedLayer, NewVal); + else if(Prop == PROP_GROUP && pCurrentLayer->m_Type != LAYERTYPE_GAME) + { + if(NewVal >= 0 && NewVal < pEditor->m_Map.m_lGroups.size()) + { + pCurrentGroup->m_lLayers.remove(pCurrentLayer); + pEditor->m_Map.m_lGroups[NewVal]->m_lLayers.add(pCurrentLayer); + pEditor->m_SelectedGroup = NewVal; + pEditor->m_SelectedLayer = pEditor->m_Map.m_lGroups[NewVal]->m_lLayers.size()-1; + } + } + else if(Prop == PROP_HQ) + { + pCurrentLayer->m_Flags &= ~LAYERFLAG_DETAIL; + if(NewVal) + pCurrentLayer->m_Flags |= LAYERFLAG_DETAIL; + } + + return pCurrentLayer->RenderProperties(&View); +} + +int CEditor::PopupQuad(CEditor *pEditor, CUIRect View) +{ + CQuad *pQuad = pEditor->GetSelectedQuad(); + + CUIRect Button; + + // delete button + View.HSplitBottom(12.0f, &View, &Button); + static int s_DeleteButton = 0; + if(pEditor->DoButton_Editor(&s_DeleteButton, "Delete", 0, &Button, 0, "Deletes the current quad")) + { + CLayerQuads *pLayer = (CLayerQuads *)pEditor->GetSelectedLayerType(0, LAYERTYPE_QUADS); + if(pLayer) + { + pEditor->m_Map.m_Modified = true; + pLayer->m_lQuads.remove_index(pEditor->m_SelectedQuad); + pEditor->m_SelectedQuad--; + } + return 1; + } + + // aspect ratio button + View.HSplitBottom(10.0f, &View, &Button); + View.HSplitBottom(12.0f, &View, &Button); + CLayerQuads *pLayer = (CLayerQuads *)pEditor->GetSelectedLayerType(0, LAYERTYPE_QUADS); + if(pLayer && pLayer->m_Image >= 0 && pLayer->m_Image < pEditor->m_Map.m_lImages.size()) + { + 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")) + { + int Top = pQuad->m_aPoints[0].y; + int Left = pQuad->m_aPoints[0].x; + int Right = pQuad->m_aPoints[0].x; + + for(int k = 1; k < 4; k++) + { + if(pQuad->m_aPoints[k].y < Top) Top = pQuad->m_aPoints[k].y; + if(pQuad->m_aPoints[k].x < Left) Left = pQuad->m_aPoints[k].x; + if(pQuad->m_aPoints[k].x > Right) Right = pQuad->m_aPoints[k].x; + } + + int Height = (Right-Left)*pEditor->m_Map.m_lImages[pLayer->m_Image]->m_Height/pEditor->m_Map.m_lImages[pLayer->m_Image]->m_Width; + + pQuad->m_aPoints[0].x = Left; pQuad->m_aPoints[0].y = Top; + pQuad->m_aPoints[1].x = Right; pQuad->m_aPoints[1].y = Top; + pQuad->m_aPoints[2].x = Left; pQuad->m_aPoints[2].y = Top+Height; + pQuad->m_aPoints[3].x = Right; pQuad->m_aPoints[3].y = Top+Height; + pEditor->m_Map.m_Modified = true; + return 1; + } + } + + // align button + View.HSplitBottom(6.0f, &View, &Button); + View.HSplitBottom(12.0f, &View, &Button); + static int s_AlignButton = 0; + if(pEditor->DoButton_Editor(&s_AlignButton, "Align", 0, &Button, 0, "Aligns coordinates of the quad points")) + { + for(int k = 1; k < 4; k++) + { + pQuad->m_aPoints[k].x = 1000.0f * (int(pQuad->m_aPoints[k].x) / 1000); + pQuad->m_aPoints[k].y = 1000.0f * (int(pQuad->m_aPoints[k].y) / 1000); + } + pEditor->m_Map.m_Modified = true; + return 1; + } + + // square button + View.HSplitBottom(6.0f, &View, &Button); + View.HSplitBottom(12.0f, &View, &Button); + static int s_Button = 0; + if(pEditor->DoButton_Editor(&s_Button, "Square", 0, &Button, 0, "Squares the current quad")) + { + int Top = pQuad->m_aPoints[0].y; + int Left = pQuad->m_aPoints[0].x; + int Bottom = pQuad->m_aPoints[0].y; + int Right = pQuad->m_aPoints[0].x; + + for(int k = 1; k < 4; k++) + { + if(pQuad->m_aPoints[k].y < Top) Top = pQuad->m_aPoints[k].y; + if(pQuad->m_aPoints[k].x < Left) Left = pQuad->m_aPoints[k].x; + if(pQuad->m_aPoints[k].y > Bottom) Bottom = pQuad->m_aPoints[k].y; + if(pQuad->m_aPoints[k].x > Right) Right = pQuad->m_aPoints[k].x; + } + + pQuad->m_aPoints[0].x = Left; pQuad->m_aPoints[0].y = Top; + pQuad->m_aPoints[1].x = Right; pQuad->m_aPoints[1].y = Top; + pQuad->m_aPoints[2].x = Left; pQuad->m_aPoints[2].y = Bottom; + pQuad->m_aPoints[3].x = Right; pQuad->m_aPoints[3].y = Bottom; + pEditor->m_Map.m_Modified = true; + return 1; + } + + + enum + { + PROP_POS_X=0, + PROP_POS_Y, + PROP_POS_ENV, + PROP_POS_ENV_OFFSET, + PROP_COLOR_ENV, + PROP_COLOR_ENV_OFFSET, + NUM_PROPS, + }; + + CProperty aProps[] = { + {"Pos X", pQuad->m_aPoints[4].x/1000, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {"Pos Y", pQuad->m_aPoints[4].y/1000, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {"Pos. Env", pQuad->m_PosEnv+1, PROPTYPE_INT_STEP, 0, pEditor->m_Map.m_lEnvelopes.size()+1}, + {"Pos. TO", pQuad->m_PosEnvOffset, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {"Color Env", pQuad->m_ColorEnv+1, PROPTYPE_INT_STEP, 0, pEditor->m_Map.m_lEnvelopes.size()+1}, + {"Color TO", pQuad->m_ColorEnvOffset, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + + {0}, + }; + + static int s_aIds[NUM_PROPS] = {0}; + int NewVal = 0; + int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal); + if(Prop != -1) + pEditor->m_Map.m_Modified = true; + + if(Prop == PROP_POS_X) + { + float Offset = NewVal*1000-pQuad->m_aPoints[4].x; + for(int k = 0; k < 5; ++k) + pQuad->m_aPoints[k].x += Offset; + } + if(Prop == PROP_POS_Y) + { + float Offset = NewVal*1000-pQuad->m_aPoints[4].y; + for(int k = 0; k < 5; ++k) + pQuad->m_aPoints[k].y += Offset; + } + if(Prop == PROP_POS_ENV) pQuad->m_PosEnv = clamp(NewVal-1, -1, pEditor->m_Map.m_lEnvelopes.size()-1); + if(Prop == PROP_POS_ENV_OFFSET) pQuad->m_PosEnvOffset = NewVal; + if(Prop == PROP_COLOR_ENV) pQuad->m_ColorEnv = clamp(NewVal-1, -1, pEditor->m_Map.m_lEnvelopes.size()-1); + if(Prop == PROP_COLOR_ENV_OFFSET) pQuad->m_ColorEnvOffset = NewVal; + + return 0; +} + +int CEditor::PopupPoint(CEditor *pEditor, CUIRect View) +{ + CQuad *pQuad = pEditor->GetSelectedQuad(); + + enum + { + PROP_POS_X=0, + PROP_POS_Y, + PROP_COLOR, + NUM_PROPS, + }; + + int Color = 0; + int x = 0, y = 0; + + for(int v = 0; v < 4; v++) + { + if(pEditor->m_SelectedPoints&(1<m_aColors[v].r<<24; + Color |= pQuad->m_aColors[v].g<<16; + Color |= pQuad->m_aColors[v].b<<8; + Color |= pQuad->m_aColors[v].a; + + x = pQuad->m_aPoints[v].x/1000; + y = pQuad->m_aPoints[v].y/1000; + } + } + + + CProperty aProps[] = { + {"Pos X", x, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {"Pos Y", y, PROPTYPE_INT_SCROLL, -1000000, 1000000}, + {"Color", Color, PROPTYPE_COLOR, -1, pEditor->m_Map.m_lEnvelopes.size()}, + {0}, + }; + + static int s_aIds[NUM_PROPS] = {0}; + int NewVal = 0; + int Prop = pEditor->DoProperties(&View, aProps, s_aIds, &NewVal); + if(Prop != -1) + pEditor->m_Map.m_Modified = true; + + if(Prop == PROP_POS_X) + { + for(int v = 0; v < 4; v++) + if(pEditor->m_SelectedPoints&(1<m_aPoints[v].x = NewVal*1000; + } + if(Prop == PROP_POS_Y) + { + for(int v = 0; v < 4; v++) + if(pEditor->m_SelectedPoints&(1<m_aPoints[v].y = NewVal*1000; + } + if(Prop == PROP_COLOR) + { + for(int v = 0; v < 4; v++) + { + if(pEditor->m_SelectedPoints&(1<m_aColors[v].r = (NewVal>>24)&0xff; + pQuad->m_aColors[v].g = (NewVal>>16)&0xff; + pQuad->m_aColors[v].b = (NewVal>>8)&0xff; + pQuad->m_aColors[v].a = NewVal&0xff; + } + } + } + + return 0; +} + +int CEditor::PopupNewFolder(CEditor *pEditor, CUIRect View) +{ + CUIRect Label, ButtonBar; + + // title + View.HSplitTop(10.0f, 0, &View); + View.HSplitTop(30.0f, &Label, &View); + pEditor->UI()->DoLabel(&Label, "Create new folder", 20.0f, 0); + + View.HSplitBottom(10.0f, &View, 0); + View.HSplitBottom(20.0f, &View, &ButtonBar); + + if(pEditor->m_FileDialogErrString[0] == 0) + { + // interaction box + View.HSplitBottom(40.0f, &View, 0); + View.VMargin(40.0f, &View); + View.HSplitBottom(20.0f, &View, &Label); + static int s_FolderBox = 0; + pEditor->DoEditBox(&s_FolderBox, &Label, pEditor->m_FileDialogNewFolderName, sizeof(pEditor->m_FileDialogNewFolderName), 15.0f); + View.HSplitBottom(20.0f, &View, &Label); + pEditor->UI()->DoLabel(&Label, "Name:", 10.0f, -1); + + // button bar + ButtonBar.VSplitLeft(30.0f, 0, &ButtonBar); + ButtonBar.VSplitLeft(110.0f, &Label, &ButtonBar); + static int s_CreateButton = 0; + if(pEditor->DoButton_Editor(&s_CreateButton, "Create", 0, &Label, 0, 0)) + { + // create the folder + if(*pEditor->m_FileDialogNewFolderName) + { + char aBuf[512]; + str_format(aBuf, sizeof(aBuf), "%s/%s", pEditor->m_pFileDialogPath, pEditor->m_FileDialogNewFolderName); + if(pEditor->Storage()->CreateFolder(aBuf, IStorage::TYPE_SAVE)) + { + pEditor->FilelistPopulate(IStorage::TYPE_SAVE); + return 1; + } + else + str_copy(pEditor->m_FileDialogErrString, "Unable to create the folder", sizeof(pEditor->m_FileDialogErrString)); + } + } + ButtonBar.VSplitRight(30.0f, &ButtonBar, 0); + ButtonBar.VSplitRight(110.0f, &ButtonBar, &Label); + static int s_AbortButton = 0; + if(pEditor->DoButton_Editor(&s_AbortButton, "Abort", 0, &Label, 0, 0)) + return 1; + } + else + { + // error text + View.HSplitTop(30.0f, 0, &View); + View.VMargin(40.0f, &View); + View.HSplitTop(20.0f, &Label, &View); + pEditor->UI()->DoLabel(&Label, "Error:", 10.0f, -1); + View.HSplitTop(20.0f, &Label, &View); + pEditor->UI()->DoLabel(&Label, "Unable to create the folder", 10.0f, -1, View.w); + + // button + ButtonBar.VMargin(ButtonBar.w/2.0f-55.0f, &ButtonBar); + static int s_CreateButton = 0; + if(pEditor->DoButton_Editor(&s_CreateButton, "Ok", 0, &ButtonBar, 0, 0)) + return 1; + } + + return 0; +} + +int CEditor::PopupEvent(CEditor *pEditor, CUIRect View) +{ + CUIRect Label, ButtonBar; + + // title + View.HSplitTop(10.0f, 0, &View); + View.HSplitTop(30.0f, &Label, &View); + if(pEditor->m_PopupEventType == POPEVENT_EXIT) + pEditor->UI()->DoLabel(&Label, "Exit the editor", 20.0f, 0); + else if(pEditor->m_PopupEventType == POPEVENT_LOAD) + pEditor->UI()->DoLabel(&Label, "Load map", 20.0f, 0); + else if(pEditor->m_PopupEventType == POPEVENT_NEW) + pEditor->UI()->DoLabel(&Label, "New map", 20.0f, 0); + else if(pEditor->m_PopupEventType == POPEVENT_SAVE) + pEditor->UI()->DoLabel(&Label, "Save map", 20.0f, 0); + + View.HSplitBottom(10.0f, &View, 0); + View.HSplitBottom(20.0f, &View, &ButtonBar); + + // notification text + View.HSplitTop(30.0f, 0, &View); + View.VMargin(40.0f, &View); + View.HSplitTop(20.0f, &Label, &View); + if(pEditor->m_PopupEventType == POPEVENT_EXIT) + pEditor->UI()->DoLabel(&Label, "The map contains unsaved data, you might want to save it before you exit the editor.\nContinue anyway?", 10.0f, -1, Label.w-10.0f); + else if(pEditor->m_PopupEventType == POPEVENT_LOAD) + pEditor->UI()->DoLabel(&Label, "The map contains unsaved data, you might want to save it before you load a new map.\nContinue anyway?", 10.0f, -1, Label.w-10.0f); + else if(pEditor->m_PopupEventType == POPEVENT_NEW) + pEditor->UI()->DoLabel(&Label, "The map contains unsaved data, you might want to save it before you create a new map.\nContinue anyway?", 10.0f, -1, Label.w-10.0f); + else if(pEditor->m_PopupEventType == POPEVENT_SAVE) + pEditor->UI()->DoLabel(&Label, "The file already exists.\nDo you want to overwrite the map?", 10.0f, -1); + + // button bar + ButtonBar.VSplitLeft(30.0f, 0, &ButtonBar); + ButtonBar.VSplitLeft(110.0f, &Label, &ButtonBar); + static int s_OkButton = 0; + if(pEditor->DoButton_Editor(&s_OkButton, "Ok", 0, &Label, 0, 0)) + { + if(pEditor->m_PopupEventType == POPEVENT_EXIT) + g_Config.m_ClEditor = 0; + else if(pEditor->m_PopupEventType == POPEVENT_LOAD) + pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_MAP, "Load map", "Load", "maps", "", pEditor->CallbackOpenMap, pEditor); + else if(pEditor->m_PopupEventType == POPEVENT_NEW) + { + pEditor->Reset(); + pEditor->m_aFileName[0] = 0; + } + else if(pEditor->m_PopupEventType == POPEVENT_SAVE) + pEditor->CallbackSaveMap(pEditor->m_aFileSaveName, IStorage::TYPE_SAVE, pEditor); + return 1; + } + ButtonBar.VSplitRight(30.0f, &ButtonBar, 0); + ButtonBar.VSplitRight(110.0f, &ButtonBar, &Label); + static int s_AbortButton = 0; + if(pEditor->DoButton_Editor(&s_AbortButton, "Abort", 0, &Label, 0, 0)) + return 1; + + return 0; +} + + +static int g_SelectImageSelected = -100; +static int g_SelectImageCurrent = -100; + +int CEditor::PopupSelectImage(CEditor *pEditor, CUIRect View) +{ + CUIRect ButtonBar, ImageView; + View.VSplitLeft(80.0f, &ButtonBar, &View); + View.Margin(10.0f, &ImageView); + + int ShowImage = g_SelectImageCurrent; + + for(int i = -1; i < pEditor->m_Map.m_lImages.size(); i++) + { + CUIRect Button; + ButtonBar.HSplitTop(12.0f, &Button, &ButtonBar); + ButtonBar.HSplitTop(2.0f, 0, &ButtonBar); + + if(pEditor->UI()->MouseInside(&Button)) + ShowImage = i; + + if(i == -1) + { + if(pEditor->DoButton_MenuItem(&pEditor->m_Map.m_lImages[i], "None", i==g_SelectImageCurrent, &Button)) + g_SelectImageSelected = -1; + } + else + { + if(pEditor->DoButton_MenuItem(&pEditor->m_Map.m_lImages[i], pEditor->m_Map.m_lImages[i]->m_aName, i==g_SelectImageCurrent, &Button)) + g_SelectImageSelected = i; + } + } + + if(ShowImage >= 0 && ShowImage < pEditor->m_Map.m_lImages.size()) + pEditor->Graphics()->TextureSet(pEditor->m_Map.m_lImages[ShowImage]->m_TexID); + else + pEditor->Graphics()->TextureSet(-1); + pEditor->Graphics()->QuadsBegin(); + IGraphics::CQuadItem QuadItem(ImageView.x, ImageView.y, ImageView.w, ImageView.h); + pEditor->Graphics()->QuadsDrawTL(&QuadItem, 1); + pEditor->Graphics()->QuadsEnd(); + + return 0; +} + +void CEditor::PopupSelectImageInvoke(int Current, float x, float y) +{ + static int s_SelectImagePopupId = 0; + g_SelectImageSelected = -100; + g_SelectImageCurrent = Current; + UiInvokePopupMenu(&s_SelectImagePopupId, 0, x, y, 400, 300, PopupSelectImage); +} + +int CEditor::PopupSelectImageResult() +{ + if(g_SelectImageSelected == -100) + return -100; + + g_SelectImageCurrent = g_SelectImageSelected; + g_SelectImageSelected = -100; + return g_SelectImageCurrent; +} + +static int s_GametileOpSelected = -1; + +int CEditor::PopupSelectGametileOp(CEditor *pEditor, CUIRect View) +{ + static const char *s_pButtonNames[] = { "Clear", "Collision", "Death", "Unhookable" }; + static unsigned s_NumButtons = sizeof(s_pButtonNames) / sizeof(char*); + CUIRect Button; + + for(unsigned i = 0; i < s_NumButtons; ++i) + { + View.HSplitTop(2.0f, 0, &View); + View.HSplitTop(12.0f, &Button, &View); + if(pEditor->DoButton_Editor(&s_pButtonNames[i], s_pButtonNames[i], 0, &Button, 0, 0)) + s_GametileOpSelected = i; + } + + return 0; +} + +void CEditor::PopupSelectGametileOpInvoke(float x, float y) +{ + static int s_SelectGametileOpPopupId = 0; + s_GametileOpSelected = -1; + UiInvokePopupMenu(&s_SelectGametileOpPopupId, 0, x, y, 120.0f, 70.0f, PopupSelectGametileOp); +} + +int CEditor::PopupSelectGameTileOpResult() +{ + if(s_GametileOpSelected < 0) + return -1; + + int Result = s_GametileOpSelected; + s_GametileOpSelected = -1; + return Result; +} -- cgit 1.4.1