1 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2 /* If you are missing that file, acquire a complete release at teeworlds.com. */
4 #include <base/system.h>
6 #include <engine/shared/datafile.h>
7 #include <engine/shared/config.h>
8 #include <engine/client.h>
9 #include <engine/console.h>
10 #include <engine/graphics.h>
11 #include <engine/textrender.h>
12 #include <engine/input.h>
13 #include <engine/keys.h>
14 #include <engine/storage.h>
16 #include <game/client/ui.h>
17 #include <game/gamecore.h>
18 #include <game/client/render.h>
19 #include <game/generated/client_data.h>
22 #include <game/client/lineinput.h>
24 #include <game/localization.h>
26 int CEditor::ms_CheckerTexture
;
27 int CEditor::ms_BackgroundTexture
;
28 int CEditor::ms_CursorTexture
;
29 int CEditor::ms_EntitiesTexture
;
30 const void* CEditor::ms_pUiGotContext
;
37 CEditorImage::~CEditorImage()
39 m_pEditor
->Graphics()->UnloadTexture(m_TexID
);
42 CLayerGroup::CLayerGroup()
60 CLayerGroup::~CLayerGroup()
65 void CLayerGroup::Convert(CUIRect
*pRect
)
67 pRect
->x
+= m_OffsetX
;
68 pRect
->y
+= m_OffsetY
;
71 void CLayerGroup::Mapping(float *pPoints
)
73 m_pMap
->m_pEditor
->RenderTools()->MapscreenToWorld(
74 m_pMap
->m_pEditor
->m_WorldOffsetX
, m_pMap
->m_pEditor
->m_WorldOffsetY
,
75 m_ParallaxX
/100.0f
, m_ParallaxY
/100.0f
,
77 m_pMap
->m_pEditor
->Graphics()->ScreenAspect(), m_pMap
->m_pEditor
->m_WorldZoom
, pPoints
);
79 pPoints
[0] += m_pMap
->m_pEditor
->m_EditorOffsetX
;
80 pPoints
[1] += m_pMap
->m_pEditor
->m_EditorOffsetY
;
81 pPoints
[2] += m_pMap
->m_pEditor
->m_EditorOffsetX
;
82 pPoints
[3] += m_pMap
->m_pEditor
->m_EditorOffsetY
;
85 void CLayerGroup::MapScreen()
89 m_pMap
->m_pEditor
->Graphics()->MapScreen(aPoints
[0], aPoints
[1], aPoints
[2], aPoints
[3]);
92 void CLayerGroup::Render()
95 IGraphics
*pGraphics
= m_pMap
->m_pEditor
->Graphics();
100 m_pMap
->m_pGameGroup
->Mapping(aPoints
);
101 float x0
= (m_ClipX
- aPoints
[0]) / (aPoints
[2]-aPoints
[0]);
102 float y0
= (m_ClipY
- aPoints
[1]) / (aPoints
[3]-aPoints
[1]);
103 float x1
= ((m_ClipX
+m_ClipW
) - aPoints
[0]) / (aPoints
[2]-aPoints
[0]);
104 float y1
= ((m_ClipY
+m_ClipH
) - aPoints
[1]) / (aPoints
[3]-aPoints
[1]);
106 pGraphics
->ClipEnable((int)(x0
*pGraphics
->ScreenWidth()), (int)(y0
*pGraphics
->ScreenHeight()),
107 (int)((x1
-x0
)*pGraphics
->ScreenWidth()), (int)((y1
-y0
)*pGraphics
->ScreenHeight()));
110 for(int i
= 0; i
< m_lLayers
.size(); i
++)
112 if(m_lLayers
[i
]->m_Visible
&& m_lLayers
[i
] != m_pMap
->m_pGameLayer
)
114 if(m_pMap
->m_pEditor
->m_ShowDetail
|| !(m_lLayers
[i
]->m_Flags
&LAYERFLAG_DETAIL
))
115 m_lLayers
[i
]->Render();
119 pGraphics
->ClipDisable();
122 void CLayerGroup::AddLayer(CLayer
*l
)
124 m_pMap
->m_Modified
= true;
128 void CLayerGroup::DeleteLayer(int Index
)
130 if(Index
< 0 || Index
>= m_lLayers
.size()) return;
131 delete m_lLayers
[Index
];
132 m_lLayers
.remove_index(Index
);
133 m_pMap
->m_Modified
= true;
136 void CLayerGroup::GetSize(float *w
, float *h
)
139 for(int i
= 0; i
< m_lLayers
.size(); i
++)
142 m_lLayers
[i
]->GetSize(&lw
, &lh
);
149 int CLayerGroup::SwapLayers(int Index0
, int Index1
)
151 if(Index0
< 0 || Index0
>= m_lLayers
.size()) return Index0
;
152 if(Index1
< 0 || Index1
>= m_lLayers
.size()) return Index0
;
153 if(Index0
== Index1
) return Index0
;
154 m_pMap
->m_Modified
= true;
155 swap(m_lLayers
[Index0
], m_lLayers
[Index1
]);
159 void CEditorImage::AnalyseTileFlags()
161 mem_zero(m_aTileFlags
, sizeof(m_aTileFlags
));
163 int tw
= m_Width
/16; // tilesizes
164 int th
= m_Height
/16;
167 unsigned char *pPixelData
= (unsigned char *)m_pData
;
170 for(int ty
= 0; ty
< 16; ty
++)
171 for(int tx
= 0; tx
< 16; tx
++, TileID
++)
174 for(int x
= 0; x
< tw
; x
++)
175 for(int y
= 0; y
< th
; y
++)
177 int p
= (ty
*tw
+y
)*m_Width
+ tx
*tw
+x
;
178 if(pPixelData
[p
*4+3] < 250)
186 m_aTileFlags
[TileID
] |= TILEFLAG_OPAQUE
;
192 /********************************************************
194 *********************************************************/
196 // copied from gc_menu.cpp, should be more generalized
197 //extern int ui_do_edit_box(void *id, const CUIRect *rect, char *str, int str_size, float font_size, bool hidden=false);
199 int CEditor::DoEditBox(void *pID
, const CUIRect
*pRect
, char *pStr
, unsigned StrSize
, float FontSize
, bool Hidden
)
201 int Inside
= UI()->MouseInside(pRect
);
202 bool ReturnValue
= false;
203 static int s_AtIndex
= 0;
205 if(UI()->LastActiveItem() == pID
)
207 int Len
= str_length(pStr
);
209 if(Inside
&& UI()->MouseButton(0))
211 int MxRel
= (int)(UI()->MouseX() - pRect
->x
);
213 for (int i
= 1; i
<= Len
; i
++)
215 if (TextRender()->TextWidth(0, FontSize
, pStr
, i
) + 10 > MxRel
)
226 for(int i
= 0; i
< Input()->NumEvents(); i
++)
228 Len
= str_length(pStr
);
229 ReturnValue
|= CLineInput::Manipulate(Input()->GetEvent(i
), pStr
, StrSize
, &Len
, &s_AtIndex
);
233 bool JustGotActive
= false;
235 if(UI()->ActiveItem() == pID
)
237 if(!UI()->MouseButton(0))
238 UI()->SetActiveItem(0);
240 else if(UI()->HotItem() == pID
)
242 if(UI()->MouseButton(0))
244 if (UI()->LastActiveItem() != pID
)
245 JustGotActive
= true;
246 UI()->SetActiveItem(pID
);
251 UI()->SetHotItem(pID
);
253 CUIRect Textbox
= *pRect
;
254 RenderTools()->DrawUIRect(&Textbox
, vec4(1,1,1,0.5f
), CUI::CORNER_ALL
, 3.0f
);
255 Textbox
.VMargin(3.0f
, &Textbox
);
257 const char *pDisplayStr
= pStr
;
262 unsigned s
= str_length(pStr
);
263 if(s
>= sizeof(aStars
))
264 s
= sizeof(aStars
)-1;
265 for(unsigned int i
= 0; i
< s
; ++i
)
268 pDisplayStr
= aStars
;
271 UI()->DoLabel(&Textbox
, pDisplayStr
, FontSize
, -1);
273 //TODO: make it blink
274 if(UI()->LastActiveItem() == pID
&& !JustGotActive
)
276 float w
= TextRender()->TextWidth(0, FontSize
, pDisplayStr
, s_AtIndex
);
278 Textbox
.VSplitLeft(2.0f
, 0, &Textbox
);
279 Textbox
.x
+= w
*UI()->Scale();
280 Textbox
.y
-= FontSize
/10.f
;
282 UI()->DoLabel(&Textbox
, "|", FontSize
*1.1f
, -1);
288 vec4
CEditor::ButtonColorMul(const void *pID
)
290 if(UI()->ActiveItem() == pID
)
291 return vec4(1,1,1,0.5f
);
292 else if(UI()->HotItem() == pID
)
293 return vec4(1,1,1,1.5f
);
294 return vec4(1,1,1,1);
297 float CEditor::UiDoScrollbarV(const void *pID
, const CUIRect
*pRect
, float Current
)
300 static float s_OffsetY
;
301 pRect
->HSplitTop(33, &Handle
, 0);
303 Handle
.y
+= (pRect
->h
-Handle
.h
)*Current
;
307 int Inside
= UI()->MouseInside(&Handle
);
309 if(UI()->ActiveItem() == pID
)
311 if(!UI()->MouseButton(0))
312 UI()->SetActiveItem(0);
314 float Min
= pRect
->y
;
315 float Max
= pRect
->h
-Handle
.h
;
316 float Cur
= UI()->MouseY()-s_OffsetY
;
318 if(Ret
< 0.0f
) Ret
= 0.0f
;
319 if(Ret
> 1.0f
) Ret
= 1.0f
;
321 else if(UI()->HotItem() == pID
)
323 if(UI()->MouseButton(0))
325 UI()->SetActiveItem(pID
);
326 s_OffsetY
= UI()->MouseY()-Handle
.y
;
331 UI()->SetHotItem(pID
);
335 pRect
->VMargin(5.0f
, &Rail
);
336 RenderTools()->DrawUIRect(&Rail
, vec4(1,1,1,0.25f
), 0, 0.0f
);
338 CUIRect Slider
= Handle
;
339 Slider
.w
= Rail
.x
-Slider
.x
;
340 RenderTools()->DrawUIRect(&Slider
, vec4(1,1,1,0.25f
), CUI::CORNER_L
, 2.5f
);
341 Slider
.x
= Rail
.x
+Rail
.w
;
342 RenderTools()->DrawUIRect(&Slider
, vec4(1,1,1,0.25f
), CUI::CORNER_R
, 2.5f
);
345 Slider
.Margin(5.0f
, &Slider
);
346 RenderTools()->DrawUIRect(&Slider
, vec4(1,1,1,0.25f
)*ButtonColorMul(pID
), CUI::CORNER_ALL
, 2.5f
);
351 vec4
CEditor::GetButtonColor(const void *pID
, int Checked
)
354 return vec4(0,0,0,0.5f
);
358 if(UI()->HotItem() == pID
)
359 return vec4(1,0,0,0.75f
);
360 return vec4(1,0,0,0.5f
);
363 if(UI()->HotItem() == pID
)
364 return vec4(1,1,1,0.75f
);
365 return vec4(1,1,1,0.5f
);
368 int CEditor::DoButton_Editor_Common(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
370 if(UI()->MouseInside(pRect
))
372 if(Flags
&BUTTON_CONTEXT
)
373 ms_pUiGotContext
= pID
;
375 m_pTooltip
= pToolTip
;
378 if(UI()->HotItem() == pID
&& pToolTip
)
379 m_pTooltip
= (const char *)pToolTip
;
381 return UI()->DoButtonLogic(pID
, pText
, Checked
, pRect
);
384 //return UI()->DoButton(id, text, checked, r, draw_func, 0);
388 int CEditor::DoButton_Editor(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
390 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_ALL
, 3.0f
);
391 CUIRect NewRect
= *pRect
;
392 NewRect
.y
+= NewRect
.h
/2.0f
-7.0f
;
393 float tw
= min(TextRender()->TextWidth(0, 10.0f
, pText
, -1), NewRect
.w
);
395 TextRender()->SetCursor(&Cursor
, NewRect
.x
+ NewRect
.w
/2-tw
/2, NewRect
.y
- 1.0f
, 10.0f
, TEXTFLAG_RENDER
|TEXTFLAG_STOP_AT_END
);
396 Cursor
.m_LineWidth
= NewRect
.w
;
397 TextRender()->TextEx(&Cursor
, pText
, -1);
398 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
401 int CEditor::DoButton_File(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
404 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_ALL
, 3.0f
);
408 UI()->DoLabel(&t
, pText
, 10, -1, -1);
409 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
412 int CEditor::DoButton_Menu(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
415 RenderTools()->DrawUIRect(&r
, vec4(0.5f
, 0.5f
, 0.5f
, 1.0f
), CUI::CORNER_T
, 3.0f
);
419 UI()->DoLabel(&r
, pText
, 10, -1, -1);
420 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
423 int CEditor::DoButton_MenuItem(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
425 if(UI()->HotItem() == pID
|| Checked
)
426 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_ALL
, 3.0f
);
431 TextRender()->SetCursor(&Cursor
, t
.x
, t
.y
- 1.0f
, 10.0f
, TEXTFLAG_RENDER
|TEXTFLAG_STOP_AT_END
);
432 Cursor
.m_LineWidth
= t
.w
;
433 TextRender()->TextEx(&Cursor
, pText
, -1);
434 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
437 int CEditor::DoButton_Tab(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
439 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_T
, 5.0f
);
440 CUIRect NewRect
= *pRect
;
441 NewRect
.y
+= NewRect
.h
/2.0f
-7.0f
;
442 UI()->DoLabel(&NewRect
, pText
, 10, 0, -1);
443 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
446 int CEditor::DoButton_Ex(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
, int Corners
)
448 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), Corners
, 3.0f
);
449 CUIRect NewRect
= *pRect
;
450 NewRect
.y
+= NewRect
.h
/2.0f
-7.0f
;
451 UI()->DoLabel(&NewRect
, pText
, 10, 0, -1);
452 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
455 int CEditor::DoButton_ButtonInc(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
457 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_R
, 3.0f
);
458 UI()->DoLabel(pRect
, pText
?pText
:"+", 10, 0, -1);
459 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
462 int CEditor::DoButton_ButtonDec(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
464 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_L
, 3.0f
);
465 UI()->DoLabel(pRect
, pText
?pText
:"-", 10, 0, -1);
466 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
469 void CEditor::RenderBackground(CUIRect View
, int Texture
, float Size
, float Brightness
)
471 Graphics()->TextureSet(Texture
);
472 Graphics()->BlendNormal();
473 Graphics()->QuadsBegin();
474 Graphics()->SetColor(Brightness
, Brightness
, Brightness
, 1.0f
);
475 Graphics()->QuadsSetSubset(0,0, View
.w
/Size
, View
.h
/Size
);
476 IGraphics::CQuadItem
QuadItem(View
.x
, View
.y
, View
.w
, View
.h
);
477 Graphics()->QuadsDrawTL(&QuadItem
, 1);
478 Graphics()->QuadsEnd();
481 int CEditor::UiDoValueSelector(void *pID
, CUIRect
*pRect
, const char *pLabel
, int Current
, int Min
, int Max
, int Step
, float Scale
, const char *pToolTip
)
484 static float s_Value
;
485 int Inside
= UI()->MouseInside(pRect
);
487 if(UI()->ActiveItem() == pID
)
489 if(!UI()->MouseButton(0))
492 UI()->SetActiveItem(0);
496 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
497 s_Value
+= m_MouseDeltaX
*0.05f
;
499 s_Value
+= m_MouseDeltaX
;
501 if(absolute(s_Value
) > Scale
)
503 int Count
= (int)(s_Value
/Scale
);
504 s_Value
= fmod(s_Value
, Scale
);
505 Current
+= Step
*Count
;
513 m_pTooltip
= pToolTip
;
515 else if(UI()->HotItem() == pID
)
517 if(UI()->MouseButton(0))
521 UI()->SetActiveItem(pID
);
524 m_pTooltip
= pToolTip
;
528 UI()->SetHotItem(pID
);
532 str_format(aBuf
, sizeof(aBuf
),"%s %d", pLabel
, Current
);
533 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, 0), CUI::CORNER_ALL
, 5.0f
);
534 pRect
->y
+= pRect
->h
/2.0f
-7.0f
;
535 UI()->DoLabel(pRect
, aBuf
, 10, 0, -1);
540 CLayerGroup
*CEditor::GetSelectedGroup()
542 if(m_SelectedGroup
>= 0 && m_SelectedGroup
< m_Map
.m_lGroups
.size())
543 return m_Map
.m_lGroups
[m_SelectedGroup
];
547 CLayer
*CEditor::GetSelectedLayer(int Index
)
549 CLayerGroup
*pGroup
= GetSelectedGroup();
553 if(m_SelectedLayer
>= 0 && m_SelectedLayer
< m_Map
.m_lGroups
[m_SelectedGroup
]->m_lLayers
.size())
554 return pGroup
->m_lLayers
[m_SelectedLayer
];
558 CLayer
*CEditor::GetSelectedLayerType(int Index
, int Type
)
560 CLayer
*p
= GetSelectedLayer(Index
);
561 if(p
&& p
->m_Type
== Type
)
566 CQuad
*CEditor::GetSelectedQuad()
568 CLayerQuads
*ql
= (CLayerQuads
*)GetSelectedLayerType(0, LAYERTYPE_QUADS
);
571 if(m_SelectedQuad
>= 0 && m_SelectedQuad
< ql
->m_lQuads
.size())
572 return &ql
->m_lQuads
[m_SelectedQuad
];
576 void CEditor::CallbackOpenMap(const char *pFileName
, int StorageType
, void *pUser
)
578 CEditor
*pEditor
= (CEditor
*)pUser
;
579 if(pEditor
->Load(pFileName
, StorageType
))
581 str_copy(pEditor
->m_aFileName
, pFileName
, 512);
582 pEditor
->m_ValidSaveFilename
= StorageType
== IStorage::TYPE_SAVE
&& pEditor
->m_pFileDialogPath
== pEditor
->m_aFileDialogCurrentFolder
;
583 pEditor
->SortImages();
584 pEditor
->m_Dialog
= DIALOG_NONE
;
585 pEditor
->m_Map
.m_Modified
= false;
588 void CEditor::CallbackAppendMap(const char *pFileName
, int StorageType
, void *pUser
)
590 CEditor
*pEditor
= (CEditor
*)pUser
;
591 if(pEditor
->Append(pFileName
, StorageType
))
592 pEditor
->m_aFileName
[0] = 0;
594 pEditor
->SortImages();
596 pEditor
->m_Dialog
= DIALOG_NONE
;
598 void CEditor::CallbackSaveMap(const char *pFileName
, int StorageType
, void *pUser
)
600 CEditor
*pEditor
= static_cast<CEditor
*>(pUser
);
602 const int Length
= str_length(pFileName
);
604 if(Length
<= 4 || pFileName
[Length
-4] != '.' || str_comp_nocase(pFileName
+Length
-3, "map"))
606 str_format(aBuf
, sizeof(aBuf
), "%s.map", pFileName
);
610 if(pEditor
->Save(pFileName
))
612 str_copy(pEditor
->m_aFileName
, pFileName
, sizeof(pEditor
->m_aFileName
));
613 pEditor
->m_ValidSaveFilename
= StorageType
== IStorage::TYPE_SAVE
&& pEditor
->m_pFileDialogPath
== pEditor
->m_aFileDialogCurrentFolder
;
614 pEditor
->m_Map
.m_Modified
= false;
617 pEditor
->m_Dialog
= DIALOG_NONE
;
620 void CEditor::DoToolbar(CUIRect ToolBar
)
622 CUIRect TB_Top
, TB_Bottom
;
625 ToolBar
.HSplitTop(ToolBar
.h
/2.0f
, &TB_Top
, &TB_Bottom
);
627 TB_Top
.HSplitBottom(2.5f
, &TB_Top
, 0);
628 TB_Bottom
.HSplitTop(2.5f
, 0, &TB_Bottom
);
631 if(Input()->KeyDown('o') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
)))
635 m_PopupEventType
= POPEVENT_LOAD
;
636 m_PopupEventActivated
= true;
639 InvokeFileDialog(IStorage::TYPE_ALL
, FILETYPE_MAP
, "Load map", "Load", "maps", "", CallbackOpenMap
, this);
643 if(Input()->KeyDown('s') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
)))
645 if(m_aFileName
[0] && m_ValidSaveFilename
)
647 str_copy(m_aFileSaveName
, m_aFileName
, sizeof(m_aFileSaveName
));
648 m_PopupEventType
= POPEVENT_SAVE
;
649 m_PopupEventActivated
= true;
652 InvokeFileDialog(IStorage::TYPE_SAVE
, FILETYPE_MAP
, "Save map", "Save", "maps", "", CallbackSaveMap
, this);
656 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
657 static int s_HqButton
= 0;
658 if(DoButton_Editor(&s_HqButton
, "HD", m_ShowDetail
, &Button
, 0, "[ctrl+h] Toggle High Detail") ||
659 (Input()->KeyDown('h') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
))))
661 m_ShowDetail
= !m_ShowDetail
;
664 TB_Top
.VSplitLeft(5.0f
, 0, &TB_Top
);
667 TB_Top
.VSplitLeft(40.0f
, &Button
, &TB_Top
);
668 static int s_AnimateButton
= 0;
669 if(DoButton_Editor(&s_AnimateButton
, "Anim", m_Animate
, &Button
, 0, "[ctrl+m] Toggle animation") ||
670 (Input()->KeyDown('m') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
))))
672 m_AnimateStart
= time_get();
673 m_Animate
= !m_Animate
;
676 TB_Top
.VSplitLeft(5.0f
, 0, &TB_Top
);
679 TB_Top
.VSplitLeft(40.0f
, &Button
, &TB_Top
);
680 static int s_ProofButton
= 0;
681 if(DoButton_Editor(&s_ProofButton
, "Proof", m_ProofBorders
, &Button
, 0, "[ctrl+p] Toggles proof borders. These borders represent what a player maximum can see.") ||
682 (Input()->KeyDown('p') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
))))
684 m_ProofBorders
= !m_ProofBorders
;
687 TB_Top
.VSplitLeft(5.0f
, 0, &TB_Top
);
690 TB_Top
.VSplitLeft(40.0f
, &Button
, &TB_Top
);
691 static int s_TileInfoButton
= 0;
692 if(DoButton_Editor(&s_TileInfoButton
, "Info", m_ShowTileInfo
, &Button
, 0, "[ctrl+i] Show tile informations") ||
693 (Input()->KeyDown('i') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
))))
695 m_ShowTileInfo
= !m_ShowTileInfo
;
698 TB_Top
.VSplitLeft(15.0f
, 0, &TB_Top
);
701 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
702 static int s_ZoomOutButton
= 0;
703 if(DoButton_Ex(&s_ZoomOutButton
, "ZO", 0, &Button
, 0, "[NumPad-] Zoom out", CUI::CORNER_L
) || Input()->KeyDown(KEY_KP_MINUS
))
706 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
707 static int s_ZoomNormalButton
= 0;
708 if(DoButton_Ex(&s_ZoomNormalButton
, "1:1", 0, &Button
, 0, "[NumPad*] Zoom to normal and remove editor offset", 0) || Input()->KeyDown(KEY_KP_MULTIPLY
))
715 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
716 static int s_ZoomInButton
= 0;
717 if(DoButton_Ex(&s_ZoomInButton
, "ZI", 0, &Button
, 0, "[NumPad+] Zoom in", CUI::CORNER_R
) || Input()->KeyDown(KEY_KP_PLUS
))
720 TB_Top
.VSplitLeft(10.0f
, 0, &TB_Top
);
723 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
724 static int s_AnimFasterButton
= 0;
725 if(DoButton_Ex(&s_AnimFasterButton
, "A+", 0, &Button
, 0, "Increase animation speed", CUI::CORNER_L
))
726 m_AnimateSpeed
+= 0.5f
;
728 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
729 static int s_AnimNormalButton
= 0;
730 if(DoButton_Ex(&s_AnimNormalButton
, "1", 0, &Button
, 0, "Normal animation speed", 0))
731 m_AnimateSpeed
= 1.0f
;
733 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
734 static int s_AnimSlowerButton
= 0;
735 if(DoButton_Ex(&s_AnimSlowerButton
, "A-", 0, &Button
, 0, "Decrease animation speed", CUI::CORNER_R
))
737 if(m_AnimateSpeed
> 0.5f
)
738 m_AnimateSpeed
-= 0.5f
;
741 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP
) && m_Dialog
== DIALOG_NONE
)
744 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN
) && m_Dialog
== DIALOG_NONE
)
747 m_ZoomLevel
= clamp(m_ZoomLevel
, 50, 2000);
748 m_WorldZoom
= m_ZoomLevel
/100.0f
;
750 TB_Top
.VSplitLeft(10.0f
, &Button
, &TB_Top
);
753 // brush manipulation
755 int Enabled
= m_Brush
.IsEmpty()?-1:0;
758 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
759 static int s_FlipXButton
= 0;
760 if(DoButton_Ex(&s_FlipXButton
, "X/X", Enabled
, &Button
, 0, "[N] Flip brush horizontal", CUI::CORNER_L
) || Input()->KeyDown('n'))
762 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
763 m_Brush
.m_lLayers
[i
]->BrushFlipX();
766 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
767 static int s_FlipyButton
= 0;
768 if(DoButton_Ex(&s_FlipyButton
, "Y/Y", Enabled
, &Button
, 0, "[M] Flip brush vertical", CUI::CORNER_R
) || Input()->KeyDown('m'))
770 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
771 m_Brush
.m_lLayers
[i
]->BrushFlipY();
775 TB_Top
.VSplitLeft(15.0f
, &Button
, &TB_Top
);
777 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
778 static int s_RotationAmount
= 90;
779 bool TileLayer
= false;
780 // check for tile layers in brush selection
781 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
782 if(m_Brush
.m_lLayers
[i
]->m_Type
== LAYERTYPE_TILES
)
785 s_RotationAmount
= max(90, (s_RotationAmount
/90)*90);
788 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.");
790 TB_Top
.VSplitLeft(5.0f
, &Button
, &TB_Top
);
791 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
792 static int s_CcwButton
= 0;
793 if(DoButton_Ex(&s_CcwButton
, "CCW", Enabled
, &Button
, 0, "[R] Rotates the brush counter clockwise", CUI::CORNER_L
) || Input()->KeyDown('r'))
795 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
796 m_Brush
.m_lLayers
[i
]->BrushRotate(-s_RotationAmount
/360.0f
*pi
*2);
799 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
800 static int s_CwButton
= 0;
801 if(DoButton_Ex(&s_CwButton
, "CW", Enabled
, &Button
, 0, "[T] Rotates the brush clockwise", CUI::CORNER_R
) || Input()->KeyDown('t'))
803 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
804 m_Brush
.m_lLayers
[i
]->BrushRotate(s_RotationAmount
/360.0f
*pi
*2);
811 TB_Top
.VSplitLeft(10.0f
, &Button
, &TB_Top
);
812 TB_Top
.VSplitLeft(60.0f
, &Button
, &TB_Top
);
813 static int s_NewButton
= 0;
815 CLayerQuads
*pQLayer
= (CLayerQuads
*)GetSelectedLayerType(0, LAYERTYPE_QUADS
);
816 //CLayerTiles *tlayer = (CLayerTiles *)get_selected_layer_type(0, LAYERTYPE_TILES);
817 if(DoButton_Editor(&s_NewButton
, "Add Quad", pQLayer
?0:-1, &Button
, 0, "Adds a new quad"))
822 CLayerGroup
*g
= GetSelectedGroup();
824 int AddX
= f2fx(Mapping
[0] + (Mapping
[2]-Mapping
[0])/2);
825 int AddY
= f2fx(Mapping
[1] + (Mapping
[3]-Mapping
[1])/2);
827 CQuad
*q
= pQLayer
->NewQuad();
828 for(int i
= 0; i
< 5; i
++)
830 q
->m_aPoints
[i
].x
+= AddX
;
831 q
->m_aPoints
[i
].y
+= AddY
;
839 TB_Bottom
.VSplitLeft(40.0f
, &Button
, &TB_Bottom
);
840 static int s_BorderBut
= 0;
841 CLayerTiles
*pT
= (CLayerTiles
*)GetSelectedLayerType(0, LAYERTYPE_TILES
);
843 if(DoButton_Editor(&s_BorderBut
, "Border", pT
?0:-1, &Button
, 0, "Adds border tiles"))
850 TB_Bottom
.VSplitLeft(5.0f
, 0, &TB_Bottom
);
853 TB_Bottom
.VSplitLeft(50.0f
, &Button
, &TB_Bottom
);
854 static int s_RefocusButton
= 0;
855 if(DoButton_Editor(&s_RefocusButton
, "Refocus", m_WorldOffsetX
&&m_WorldOffsetY
?0:-1, &Button
, 0, "[HOME] Restore map focus") || Input()->KeyDown(KEY_HOME
))
862 static void Rotate(CPoint
*pCenter
, CPoint
*pPoint
, float Rotation
)
864 int x
= pPoint
->x
- pCenter
->x
;
865 int y
= pPoint
->y
- pCenter
->y
;
866 pPoint
->x
= (int)(x
* cosf(Rotation
) - y
* sinf(Rotation
) + pCenter
->x
);
867 pPoint
->y
= (int)(x
* sinf(Rotation
) + y
* cosf(Rotation
) + pCenter
->y
);
870 void CEditor::DoQuad(CQuad
*q
, int Index
)
882 void *pID
= &q
->m_aPoints
[4]; // use pivot addr as id
883 static CPoint s_RotatePoints
[4];
884 static float s_LastWx
;
885 static float s_LastWy
;
886 static int s_Operation
= OP_NONE
;
887 static float s_RotateAngle
= 0;
888 float wx
= UI()->MouseWorldX();
889 float wy
= UI()->MouseWorldY();
892 float CenterX
= fx2f(q
->m_aPoints
[4].x
);
893 float CenterY
= fx2f(q
->m_aPoints
[4].y
);
895 float dx
= (CenterX
- wx
)/m_WorldZoom
;
896 float dy
= (CenterY
- wy
)/m_WorldZoom
;
898 UI()->SetHotItem(pID
);
900 // draw selection background
901 if(m_SelectedQuad
== Index
)
903 Graphics()->SetColor(0,0,0,1);
904 IGraphics::CQuadItem
QuadItem(CenterX
, CenterY
, 7.0f
, 7.0f
);
905 Graphics()->QuadsDraw(&QuadItem
, 1);
908 if(UI()->ActiveItem() == pID
)
910 // check if we only should move pivot
911 if(s_Operation
== OP_MOVE_PIVOT
)
913 q
->m_aPoints
[4].x
+= f2fx(wx
-s_LastWx
);
914 q
->m_aPoints
[4].y
+= f2fx(wy
-s_LastWy
);
916 else if(s_Operation
== OP_MOVE_ALL
)
918 // move all points including pivot
919 for(int v
= 0; v
< 5; v
++)
921 q
->m_aPoints
[v
].x
+= f2fx(wx
-s_LastWx
);
922 q
->m_aPoints
[v
].y
+= f2fx(wy
-s_LastWy
);
925 else if(s_Operation
== OP_ROTATE
)
927 for(int v
= 0; v
< 4; v
++)
929 q
->m_aPoints
[v
] = s_RotatePoints
[v
];
930 Rotate(&q
->m_aPoints
[4], &q
->m_aPoints
[v
], s_RotateAngle
);
934 s_RotateAngle
+= (m_MouseDeltaX
) * 0.002f
;
938 if(s_Operation
== OP_CONTEXT_MENU
)
940 if(!UI()->MouseButton(1))
942 static int s_QuadPopupID
= 0;
943 UiInvokePopupMenu(&s_QuadPopupID
, 0, UI()->MouseX(), UI()->MouseY(), 120, 180, PopupQuad
);
945 s_Operation
= OP_NONE
;
946 UI()->SetActiveItem(0);
951 if(!UI()->MouseButton(0))
954 s_Operation
= OP_NONE
;
955 UI()->SetActiveItem(0);
959 Graphics()->SetColor(1,1,1,1);
961 else if(UI()->HotItem() == pID
)
963 ms_pUiGotContext
= pID
;
965 Graphics()->SetColor(1,1,1,1);
966 m_pTooltip
= "Left mouse button to move. Hold shift to move pivot. Hold ctrl to rotate.";
968 if(UI()->MouseButton(0))
970 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
971 s_Operation
= OP_MOVE_PIVOT
;
972 else if(Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
))
975 s_Operation
= OP_ROTATE
;
977 s_RotatePoints
[0] = q
->m_aPoints
[0];
978 s_RotatePoints
[1] = q
->m_aPoints
[1];
979 s_RotatePoints
[2] = q
->m_aPoints
[2];
980 s_RotatePoints
[3] = q
->m_aPoints
[3];
983 s_Operation
= OP_MOVE_ALL
;
985 UI()->SetActiveItem(pID
);
986 m_SelectedQuad
= Index
;
991 if(UI()->MouseButton(1))
993 m_SelectedQuad
= Index
;
994 s_Operation
= OP_CONTEXT_MENU
;
995 UI()->SetActiveItem(pID
);
999 Graphics()->SetColor(0,1,0,1);
1001 IGraphics::CQuadItem
QuadItem(CenterX
, CenterY
, 5.0f
*m_WorldZoom
, 5.0f
*m_WorldZoom
);
1002 Graphics()->QuadsDraw(&QuadItem
, 1);
1005 void CEditor::DoQuadPoint(CQuad
*pQuad
, int QuadIndex
, int V
)
1007 void *pID
= &pQuad
->m_aPoints
[V
];
1009 float wx
= UI()->MouseWorldX();
1010 float wy
= UI()->MouseWorldY();
1012 float px
= fx2f(pQuad
->m_aPoints
[V
].x
);
1013 float py
= fx2f(pQuad
->m_aPoints
[V
].y
);
1015 float dx
= (px
- wx
)/m_WorldZoom
;
1016 float dy
= (py
- wy
)/m_WorldZoom
;
1017 if(dx
*dx
+dy
*dy
< 50)
1018 UI()->SetHotItem(pID
);
1020 // draw selection background
1021 if(m_SelectedQuad
== QuadIndex
&& m_SelectedPoints
&(1<<V
))
1023 Graphics()->SetColor(0,0,0,1);
1024 IGraphics::CQuadItem
QuadItem(px
, py
, 7.0f
, 7.0f
);
1025 Graphics()->QuadsDraw(&QuadItem
, 1);
1036 static bool s_Moved
;
1037 static int s_Operation
= OP_NONE
;
1039 if(UI()->ActiveItem() == pID
)
1041 float dx
= m_MouseDeltaWx
;
1042 float dy
= m_MouseDeltaWy
;
1045 if(dx
*dx
+dy
*dy
> 0.5f
)
1051 if(s_Operation
== OP_MOVEPOINT
)
1053 for(int m
= 0; m
< 4; m
++)
1054 if(m_SelectedPoints
&(1<<m
))
1056 pQuad
->m_aPoints
[m
].x
+= f2fx(dx
);
1057 pQuad
->m_aPoints
[m
].y
+= f2fx(dy
);
1060 else if(s_Operation
== OP_MOVEUV
)
1062 for(int m
= 0; m
< 4; m
++)
1063 if(m_SelectedPoints
&(1<<m
))
1068 pQuad
->m_aTexcoords
[m
].x
+= f2fx(dx
*0.001f
);
1069 pQuad
->m_aTexcoords
[(m
+2)%4].x
+= f2fx(dx
*0.001f
);
1071 pQuad
->m_aTexcoords
[m
].y
+= f2fx(dy
*0.001f
);
1072 pQuad
->m_aTexcoords
[m
^1].y
+= f2fx(dy
*0.001f
);
1077 if(s_Operation
== OP_CONTEXT_MENU
)
1079 if(!UI()->MouseButton(1))
1081 static int s_PointPopupID
= 0;
1082 UiInvokePopupMenu(&s_PointPopupID
, 0, UI()->MouseX(), UI()->MouseY(), 120, 150, PopupPoint
);
1083 UI()->SetActiveItem(0);
1088 if(!UI()->MouseButton(0))
1092 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
1093 m_SelectedPoints
^= 1<<V
;
1095 m_SelectedPoints
= 1<<V
;
1097 m_LockMouse
= false;
1098 UI()->SetActiveItem(0);
1102 Graphics()->SetColor(1,1,1,1);
1104 else if(UI()->HotItem() == pID
)
1106 ms_pUiGotContext
= pID
;
1108 Graphics()->SetColor(1,1,1,1);
1109 m_pTooltip
= "Left mouse button to move. Hold shift to move the texture.";
1111 if(UI()->MouseButton(0))
1113 UI()->SetActiveItem(pID
);
1115 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
1117 s_Operation
= OP_MOVEUV
;
1121 s_Operation
= OP_MOVEPOINT
;
1123 if(!(m_SelectedPoints
&(1<<V
)))
1125 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
1126 m_SelectedPoints
|= 1<<V
;
1128 m_SelectedPoints
= 1<<V
;
1132 m_SelectedQuad
= QuadIndex
;
1134 else if(UI()->MouseButton(1))
1136 s_Operation
= OP_CONTEXT_MENU
;
1137 m_SelectedQuad
= QuadIndex
;
1138 UI()->SetActiveItem(pID
);
1139 if(!(m_SelectedPoints
&(1<<V
)))
1141 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
1142 m_SelectedPoints
|= 1<<V
;
1144 m_SelectedPoints
= 1<<V
;
1150 Graphics()->SetColor(1,0,0,1);
1152 IGraphics::CQuadItem
QuadItem(px
, py
, 5.0f
*m_WorldZoom
, 5.0f
*m_WorldZoom
);
1153 Graphics()->QuadsDraw(&QuadItem
, 1);
1156 void CEditor::DoMapEditor(CUIRect View
, CUIRect ToolBar
)
1158 // render all good stuff
1161 for(int g
= 0; g
< m_Map
.m_lGroups
.size(); g
++)
1163 if(m_Map
.m_lGroups
[g
]->m_Visible
)
1164 m_Map
.m_lGroups
[g
]->Render();
1165 //UI()->ClipEnable(&view);
1168 // render the game above everything else
1169 if(m_Map
.m_pGameGroup
->m_Visible
&& m_Map
.m_pGameLayer
->m_Visible
)
1171 m_Map
.m_pGameGroup
->MapScreen();
1172 m_Map
.m_pGameLayer
->Render();
1175 CLayerTiles
*pT
= static_cast<CLayerTiles
*>(GetSelectedLayerType(0, LAYERTYPE_TILES
));
1176 if(m_ShowTileInfo
&& pT
&& pT
->m_Visible
&& m_ZoomLevel
<= 300)
1178 GetSelectedGroup()->MapScreen();
1183 static void *s_pEditorID
= (void *)&s_pEditorID
;
1184 int Inside
= UI()->MouseInside(&View
);
1186 // fetch mouse position
1187 float wx
= UI()->MouseWorldX();
1188 float wy
= UI()->MouseWorldY();
1189 float mx
= UI()->MouseX();
1190 float my
= UI()->MouseY();
1192 static float s_StartWx
= 0;
1193 static float s_StartWy
= 0;
1205 // remap the screen so it can display the whole tileset
1208 CUIRect Screen
= *UI()->Screen();
1209 float Size
= 32.0*16.0f
;
1210 float w
= Size
*(Screen
.w
/View
.w
);
1211 float h
= Size
*(Screen
.h
/View
.h
);
1212 float x
= -(View
.x
/Screen
.w
)*w
;
1213 float y
= -(View
.y
/Screen
.h
)*h
;
1214 wx
= x
+w
*mx
/Screen
.w
;
1215 wy
= y
+h
*my
/Screen
.h
;
1216 Graphics()->MapScreen(x
, y
, x
+w
, y
+h
);
1217 CLayerTiles
*t
= (CLayerTiles
*)GetSelectedLayerType(0, LAYERTYPE_TILES
);
1220 m_TilesetPicker
.m_Image
= t
->m_Image
;
1221 m_TilesetPicker
.m_TexID
= t
->m_TexID
;
1222 m_TilesetPicker
.Render();
1224 m_TilesetPicker
.ShowInfo();
1228 static int s_Operation
= OP_NONE
;
1230 // draw layer borders
1231 CLayer
*pEditLayers
[16];
1232 int NumEditLayers
= 0;
1237 pEditLayers
[0] = &m_TilesetPicker
;
1242 pEditLayers
[0] = GetSelectedLayer(0);
1246 CLayerGroup
*g
= GetSelectedGroup();
1251 for(int i
= 0; i
< NumEditLayers
; i
++)
1253 if(pEditLayers
[i
]->m_Type
!= LAYERTYPE_TILES
)
1257 pEditLayers
[i
]->GetSize(&w
, &h
);
1259 IGraphics::CLineItem Array
[4] = {
1260 IGraphics::CLineItem(0, 0, w
, 0),
1261 IGraphics::CLineItem(w
, 0, w
, h
),
1262 IGraphics::CLineItem(w
, h
, 0, h
),
1263 IGraphics::CLineItem(0, h
, 0, 0)};
1264 Graphics()->TextureSet(-1);
1265 Graphics()->LinesBegin();
1266 Graphics()->LinesDraw(Array
, 4);
1267 Graphics()->LinesEnd();
1274 UI()->SetHotItem(s_pEditorID
);
1276 // do global operations like pan and zoom
1277 if(UI()->ActiveItem() == 0 && (UI()->MouseButton(0) || UI()->MouseButton(2)))
1282 if(Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
) || UI()->MouseButton(2))
1284 if(Input()->KeyPressed(KEY_LSHIFT
))
1285 s_Operation
= OP_PAN_EDITOR
;
1287 s_Operation
= OP_PAN_WORLD
;
1288 UI()->SetActiveItem(s_pEditorID
);
1293 if(UI()->HotItem() == s_pEditorID
)
1295 if(m_Brush
.IsEmpty())
1296 m_pTooltip
= "Use left mouse button to drag and create a brush.";
1298 m_pTooltip
= "Use left mouse button to paint with the brush. Right button clears the brush.";
1300 if(UI()->ActiveItem() == s_pEditorID
)
1319 if(s_Operation
== OP_BRUSH_DRAW
)
1321 if(!m_Brush
.IsEmpty())
1324 for(int k
= 0; k
< NumEditLayers
; k
++)
1326 if(pEditLayers
[k
]->m_Type
== m_Brush
.m_lLayers
[0]->m_Type
)
1327 pEditLayers
[k
]->BrushDraw(m_Brush
.m_lLayers
[0], wx
, wy
);
1331 else if(s_Operation
== OP_BRUSH_GRAB
)
1333 if(!UI()->MouseButton(0))
1337 str_format(aBuf
, sizeof(aBuf
),"grabbing %f %f %f %f", r
.x
, r
.y
, r
.w
, r
.h
);
1338 Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG
, "editor", aBuf
);
1340 // TODO: do all layers
1342 for(int k
= 0; k
< NumEditLayers
; k
++)
1343 Grabs
+= pEditLayers
[k
]->BrushGrab(&m_Brush
, r
);
1349 //editor.map.groups[selected_group]->mapscreen();
1350 for(int k
= 0; k
< NumEditLayers
; k
++)
1351 pEditLayers
[k
]->BrushSelecting(r
);
1352 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
1355 else if(s_Operation
== OP_BRUSH_PAINT
)
1357 if(!UI()->MouseButton(0))
1359 for(int k
= 0; k
< NumEditLayers
; k
++)
1360 pEditLayers
[k
]->FillSelection(m_Brush
.IsEmpty(), m_Brush
.m_lLayers
[0], r
);
1364 //editor.map.groups[selected_group]->mapscreen();
1365 for(int k
= 0; k
< NumEditLayers
; k
++)
1366 pEditLayers
[k
]->BrushSelecting(r
);
1367 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
1373 if(UI()->MouseButton(1))
1376 if(UI()->MouseButton(0) && s_Operation
== OP_NONE
)
1378 UI()->SetActiveItem(s_pEditorID
);
1380 if(m_Brush
.IsEmpty())
1381 s_Operation
= OP_BRUSH_GRAB
;
1384 s_Operation
= OP_BRUSH_DRAW
;
1385 for(int k
= 0; k
< NumEditLayers
; k
++)
1387 if(pEditLayers
[k
]->m_Type
== m_Brush
.m_lLayers
[0]->m_Type
)
1388 pEditLayers
[k
]->BrushPlace(m_Brush
.m_lLayers
[0], wx
, wy
);
1393 CLayerTiles
*pLayer
= (CLayerTiles
*)GetSelectedLayerType(0, LAYERTYPE_TILES
);
1394 if((Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
)) && pLayer
)
1395 s_Operation
= OP_BRUSH_PAINT
;
1398 if(!m_Brush
.IsEmpty())
1400 m_Brush
.m_OffsetX
= -(int)wx
;
1401 m_Brush
.m_OffsetY
= -(int)wy
;
1402 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
1404 if(m_Brush
.m_lLayers
[i
]->m_Type
== LAYERTYPE_TILES
)
1406 m_Brush
.m_OffsetX
= -(int)(wx
/32.0f
)*32;
1407 m_Brush
.m_OffsetY
= -(int)(wy
/32.0f
)*32;
1412 CLayerGroup
*g
= GetSelectedGroup();
1415 m_Brush
.m_OffsetX
+= g
->m_OffsetX
;
1416 m_Brush
.m_OffsetY
+= g
->m_OffsetY
;
1417 m_Brush
.m_ParallaxX
= g
->m_ParallaxX
;
1418 m_Brush
.m_ParallaxY
= g
->m_ParallaxY
;
1421 m_Brush
.GetSize(&w
, &h
);
1423 IGraphics::CLineItem Array
[4] = {
1424 IGraphics::CLineItem(0, 0, w
, 0),
1425 IGraphics::CLineItem(w
, 0, w
, h
),
1426 IGraphics::CLineItem(w
, h
, 0, h
),
1427 IGraphics::CLineItem(0, h
, 0, 0)};
1428 Graphics()->TextureSet(-1);
1429 Graphics()->LinesBegin();
1430 Graphics()->LinesDraw(Array
, 4);
1431 Graphics()->LinesEnd();
1439 if(!m_ShowPicker
&& m_Brush
.IsEmpty())
1442 CLayerGroup
*g
= GetSelectedGroup();
1446 for(int k
= 0; k
< NumEditLayers
; k
++)
1448 if(pEditLayers
[k
]->m_Type
== LAYERTYPE_QUADS
)
1450 CLayerQuads
*pLayer
= (CLayerQuads
*)pEditLayers
[k
];
1452 Graphics()->TextureSet(-1);
1453 Graphics()->QuadsBegin();
1454 for(int i
= 0; i
< pLayer
->m_lQuads
.size(); i
++)
1456 for(int v
= 0; v
< 4; v
++)
1457 DoQuadPoint(&pLayer
->m_lQuads
[i
], i
, v
);
1459 DoQuad(&pLayer
->m_lQuads
[i
], i
);
1461 Graphics()->QuadsEnd();
1465 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
1469 if(UI()->ActiveItem() == s_pEditorID
)
1471 if(s_Operation
== OP_PAN_WORLD
)
1473 m_WorldOffsetX
-= m_MouseDeltaX
*m_WorldZoom
;
1474 m_WorldOffsetY
-= m_MouseDeltaY
*m_WorldZoom
;
1476 else if(s_Operation
== OP_PAN_EDITOR
)
1478 m_EditorOffsetX
-= m_MouseDeltaX
*m_WorldZoom
;
1479 m_EditorOffsetY
-= m_MouseDeltaY
*m_WorldZoom
;
1483 if(!UI()->MouseButton(0))
1485 s_Operation
= OP_NONE
;
1486 UI()->SetActiveItem(0);
1491 else if(UI()->ActiveItem() == s_pEditorID
)
1494 if(!UI()->MouseButton(0))
1496 s_Operation
= OP_NONE
;
1497 UI()->SetActiveItem(0);
1501 if(GetSelectedGroup() && GetSelectedGroup()->m_UseClipping
)
1503 CLayerGroup
*g
= m_Map
.m_pGameGroup
;
1506 Graphics()->TextureSet(-1);
1507 Graphics()->LinesBegin();
1510 r
.x
= GetSelectedGroup()->m_ClipX
;
1511 r
.y
= GetSelectedGroup()->m_ClipY
;
1512 r
.w
= GetSelectedGroup()->m_ClipW
;
1513 r
.h
= GetSelectedGroup()->m_ClipH
;
1515 IGraphics::CLineItem Array
[4] = {
1516 IGraphics::CLineItem(r
.x
, r
.y
, r
.x
+r
.w
, r
.y
),
1517 IGraphics::CLineItem(r
.x
+r
.w
, r
.y
, r
.x
+r
.w
, r
.y
+r
.h
),
1518 IGraphics::CLineItem(r
.x
+r
.w
, r
.y
+r
.h
, r
.x
, r
.y
+r
.h
),
1519 IGraphics::CLineItem(r
.x
, r
.y
+r
.h
, r
.x
, r
.y
)};
1520 Graphics()->SetColor(1,0,0,1);
1521 Graphics()->LinesDraw(Array
, 4);
1523 Graphics()->LinesEnd();
1526 // render screen sizes
1529 CLayerGroup
*g
= m_Map
.m_pGameGroup
;
1532 Graphics()->TextureSet(-1);
1533 Graphics()->LinesBegin();
1535 float aLastPoints
[4];
1536 float Start
= 1.0f
; //9.0f/16.0f;
1537 float End
= 16.0f
/9.0f
;
1538 const int NumSteps
= 20;
1539 for(int i
= 0; i
<= NumSteps
; i
++)
1542 float Aspect
= Start
+ (End
-Start
)*(i
/(float)NumSteps
);
1544 RenderTools()->MapscreenToWorld(
1545 m_WorldOffsetX
, m_WorldOffsetY
,
1546 1.0f
, 1.0f
, 0.0f
, 0.0f
, Aspect
, 1.0f
, aPoints
);
1550 IGraphics::CLineItem Array
[2] = {
1551 IGraphics::CLineItem(aPoints
[0], aPoints
[1], aPoints
[2], aPoints
[1]),
1552 IGraphics::CLineItem(aPoints
[0], aPoints
[3], aPoints
[2], aPoints
[3])};
1553 Graphics()->LinesDraw(Array
, 2);
1558 IGraphics::CLineItem Array
[4] = {
1559 IGraphics::CLineItem(aPoints
[0], aPoints
[1], aLastPoints
[0], aLastPoints
[1]),
1560 IGraphics::CLineItem(aPoints
[2], aPoints
[1], aLastPoints
[2], aLastPoints
[1]),
1561 IGraphics::CLineItem(aPoints
[0], aPoints
[3], aLastPoints
[0], aLastPoints
[3]),
1562 IGraphics::CLineItem(aPoints
[2], aPoints
[3], aLastPoints
[2], aLastPoints
[3])};
1563 Graphics()->LinesDraw(Array
, 4);
1568 IGraphics::CLineItem Array
[2] = {
1569 IGraphics::CLineItem(aPoints
[0], aPoints
[1], aPoints
[0], aPoints
[3]),
1570 IGraphics::CLineItem(aPoints
[2], aPoints
[1], aPoints
[2], aPoints
[3])};
1571 Graphics()->LinesDraw(Array
, 2);
1574 mem_copy(aLastPoints
, aPoints
, sizeof(aPoints
));
1579 Graphics()->SetColor(1,0,0,1);
1580 for(int i
= 0; i
< 2; i
++)
1583 float aAspects
[] = {4.0f
/3.0f
, 16.0f
/10.0f
, 5.0f
/4.0f
, 16.0f
/9.0f
};
1584 float Aspect
= aAspects
[i
];
1586 RenderTools()->MapscreenToWorld(
1587 m_WorldOffsetX
, m_WorldOffsetY
,
1588 1.0f
, 1.0f
, 0.0f
, 0.0f
, Aspect
, 1.0f
, aPoints
);
1593 r
.w
= aPoints
[2]-aPoints
[0];
1594 r
.h
= aPoints
[3]-aPoints
[1];
1596 IGraphics::CLineItem Array
[4] = {
1597 IGraphics::CLineItem(r
.x
, r
.y
, r
.x
+r
.w
, r
.y
),
1598 IGraphics::CLineItem(r
.x
+r
.w
, r
.y
, r
.x
+r
.w
, r
.y
+r
.h
),
1599 IGraphics::CLineItem(r
.x
+r
.w
, r
.y
+r
.h
, r
.x
, r
.y
+r
.h
),
1600 IGraphics::CLineItem(r
.x
, r
.y
+r
.h
, r
.x
, r
.y
)};
1601 Graphics()->LinesDraw(Array
, 4);
1602 Graphics()->SetColor(0,1,0,1);
1606 Graphics()->LinesEnd();
1609 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
1610 //UI()->ClipDisable();
1614 int CEditor::DoProperties(CUIRect
*pToolBox
, CProperty
*pProps
, int *pIDs
, int *pNewVal
)
1618 for(int i
= 0; pProps
[i
].m_pName
; i
++)
1621 pToolBox
->HSplitTop(13.0f
, &Slot
, pToolBox
);
1622 CUIRect Label
, Shifter
;
1623 Slot
.VSplitMid(&Label
, &Shifter
);
1624 Shifter
.HMargin(1.0f
, &Shifter
);
1625 UI()->DoLabel(&Label
, pProps
[i
].m_pName
, 10.0f
, -1, -1);
1627 if(pProps
[i
].m_Type
== PROPTYPE_INT_STEP
)
1632 Shifter
.VSplitRight(10.0f
, &Shifter
, &Inc
);
1633 Shifter
.VSplitLeft(10.0f
, &Dec
, &Shifter
);
1634 str_format(aBuf
, sizeof(aBuf
),"%d", pProps
[i
].m_Value
);
1635 RenderTools()->DrawUIRect(&Shifter
, vec4(1,1,1,0.5f
), 0, 0.0f
);
1636 UI()->DoLabel(&Shifter
, aBuf
, 10.0f
, 0, -1);
1638 if(DoButton_ButtonDec(&pIDs
[i
], 0, 0, &Dec
, 0, "Decrease"))
1640 *pNewVal
= pProps
[i
].m_Value
-1;
1643 if(DoButton_ButtonInc(((char *)&pIDs
[i
])+1, 0, 0, &Inc
, 0, "Increase"))
1645 *pNewVal
= pProps
[i
].m_Value
+1;
1649 else if(pProps
[i
].m_Type
== PROPTYPE_BOOL
)
1652 Shifter
.VSplitMid(&No
, &Yes
);
1653 if(DoButton_ButtonDec(&pIDs
[i
], "No", !pProps
[i
].m_Value
, &No
, 0, ""))
1658 if(DoButton_ButtonInc(((char *)&pIDs
[i
])+1, "Yes", pProps
[i
].m_Value
, &Yes
, 0, ""))
1664 else if(pProps
[i
].m_Type
== PROPTYPE_INT_SCROLL
)
1666 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.");
1667 if(NewValue
!= pProps
[i
].m_Value
)
1669 *pNewVal
= NewValue
;
1673 else if(pProps
[i
].m_Type
== PROPTYPE_COLOR
)
1675 static const char *s_paTexts
[4] = {"R", "G", "B", "A"};
1676 static int s_aShift
[] = {24, 16, 8, 0};
1679 for(int c
= 0; c
< 4; c
++)
1681 int v
= (pProps
[i
].m_Value
>> s_aShift
[c
])&0xff;
1682 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.")<<s_aShift
[c
];
1686 pToolBox
->HSplitTop(13.0f
, &Slot
, pToolBox
);
1687 Slot
.VSplitMid(0, &Shifter
);
1688 Shifter
.HMargin(1.0f
, &Shifter
);
1692 if(NewColor
!= pProps
[i
].m_Value
)
1694 *pNewVal
= NewColor
;
1698 else if(pProps
[i
].m_Type
== PROPTYPE_IMAGE
)
1701 if(pProps
[i
].m_Value
< 0)
1702 str_copy(aBuf
, "None", sizeof(aBuf
));
1704 str_format(aBuf
, sizeof(aBuf
),"%s", m_Map
.m_lImages
[pProps
[i
].m_Value
]->m_aName
);
1706 if(DoButton_Editor(&pIDs
[i
], aBuf
, 0, &Shifter
, 0, 0))
1707 PopupSelectImageInvoke(pProps
[i
].m_Value
, UI()->MouseX(), UI()->MouseY());
1709 int r
= PopupSelectImageResult();
1716 else if(pProps
[i
].m_Type
== PROPTYPE_SHIFT
)
1718 CUIRect Left
, Right
, Up
, Down
;
1719 Shifter
.VSplitMid(&Left
, &Up
);
1720 Left
.VSplitRight(1.0f
, &Left
, 0);
1721 Up
.VSplitLeft(1.0f
, 0, &Up
);
1722 Left
.VSplitLeft(10.0f
, &Left
, &Shifter
);
1723 Shifter
.VSplitRight(10.0f
, &Shifter
, &Right
);
1724 RenderTools()->DrawUIRect(&Shifter
, vec4(1,1,1,0.5f
), 0, 0.0f
);
1725 UI()->DoLabel(&Shifter
, "X", 10.0f
, 0, -1);
1726 Up
.VSplitLeft(10.0f
, &Up
, &Shifter
);
1727 Shifter
.VSplitRight(10.0f
, &Shifter
, &Down
);
1728 RenderTools()->DrawUIRect(&Shifter
, vec4(1,1,1,0.5f
), 0, 0.0f
);
1729 UI()->DoLabel(&Shifter
, "Y", 10.0f
, 0, -1);
1730 if(DoButton_ButtonDec(&pIDs
[i
], "-", 0, &Left
, 0, "Left"))
1735 if(DoButton_ButtonInc(((char *)&pIDs
[i
])+3, "+", 0, &Right
, 0, "Right"))
1740 if(DoButton_ButtonDec(((char *)&pIDs
[i
])+1, "-", 0, &Up
, 0, "Up"))
1745 if(DoButton_ButtonInc(((char *)&pIDs
[i
])+2, "+", 0, &Down
, 0, "Down"))
1756 void CEditor::RenderLayers(CUIRect ToolBox
, CUIRect ToolBar
, CUIRect View
)
1758 CUIRect LayersBox
= ToolBox
;
1763 CUIRect Slot
, Button
;
1766 float LayersHeight
= 12.0f
; // Height of AddGroup button
1767 static int s_ScrollBar
= 0;
1768 static float s_ScrollValue
= 0;
1770 for(int g
= 0; g
< m_Map
.m_lGroups
.size(); g
++)
1771 // Each group is 19.0f
1772 // Each layer is 14.0f
1773 LayersHeight
+= 19.0f
+ m_Map
.m_lGroups
[g
]->m_lLayers
.size() * 14.0f
;
1775 float ScrollDifference
= LayersHeight
- LayersBox
.h
;
1777 if(LayersHeight
> LayersBox
.h
) // Do we even need a scrollbar?
1780 LayersBox
.VSplitRight(15.0f
, &LayersBox
, &Scroll
);
1781 LayersBox
.VSplitRight(3.0f
, &LayersBox
, 0); // extra spacing
1782 Scroll
.HMargin(5.0f
, &Scroll
);
1783 s_ScrollValue
= UiDoScrollbarV(&s_ScrollBar
, &Scroll
, s_ScrollValue
);
1786 float LayerStartAt
= ScrollDifference
* s_ScrollValue
;
1787 if(LayerStartAt
< 0.0f
)
1788 LayerStartAt
= 0.0f
;
1790 float LayerStopAt
= LayersHeight
- ScrollDifference
* (1 - s_ScrollValue
);
1795 for(int g
= 0; g
< m_Map
.m_lGroups
.size(); g
++)
1797 if(LayerCur
> LayerStopAt
)
1799 else if(LayerCur
+ m_Map
.m_lGroups
[g
]->m_lLayers
.size() * 14.0f
+ 19.0f
< LayerStartAt
)
1801 LayerCur
+= m_Map
.m_lGroups
[g
]->m_lLayers
.size() * 14.0f
+ 19.0f
;
1805 CUIRect VisibleToggle
, SaveCheck
;
1806 if(LayerCur
>= LayerStartAt
)
1808 LayersBox
.HSplitTop(12.0f
, &Slot
, &LayersBox
);
1809 Slot
.VSplitLeft(12, &VisibleToggle
, &Slot
);
1810 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
))
1811 m_Map
.m_lGroups
[g
]->m_Visible
= !m_Map
.m_lGroups
[g
]->m_Visible
;
1813 Slot
.VSplitRight(12.0f
, &Slot
, &SaveCheck
);
1814 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
))
1815 if(!m_Map
.m_lGroups
[g
]->m_GameGroup
)
1816 m_Map
.m_lGroups
[g
]->m_SaveToMap
= !m_Map
.m_lGroups
[g
]->m_SaveToMap
;
1818 str_format(aBuf
, sizeof(aBuf
),"#%d %s", g
, m_Map
.m_lGroups
[g
]->m_pName
);
1819 if(int Result
= DoButton_Ex(&m_Map
.m_lGroups
[g
], aBuf
, g
==m_SelectedGroup
, &Slot
,
1820 BUTTON_CONTEXT
, "Select group. Right click for properties.", 0))
1822 m_SelectedGroup
= g
;
1823 m_SelectedLayer
= 0;
1825 static int s_GroupPopupId
= 0;
1827 UiInvokePopupMenu(&s_GroupPopupId
, 0, UI()->MouseX(), UI()->MouseY(), 120, 200, PopupGroup
);
1829 LayersBox
.HSplitTop(2.0f
, &Slot
, &LayersBox
);
1833 for(int i
= 0; i
< m_Map
.m_lGroups
[g
]->m_lLayers
.size(); i
++)
1835 if(LayerCur
> LayerStopAt
)
1837 else if(LayerCur
< LayerStartAt
)
1844 LayersBox
.HSplitTop(12.0f
, &Slot
, &LayersBox
);
1845 Slot
.VSplitLeft(12.0f
, 0, &Button
);
1846 Button
.VSplitLeft(15, &VisibleToggle
, &Button
);
1848 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
))
1849 m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_Visible
= !m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_Visible
;
1851 Button
.VSplitRight(12.0f
, &Button
, &SaveCheck
);
1852 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
))
1853 if(m_Map
.m_lGroups
[g
]->m_lLayers
[i
] != m_Map
.m_pGameLayer
)
1854 m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_SaveToMap
= !m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_SaveToMap
;
1856 str_format(aBuf
, sizeof(aBuf
),"#%d %s ", i
, m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_pTypeName
);
1857 if(int Result
= DoButton_Ex(m_Map
.m_lGroups
[g
]->m_lLayers
[i
], aBuf
, g
==m_SelectedGroup
&&i
==m_SelectedLayer
, &Button
,
1858 BUTTON_CONTEXT
, "Select layer. Right click for properties.", 0))
1860 m_SelectedLayer
= i
;
1861 m_SelectedGroup
= g
;
1862 static int s_LayerPopupID
= 0;
1864 UiInvokePopupMenu(&s_LayerPopupID
, 0, UI()->MouseX(), UI()->MouseY(), 120, 220, PopupLayer
);
1868 LayersBox
.HSplitTop(2.0f
, &Slot
, &LayersBox
);
1870 if(LayerCur
> LayerStartAt
&& LayerCur
< LayerStopAt
)
1871 LayersBox
.HSplitTop(5.0f
, &Slot
, &LayersBox
);
1876 if(LayerCur
<= LayerStopAt
)
1878 LayersBox
.HSplitTop(12.0f
, &Slot
, &LayersBox
);
1880 static int s_NewGroupButton
= 0;
1881 if(DoButton_Editor(&s_NewGroupButton
, "Add group", 0, &Slot
, 0, "Adds a new group"))
1884 m_SelectedGroup
= m_Map
.m_lGroups
.size()-1;
1889 void CEditor::ReplaceImage(const char *pFileName
, int StorageType
, void *pUser
)
1891 CEditor
*pEditor
= (CEditor
*)pUser
;
1892 CEditorImage
ImgInfo(pEditor
);
1893 if(!pEditor
->Graphics()->LoadPNG(&ImgInfo
, pFileName
, StorageType
))
1896 CEditorImage
*pImg
= pEditor
->m_Map
.m_lImages
[pEditor
->m_SelectedImage
];
1897 int External
= pImg
->m_External
;
1898 pEditor
->Graphics()->UnloadTexture(pImg
->m_TexID
);
1900 pImg
->m_External
= External
;
1901 pEditor
->ExtractName(pFileName
, pImg
->m_aName
, sizeof(pImg
->m_aName
));
1902 pImg
->m_TexID
= pEditor
->Graphics()->LoadTextureRaw(ImgInfo
.m_Width
, ImgInfo
.m_Height
, ImgInfo
.m_Format
, ImgInfo
.m_pData
, CImageInfo::FORMAT_AUTO
, 0);
1903 pEditor
->SortImages();
1904 for(int i
= 0; i
< pEditor
->m_Map
.m_lImages
.size(); ++i
)
1906 if(!str_comp(pEditor
->m_Map
.m_lImages
[i
]->m_aName
, pImg
->m_aName
))
1907 pEditor
->m_SelectedImage
= i
;
1909 pEditor
->m_Dialog
= DIALOG_NONE
;
1912 void CEditor::AddImage(const char *pFileName
, int StorageType
, void *pUser
)
1914 CEditor
*pEditor
= (CEditor
*)pUser
;
1915 CEditorImage
ImgInfo(pEditor
);
1916 if(!pEditor
->Graphics()->LoadPNG(&ImgInfo
, pFileName
, StorageType
))
1919 // check if we have that image already
1921 ExtractName(pFileName
, aBuf
, sizeof(aBuf
));
1922 for(int i
= 0; i
< pEditor
->m_Map
.m_lImages
.size(); ++i
)
1924 if(!str_comp(pEditor
->m_Map
.m_lImages
[i
]->m_aName
, aBuf
))
1928 CEditorImage
*pImg
= new CEditorImage(pEditor
);
1930 pImg
->m_TexID
= pEditor
->Graphics()->LoadTextureRaw(ImgInfo
.m_Width
, ImgInfo
.m_Height
, ImgInfo
.m_Format
, ImgInfo
.m_pData
, CImageInfo::FORMAT_AUTO
, 0);
1931 pImg
->m_External
= 1; // external by default
1932 str_copy(pImg
->m_aName
, aBuf
, sizeof(pImg
->m_aName
));
1933 pEditor
->m_Map
.m_lImages
.add(pImg
);
1934 pEditor
->SortImages();
1935 if(pEditor
->m_SelectedImage
> -1 && pEditor
->m_SelectedImage
< pEditor
->m_Map
.m_lImages
.size())
1937 for(int i
= 0; i
<= pEditor
->m_SelectedImage
; ++i
)
1938 if(!str_comp(pEditor
->m_Map
.m_lImages
[i
]->m_aName
, aBuf
))
1940 pEditor
->m_SelectedImage
++;
1944 pEditor
->m_Dialog
= DIALOG_NONE
;
1948 static int gs_ModifyIndexDeletedIndex
;
1949 static void ModifyIndexDeleted(int *pIndex
)
1951 if(*pIndex
== gs_ModifyIndexDeletedIndex
)
1953 else if(*pIndex
> gs_ModifyIndexDeletedIndex
)
1954 *pIndex
= *pIndex
- 1;
1957 int CEditor::PopupImage(CEditor
*pEditor
, CUIRect View
)
1959 static int s_ReplaceButton
= 0;
1960 static int s_RemoveButton
= 0;
1963 View
.HSplitTop(2.0f
, &Slot
, &View
);
1964 View
.HSplitTop(12.0f
, &Slot
, &View
);
1965 CEditorImage
*pImg
= pEditor
->m_Map
.m_lImages
[pEditor
->m_SelectedImage
];
1967 static int s_ExternalButton
= 0;
1968 if(pImg
->m_External
)
1970 if(pEditor
->DoButton_MenuItem(&s_ExternalButton
, "Embed", 0, &Slot
, 0, "Embeds the image into the map file."))
1972 pImg
->m_External
= 0;
1978 if(pEditor
->DoButton_MenuItem(&s_ExternalButton
, "Make external", 0, &Slot
, 0, "Removes the image from the map file."))
1980 pImg
->m_External
= 1;
1985 View
.HSplitTop(10.0f
, &Slot
, &View
);
1986 View
.HSplitTop(12.0f
, &Slot
, &View
);
1987 if(pEditor
->DoButton_MenuItem(&s_ReplaceButton
, "Replace", 0, &Slot
, 0, "Replaces the image with a new one"))
1989 pEditor
->InvokeFileDialog(IStorage::TYPE_ALL
, FILETYPE_IMG
, "Replace Image", "Replace", "mapres", "", ReplaceImage
, pEditor
);
1993 View
.HSplitTop(10.0f
, &Slot
, &View
);
1994 View
.HSplitTop(12.0f
, &Slot
, &View
);
1995 if(pEditor
->DoButton_MenuItem(&s_RemoveButton
, "Remove", 0, &Slot
, 0, "Removes the image from the map"))
1998 pEditor
->m_Map
.m_lImages
.remove_index(pEditor
->m_SelectedImage
);
1999 gs_ModifyIndexDeletedIndex
= pEditor
->m_SelectedImage
;
2000 pEditor
->m_Map
.ModifyImageIndex(ModifyIndexDeleted
);
2007 static int CompareImageName(const void *pObject1
, const void *pObject2
)
2009 CEditorImage
*pImage1
= *(CEditorImage
**)pObject1
;
2010 CEditorImage
*pImage2
= *(CEditorImage
**)pObject2
;
2012 return str_comp(pImage1
->m_aName
, pImage2
->m_aName
);
2015 static int *gs_pSortedIndex
= 0;
2016 static void ModifySortedIndex(int *pIndex
)
2019 *pIndex
= gs_pSortedIndex
[*pIndex
];
2022 void CEditor::SortImages()
2025 for(int i
= 1; i
< m_Map
.m_lImages
.size(); i
++)
2026 if( str_comp(m_Map
.m_lImages
[i
]->m_aName
, m_Map
.m_lImages
[i
-1]->m_aName
) < 0 )
2034 array
<CEditorImage
*> lTemp
= array
<CEditorImage
*>(m_Map
.m_lImages
);
2035 gs_pSortedIndex
= new int[lTemp
.size()];
2037 qsort(m_Map
.m_lImages
.base_ptr(), m_Map
.m_lImages
.size(), sizeof(CEditorImage
*), CompareImageName
);
2039 for(int OldIndex
= 0; OldIndex
< lTemp
.size(); OldIndex
++)
2040 for(int NewIndex
= 0; NewIndex
< m_Map
.m_lImages
.size(); NewIndex
++)
2041 if(lTemp
[OldIndex
] == m_Map
.m_lImages
[NewIndex
])
2042 gs_pSortedIndex
[OldIndex
] = NewIndex
;
2044 m_Map
.ModifyImageIndex(ModifySortedIndex
);
2046 delete [] gs_pSortedIndex
;
2047 gs_pSortedIndex
= 0;
2052 void CEditor::RenderImages(CUIRect ToolBox
, CUIRect ToolBar
, CUIRect View
)
2054 static int s_ScrollBar
= 0;
2055 static float s_ScrollValue
= 0;
2056 float ImagesHeight
= 30.0f
+ 14.0f
* m_Map
.m_lImages
.size() + 27.0f
;
2057 float ScrollDifference
= ImagesHeight
- ToolBox
.h
;
2059 if(ImagesHeight
> ToolBox
.h
) // Do we even need a scrollbar?
2062 ToolBox
.VSplitRight(15.0f
, &ToolBox
, &Scroll
);
2063 ToolBox
.VSplitRight(3.0f
, &ToolBox
, 0); // extra spacing
2064 Scroll
.HMargin(5.0f
, &Scroll
);
2065 s_ScrollValue
= UiDoScrollbarV(&s_ScrollBar
, &Scroll
, s_ScrollValue
);
2068 float ImageStartAt
= ScrollDifference
* s_ScrollValue
;
2069 if(ImageStartAt
< 0.0f
)
2070 ImageStartAt
= 0.0f
;
2072 float ImageStopAt
= ImagesHeight
- ScrollDifference
* (1 - s_ScrollValue
);
2073 float ImageCur
= 0.0f
;
2075 for(int e
= 0; e
< 2; e
++) // two passes, first embedded, then external
2079 if(ImageCur
> ImageStopAt
)
2081 else if(ImageCur
>= ImageStartAt
)
2084 ToolBox
.HSplitTop(15.0f
, &Slot
, &ToolBox
);
2086 UI()->DoLabel(&Slot
, "Embedded", 12.0f
, 0);
2088 UI()->DoLabel(&Slot
, "External", 12.0f
, 0);
2092 for(int i
= 0; i
< m_Map
.m_lImages
.size(); i
++)
2094 if((e
&& !m_Map
.m_lImages
[i
]->m_External
) ||
2095 (!e
&& m_Map
.m_lImages
[i
]->m_External
))
2100 if(ImageCur
> ImageStopAt
)
2102 else if(ImageCur
< ImageStartAt
)
2110 str_copy(aBuf
, m_Map
.m_lImages
[i
]->m_aName
, sizeof(aBuf
));
2111 ToolBox
.HSplitTop(12.0f
, &Slot
, &ToolBox
);
2113 if(int Result
= DoButton_Editor(&m_Map
.m_lImages
[i
], aBuf
, m_SelectedImage
== i
, &Slot
,
2114 BUTTON_CONTEXT
, "Select image"))
2116 m_SelectedImage
= i
;
2118 static int s_PopupImageID
= 0;
2120 UiInvokePopupMenu(&s_PopupImageID
, 0, UI()->MouseX(), UI()->MouseY(), 120, 80, PopupImage
);
2123 ToolBox
.HSplitTop(2.0f
, 0, &ToolBox
);
2126 if(m_SelectedImage
== i
)
2129 View
.Margin(10.0f
, &r
);
2134 Graphics()->TextureSet(m_Map
.m_lImages
[i
]->m_TexID
);
2135 Graphics()->BlendNormal();
2136 Graphics()->QuadsBegin();
2137 IGraphics::CQuadItem
QuadItem(r
.x
, r
.y
, r
.w
, r
.h
);
2138 Graphics()->QuadsDrawTL(&QuadItem
, 1);
2139 Graphics()->QuadsEnd();
2145 if(ImageCur
+ 27.0f
> ImageStopAt
)
2149 ToolBox
.HSplitTop(5.0f
, &Slot
, &ToolBox
);
2152 static int s_NewImageButton
= 0;
2153 ToolBox
.HSplitTop(10.0f
, &Slot
, &ToolBox
);
2154 ToolBox
.HSplitTop(12.0f
, &Slot
, &ToolBox
);
2155 if(DoButton_Editor(&s_NewImageButton
, "Add", 0, &Slot
, 0, "Load a new image to use in the map"))
2156 InvokeFileDialog(IStorage::TYPE_ALL
, FILETYPE_IMG
, "Add Image", "Add", "mapres", "", AddImage
, this);
2160 static int EditorListdirCallback(const char *pName
, int IsDir
, int StorageType
, void *pUser
)
2162 CEditor
*pEditor
= (CEditor
*)pUser
;
2163 int Length
= str_length(pName
);
2164 if((pName
[0] == '.' && (pName
[1] == 0 ||
2165 (pName
[1] == '.' && pName
[2] == 0 && (!str_comp(pEditor
->m_pFileDialogPath
, "maps") || !str_comp(pEditor
->m_pFileDialogPath
, "mapres"))))) ||
2166 (!IsDir
&& ((pEditor
->m_FileDialogFileType
== CEditor::FILETYPE_MAP
&& (Length
< 4 || str_comp(pName
+Length
-4, ".map"))) ||
2167 (pEditor
->m_FileDialogFileType
== CEditor::FILETYPE_IMG
&& (Length
< 4 || str_comp(pName
+Length
-4, ".png"))))))
2170 CEditor::CFilelistItem Item
;
2171 str_copy(Item
.m_aFilename
, pName
, sizeof(Item
.m_aFilename
));
2173 str_format(Item
.m_aName
, sizeof(Item
.m_aName
), "%s/", pName
);
2175 str_copy(Item
.m_aName
, pName
, min(static_cast<int>(sizeof(Item
.m_aName
)), Length
-3));
2176 Item
.m_IsDir
= IsDir
!= 0;
2177 Item
.m_IsLink
= false;
2178 Item
.m_StorageType
= StorageType
;
2179 pEditor
->m_FileList
.add(Item
);
2184 void CEditor::AddFileDialogEntry(int Index
, CUIRect
*pView
)
2187 if(m_FilesCur
-1 < m_FilesStartAt
|| m_FilesCur
>= m_FilesStopAt
)
2190 CUIRect Button
, FileIcon
;
2191 pView
->HSplitTop(15.0f
, &Button
, pView
);
2192 pView
->HSplitTop(2.0f
, 0, pView
);
2193 Button
.VSplitLeft(Button
.h
, &FileIcon
, &Button
);
2194 Button
.VSplitLeft(5.0f
, 0, &Button
);
2196 Graphics()->TextureSet(g_pData
->m_aImages
[IMAGE_FILEICONS
].m_Id
);
2197 Graphics()->QuadsBegin();
2198 RenderTools()->SelectSprite(m_FileList
[Index
].m_IsDir
?SPRITE_FILE_FOLDER
:SPRITE_FILE_MAP2
);
2199 IGraphics::CQuadItem
QuadItem(FileIcon
.x
, FileIcon
.y
, FileIcon
.w
, FileIcon
.h
);
2200 Graphics()->QuadsDrawTL(&QuadItem
, 1);
2201 Graphics()->QuadsEnd();
2203 if(DoButton_File(&m_FileList
[Index
], m_FileList
[Index
].m_aName
, m_FilesSelectedIndex
== Index
, &Button
, 0, 0))
2205 if(!m_FileList
[Index
].m_IsDir
)
2206 str_copy(m_aFileDialogFileName
, m_FileList
[Index
].m_aFilename
, sizeof(m_aFileDialogFileName
));
2208 m_aFileDialogFileName
[0] = 0;
2209 m_FilesSelectedIndex
= Index
;
2211 if(Input()->MouseDoubleClick())
2212 m_aFileDialogActivate
= true;
2216 void CEditor::RenderFileDialog()
2219 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
2220 CUIRect View
= *UI()->Screen();
2221 float Width
= View
.w
, Height
= View
.h
;
2223 RenderTools()->DrawUIRect(&View
, vec4(0,0,0,0.25f
), 0, 0);
2224 View
.VMargin(150.0f
, &View
);
2225 View
.HMargin(50.0f
, &View
);
2226 RenderTools()->DrawUIRect(&View
, vec4(0,0,0,0.75f
), CUI::CORNER_ALL
, 5.0f
);
2227 View
.Margin(10.0f
, &View
);
2229 CUIRect Title
, FileBox
, FileBoxLabel
, ButtonBar
, Scroll
;
2230 View
.HSplitTop(18.0f
, &Title
, &View
);
2231 View
.HSplitTop(5.0f
, 0, &View
); // some spacing
2232 View
.HSplitBottom(14.0f
, &View
, &ButtonBar
);
2233 View
.HSplitBottom(10.0f
, &View
, 0); // some spacing
2234 View
.HSplitBottom(14.0f
, &View
, &FileBox
);
2235 FileBox
.VSplitLeft(55.0f
, &FileBoxLabel
, &FileBox
);
2236 View
.HSplitBottom(10.0f
, &View
, 0); // some spacing
2237 View
.VSplitRight(15.0f
, &View
, &Scroll
);
2240 RenderTools()->DrawUIRect(&Title
, vec4(1, 1, 1, 0.25f
), CUI::CORNER_ALL
, 4.0f
);
2241 Title
.VMargin(10.0f
, &Title
);
2242 UI()->DoLabel(&Title
, m_pFileDialogTitle
, 12.0f
, -1, -1);
2245 if(m_FileDialogStorageType
== IStorage::TYPE_SAVE
)
2247 static int s_FileBoxID
= 0;
2248 UI()->DoLabel(&FileBoxLabel
, "Filename:", 10.0f
, -1, -1);
2249 if(DoEditBox(&s_FileBoxID
, &FileBox
, m_aFileDialogFileName
, sizeof(m_aFileDialogFileName
), 10.0f
))
2251 // remove '/' and '\'
2252 for(int i
= 0; m_aFileDialogFileName
[i
]; ++i
)
2253 if(m_aFileDialogFileName
[i
] == '/' || m_aFileDialogFileName
[i
] == '\\')
2254 str_copy(&m_aFileDialogFileName
[i
], &m_aFileDialogFileName
[i
+1], (int)(sizeof(m_aFileDialogFileName
))-i
);
2255 m_FilesSelectedIndex
= -1;
2259 int Num
= (int)(View
.h
/17.0f
)+1;
2260 static int ScrollBar
= 0;
2261 Scroll
.HMargin(5.0f
, &Scroll
);
2262 m_FileDialogScrollValue
= UiDoScrollbarV(&ScrollBar
, &Scroll
, m_FileDialogScrollValue
);
2264 int ScrollNum
= m_FileList
.size()-Num
+1;
2267 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP
))
2268 m_FileDialogScrollValue
-= 3.0f
/ScrollNum
;
2269 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN
))
2270 m_FileDialogScrollValue
+= 3.0f
/ScrollNum
;
2275 if(m_FilesSelectedIndex
> -1)
2277 for(int i
= 0; i
< Input()->NumEvents(); i
++)
2280 if(Input()->GetEvent(i
).m_Flags
&IInput::FLAG_PRESS
)
2282 if(Input()->GetEvent(i
).m_Key
== KEY_DOWN
) NewIndex
= m_FilesSelectedIndex
+ 1;
2283 if(Input()->GetEvent(i
).m_Key
== KEY_UP
) NewIndex
= m_FilesSelectedIndex
- 1;
2285 if(NewIndex
> -1 && NewIndex
< m_FileList
.size())
2288 float IndexY
= View
.y
- m_FileDialogScrollValue
*ScrollNum
*17.0f
+ NewIndex
*17.0f
;
2289 int Scroll
= View
.y
> IndexY
? -1 : View
.y
+View
.h
< IndexY
+17.0f
? 1 : 0;
2293 m_FileDialogScrollValue
= ((float)(NewIndex
)+0.5f
)/ScrollNum
;
2295 m_FileDialogScrollValue
= ((float)(NewIndex
-Num
)+2.5f
)/ScrollNum
;
2298 if(!m_FileList
[NewIndex
].m_IsDir
)
2299 str_copy(m_aFileDialogFileName
, m_FileList
[NewIndex
].m_aFilename
, sizeof(m_aFileDialogFileName
));
2301 m_aFileDialogFileName
[0] = 0;
2302 m_FilesSelectedIndex
= NewIndex
;
2307 for(int i
= 0; i
< Input()->NumEvents(); i
++)
2309 if(Input()->GetEvent(i
).m_Flags
&IInput::FLAG_PRESS
)
2311 if(Input()->GetEvent(i
).m_Key
== KEY_RETURN
|| Input()->GetEvent(i
).m_Key
== KEY_KP_ENTER
)
2312 m_aFileDialogActivate
= true;
2316 if(m_FileDialogScrollValue
< 0) m_FileDialogScrollValue
= 0;
2317 if(m_FileDialogScrollValue
> 1) m_FileDialogScrollValue
= 1;
2319 m_FilesStartAt
= (int)(ScrollNum
*m_FileDialogScrollValue
);
2320 if(m_FilesStartAt
< 0)
2323 m_FilesStopAt
= m_FilesStartAt
+Num
;
2328 UI()->ClipEnable(&View
);
2330 for(int i
= 0; i
< m_FileList
.size(); i
++)
2331 AddFileDialogEntry(i
, &View
);
2333 // disable clipping again
2334 UI()->ClipDisable();
2337 static int s_OkButton
= 0;
2338 static int s_CancelButton
= 0;
2339 static int s_NewFolderButton
= 0;
2342 ButtonBar
.VSplitRight(50.0f
, &ButtonBar
, &Button
);
2343 bool IsDir
= m_FilesSelectedIndex
>= 0 && m_FileList
[m_FilesSelectedIndex
].m_IsDir
;
2344 if(DoButton_Editor(&s_OkButton
, IsDir
? "Open" : m_pFileDialogButtonText
, 0, &Button
, 0, 0) || m_aFileDialogActivate
)
2346 m_aFileDialogActivate
= false;
2349 if(str_comp(m_FileList
[m_FilesSelectedIndex
].m_aFilename
, "..") == 0) // parent folder
2351 if(fs_parent_dir(m_pFileDialogPath
))
2352 m_pFileDialogPath
= m_aFileDialogCurrentFolder
; // leave the link
2356 if(m_FileList
[m_FilesSelectedIndex
].m_IsLink
)
2358 m_pFileDialogPath
= m_aFileDialogCurrentLink
; // follow the link
2359 str_copy(m_aFileDialogCurrentLink
, m_FileList
[m_FilesSelectedIndex
].m_aFilename
, sizeof(m_aFileDialogCurrentLink
));
2363 char aTemp
[MAX_PATH_LENGTH
];
2364 str_copy(aTemp
, m_pFileDialogPath
, sizeof(aTemp
));
2365 str_format(m_pFileDialogPath
, MAX_PATH_LENGTH
, "%s/%s", aTemp
, m_FileList
[m_FilesSelectedIndex
].m_aFilename
);
2368 FilelistPopulate(!str_comp(m_pFileDialogPath
, "maps") || !str_comp(m_pFileDialogPath
, "mapres") ? m_FileDialogStorageType
:
2369 m_FileList
[m_FilesSelectedIndex
].m_StorageType
);
2370 if(m_FilesSelectedIndex
>= 0 && !m_FileList
[m_FilesSelectedIndex
].m_IsDir
)
2371 str_copy(m_aFileDialogFileName
, m_FileList
[m_FilesSelectedIndex
].m_aFilename
, sizeof(m_aFileDialogFileName
));
2373 m_aFileDialogFileName
[0] = 0;
2377 str_format(m_aFileSaveName
, sizeof(m_aFileSaveName
), "%s/%s", m_pFileDialogPath
, m_aFileDialogFileName
);
2378 if(!str_comp(m_pFileDialogButtonText
, "Save"))
2380 IOHANDLE File
= Storage()->OpenFile(m_aFileSaveName
, IOFLAG_READ
, IStorage::TYPE_SAVE
);
2384 m_PopupEventType
= POPEVENT_SAVE
;
2385 m_PopupEventActivated
= true;
2388 if(m_pfnFileDialogFunc
)
2389 m_pfnFileDialogFunc(m_aFileSaveName
, m_FilesSelectedIndex
>= 0 ? m_FileList
[m_FilesSelectedIndex
].m_StorageType
: m_FileDialogStorageType
, m_pFileDialogUser
);
2392 if(m_pfnFileDialogFunc
)
2393 m_pfnFileDialogFunc(m_aFileSaveName
, m_FilesSelectedIndex
>= 0 ? m_FileList
[m_FilesSelectedIndex
].m_StorageType
: m_FileDialogStorageType
, m_pFileDialogUser
);
2397 ButtonBar
.VSplitRight(40.0f
, &ButtonBar
, &Button
);
2398 ButtonBar
.VSplitRight(50.0f
, &ButtonBar
, &Button
);
2399 if(DoButton_Editor(&s_CancelButton
, "Cancel", 0, &Button
, 0, 0) || Input()->KeyPressed(KEY_ESCAPE
))
2400 m_Dialog
= DIALOG_NONE
;
2402 if(m_FileDialogStorageType
== IStorage::TYPE_SAVE
)
2404 ButtonBar
.VSplitLeft(40.0f
, 0, &ButtonBar
);
2405 ButtonBar
.VSplitLeft(70.0f
, &Button
, &ButtonBar
);
2406 if(DoButton_Editor(&s_NewFolderButton
, "New folder", 0, &Button
, 0, 0))
2408 m_FileDialogNewFolderName
[0] = 0;
2409 m_FileDialogErrString
[0] = 0;
2410 static int s_NewFolderPopupID
= 0;
2411 UiInvokePopupMenu(&s_NewFolderPopupID
, 0, Width
/2.0f
-200.0f
, Height
/2.0f
-100.0f
, 400.0f
, 200.0f
, PopupNewFolder
);
2412 UI()->SetActiveItem(0);
2417 void CEditor::FilelistPopulate(int StorageType
)
2420 if(m_FileDialogStorageType
!= IStorage::TYPE_SAVE
&& !str_comp(m_pFileDialogPath
, "maps"))
2423 str_copy(Item
.m_aFilename
, "downloadedmaps", sizeof(Item
.m_aFilename
));
2424 str_copy(Item
.m_aName
, "downloadedmaps/", sizeof(Item
.m_aName
));
2425 Item
.m_IsDir
= true;
2426 Item
.m_IsLink
= true;
2427 Item
.m_StorageType
= IStorage::TYPE_SAVE
;
2428 m_FileList
.add(Item
);
2430 Storage()->ListDirectory(StorageType
, m_pFileDialogPath
, EditorListdirCallback
, this);
2431 m_FilesSelectedIndex
= m_FileList
.size() ? 0 : -1;
2432 m_aFileDialogActivate
= false;
2435 void CEditor::InvokeFileDialog(int StorageType
, int FileType
, const char *pTitle
, const char *pButtonText
,
2436 const char *pBasePath
, const char *pDefaultName
,
2437 void (*pfnFunc
)(const char *pFileName
, int StorageType
, void *pUser
), void *pUser
)
2439 m_FileDialogStorageType
= StorageType
;
2440 m_pFileDialogTitle
= pTitle
;
2441 m_pFileDialogButtonText
= pButtonText
;
2442 m_pfnFileDialogFunc
= pfnFunc
;
2443 m_pFileDialogUser
= pUser
;
2444 m_aFileDialogFileName
[0] = 0;
2445 m_aFileDialogCurrentFolder
[0] = 0;
2446 m_aFileDialogCurrentLink
[0] = 0;
2447 m_pFileDialogPath
= m_aFileDialogCurrentFolder
;
2448 m_FileDialogFileType
= FileType
;
2449 m_FileDialogScrollValue
= 0.0f
;
2452 str_copy(m_aFileDialogFileName
, pDefaultName
, sizeof(m_aFileDialogFileName
));
2454 str_copy(m_aFileDialogCurrentFolder
, pBasePath
, sizeof(m_aFileDialogCurrentFolder
));
2456 FilelistPopulate(m_FileDialogStorageType
);
2458 m_Dialog
= DIALOG_FILE
;
2463 void CEditor::RenderModebar(CUIRect View
)
2469 View
.VSplitLeft(65.0f
, &Button
, &View
);
2470 Button
.HSplitTop(30.0f
, 0, &Button
);
2471 static int s_Button
= 0;
2472 const char *pButName
= m_Mode
== MODE_LAYERS
? "Layers" : "Images";
2473 if(DoButton_Tab(&s_Button
, pButName
, 0, &Button
, 0, "Switch between images and layers managment."))
2475 if(m_Mode
== MODE_LAYERS
)
2476 m_Mode
= MODE_IMAGES
;
2478 m_Mode
= MODE_LAYERS
;
2482 View
.VSplitLeft(5.0f
, 0, &View
);
2485 void CEditor::RenderStatusbar(CUIRect View
)
2488 View
.VSplitRight(60.0f
, &View
, &Button
);
2489 static int s_EnvelopeButton
= 0;
2490 if(DoButton_Editor(&s_EnvelopeButton
, "Envelopes", m_ShowEnvelopeEditor
, &Button
, 0, "Toggles the envelope editor."))
2491 m_ShowEnvelopeEditor
= (m_ShowEnvelopeEditor
+1)%4;
2495 if(ms_pUiGotContext
&& ms_pUiGotContext
== UI()->HotItem())
2498 str_format(aBuf
, sizeof(aBuf
), "%s Right click for context menu.", m_pTooltip
);
2499 UI()->DoLabel(&View
, aBuf
, 10.0f
, -1, -1);
2502 UI()->DoLabel(&View
, m_pTooltip
, 10.0f
, -1, -1);
2506 void CEditor::RenderEnvelopeEditor(CUIRect View
)
2508 if(m_SelectedEnvelope
< 0) m_SelectedEnvelope
= 0;
2509 if(m_SelectedEnvelope
>= m_Map
.m_lEnvelopes
.size()) m_SelectedEnvelope
= m_Map
.m_lEnvelopes
.size()-1;
2511 CEnvelope
*pEnvelope
= 0;
2512 if(m_SelectedEnvelope
>= 0 && m_SelectedEnvelope
< m_Map
.m_lEnvelopes
.size())
2513 pEnvelope
= m_Map
.m_lEnvelopes
[m_SelectedEnvelope
];
2515 CUIRect ToolBar
, CurveBar
, ColorBar
;
2516 View
.HSplitTop(15.0f
, &ToolBar
, &View
);
2517 View
.HSplitTop(15.0f
, &CurveBar
, &View
);
2518 ToolBar
.Margin(2.0f
, &ToolBar
);
2519 CurveBar
.Margin(2.0f
, &CurveBar
);
2524 CEnvelope
*pNewEnv
= 0;
2526 ToolBar
.VSplitRight(50.0f
, &ToolBar
, &Button
);
2527 static int s_New4dButton
= 0;
2528 if(DoButton_Editor(&s_New4dButton
, "Color+", 0, &Button
, 0, "Creates a new color envelope"))
2530 m_Map
.m_Modified
= true;
2531 pNewEnv
= m_Map
.NewEnvelope(4);
2534 ToolBar
.VSplitRight(5.0f
, &ToolBar
, &Button
);
2535 ToolBar
.VSplitRight(50.0f
, &ToolBar
, &Button
);
2536 static int s_New2dButton
= 0;
2537 if(DoButton_Editor(&s_New2dButton
, "Pos.+", 0, &Button
, 0, "Creates a new pos envelope"))
2539 m_Map
.m_Modified
= true;
2540 pNewEnv
= m_Map
.NewEnvelope(3);
2544 if(m_SelectedEnvelope
>= 0)
2546 ToolBar
.VSplitRight(10.0f
, &ToolBar
, &Button
);
2547 ToolBar
.VSplitRight(50.0f
, &ToolBar
, &Button
);
2548 static int s_DelButton
= 0;
2549 if(DoButton_Editor(&s_DelButton
, "Delete", 0, &Button
, 0, "Delete this envelope"))
2551 m_Map
.m_Modified
= true;
2552 m_Map
.DeleteEnvelope(m_SelectedEnvelope
);
2553 if(m_SelectedEnvelope
>= m_Map
.m_lEnvelopes
.size())
2554 m_SelectedEnvelope
= m_Map
.m_lEnvelopes
.size()-1;
2555 pEnvelope
= m_SelectedEnvelope
>= 0 ? m_Map
.m_lEnvelopes
[m_SelectedEnvelope
] : 0;
2559 if(pNewEnv
) // add the default points
2561 if(pNewEnv
->m_Channels
== 4)
2563 pNewEnv
->AddPoint(0, 1,1,1,1);
2564 pNewEnv
->AddPoint(1000, 1,1,1,1);
2568 pNewEnv
->AddPoint(0, 0);
2569 pNewEnv
->AddPoint(1000, 0);
2573 CUIRect Shifter
, Inc
, Dec
;
2574 ToolBar
.VSplitLeft(60.0f
, &Shifter
, &ToolBar
);
2575 Shifter
.VSplitRight(15.0f
, &Shifter
, &Inc
);
2576 Shifter
.VSplitLeft(15.0f
, &Dec
, &Shifter
);
2578 str_format(aBuf
, sizeof(aBuf
),"%d/%d", m_SelectedEnvelope
+1, m_Map
.m_lEnvelopes
.size());
2579 RenderTools()->DrawUIRect(&Shifter
, vec4(1,1,1,0.5f
), 0, 0.0f
);
2580 UI()->DoLabel(&Shifter
, aBuf
, 10.0f
, 0, -1);
2582 static int s_PrevButton
= 0;
2583 if(DoButton_ButtonDec(&s_PrevButton
, 0, 0, &Dec
, 0, "Previous Envelope"))
2584 m_SelectedEnvelope
--;
2586 static int s_NextButton
= 0;
2587 if(DoButton_ButtonInc(&s_NextButton
, 0, 0, &Inc
, 0, "Next Envelope"))
2588 m_SelectedEnvelope
++;
2592 ToolBar
.VSplitLeft(15.0f
, &Button
, &ToolBar
);
2593 ToolBar
.VSplitLeft(35.0f
, &Button
, &ToolBar
);
2594 UI()->DoLabel(&Button
, "Name:", 10.0f
, -1, -1);
2596 ToolBar
.VSplitLeft(80.0f
, &Button
, &ToolBar
);
2598 static int s_NameBox
= 0;
2599 if(DoEditBox(&s_NameBox
, &Button
, pEnvelope
->m_aName
, sizeof(pEnvelope
->m_aName
), 10.0f
))
2600 m_Map
.m_Modified
= true;
2604 bool ShowColorBar
= false;
2605 if(pEnvelope
&& pEnvelope
->m_Channels
== 4)
2607 ShowColorBar
= true;
2608 View
.HSplitTop(20.0f
, &ColorBar
, &View
);
2609 ColorBar
.Margin(2.0f
, &ColorBar
);
2610 RenderBackground(ColorBar
, ms_CheckerTexture
, 16.0f
, 1.0f
);
2613 RenderBackground(View
, ms_CheckerTexture
, 32.0f
, 0.1f
);
2617 static array
<int> Selection
;
2618 static int sEnvelopeEditorID
= 0;
2619 static int s_ActiveChannels
= 0xf;
2625 ToolBar
.VSplitLeft(15.0f
, &Button
, &ToolBar
);
2627 static const char *s_paNames
[2][4] = {
2628 {"X", "Y", "R", ""},
2629 {"R", "G", "B", "A"},
2632 const char *paDescriptions
[2][4] = {
2633 {"X-axis of the envelope", "Y-axis of the envelope", "Rotation of the envelope", ""},
2634 {"Red value of the envelope", "Green value of the envelope", "Blue value of the envelope", "Alpha value of the envelope"},
2637 static int s_aChannelButtons
[4] = {0};
2639 //ui_draw_button_func draw_func;
2641 for(int i
= 0; i
< pEnvelope
->m_Channels
; i
++, Bit
<<=1)
2643 ToolBar
.VSplitLeft(15.0f
, &Button
, &ToolBar
);
2645 /*if(i == 0) draw_func = draw_editor_button_l;
2646 else if(i == envelope->channels-1) draw_func = draw_editor_button_r;
2647 else draw_func = draw_editor_button_m;*/
2649 if(DoButton_Editor(&s_aChannelButtons
[i
], s_paNames
[pEnvelope
->m_Channels
-3][i
], s_ActiveChannels
&Bit
, &Button
, 0, paDescriptions
[pEnvelope
->m_Channels
-3][i
]))
2650 s_ActiveChannels
^= Bit
;
2654 float EndTime
= pEnvelope
->EndTime();
2658 pEnvelope
->FindTopBottom(s_ActiveChannels
);
2659 float Top
= pEnvelope
->m_Top
;
2660 float Bottom
= pEnvelope
->m_Bottom
;
2667 float TimeScale
= EndTime
/View
.w
;
2668 float ValueScale
= (Top
-Bottom
)/View
.h
;
2670 if(UI()->MouseInside(&View
))
2671 UI()->SetHotItem(&sEnvelopeEditorID
);
2673 if(UI()->HotItem() == &sEnvelopeEditorID
)
2678 if(UI()->MouseButtonClicked(1))
2681 int Time
= (int)(((UI()->MouseX()-View
.x
)*TimeScale
)*1000.0f
);
2682 //float env_y = (UI()->MouseY()-view.y)/TimeScale;
2684 pEnvelope
->Eval(Time
, aChannels
);
2685 pEnvelope
->AddPoint(Time
,
2686 f2fx(aChannels
[0]), f2fx(aChannels
[1]),
2687 f2fx(aChannels
[2]), f2fx(aChannels
[3]));
2688 m_Map
.m_Modified
= true;
2691 m_pTooltip
= "Press right mouse button to create a new point";
2695 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
)};
2699 UI()->ClipEnable(&View
);
2700 Graphics()->TextureSet(-1);
2701 Graphics()->LinesBegin();
2702 for(int c
= 0; c
< pEnvelope
->m_Channels
; c
++)
2704 if(s_ActiveChannels
&(1<<c
))
2705 Graphics()->SetColor(aColors
[c
].r
,aColors
[c
].g
,aColors
[c
].b
,1);
2707 Graphics()->SetColor(aColors
[c
].r
*0.5f
,aColors
[c
].g
*0.5f
,aColors
[c
].b
*0.5f
,1);
2711 pEnvelope
->Eval(0.000001f
, aResults
);
2712 float PrevValue
= aResults
[c
];
2714 int Steps
= (int)((View
.w
/UI()->Screen()->w
) * Graphics()->ScreenWidth());
2715 for(int i
= 1; i
<= Steps
; i
++)
2717 float a
= i
/(float)Steps
;
2718 pEnvelope
->Eval(a
*EndTime
, aResults
);
2719 float v
= aResults
[c
];
2720 v
= (v
-Bottom
)/(Top
-Bottom
);
2722 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
);
2723 Graphics()->LinesDraw(&LineItem
, 1);
2728 Graphics()->LinesEnd();
2729 UI()->ClipDisable();
2732 // render curve options
2734 for(int i
= 0; i
< pEnvelope
->m_lPoints
.size()-1; i
++)
2736 float t0
= pEnvelope
->m_lPoints
[i
].m_Time
/1000.0f
/EndTime
;
2737 float t1
= pEnvelope
->m_lPoints
[i
+1].m_Time
/1000.0f
/EndTime
;
2739 //dbg_msg("", "%f", end_time);
2742 v
.x
= CurveBar
.x
+ (t0
+(t1
-t0
)*0.5f
) * CurveBar
.w
;
2747 void *pID
= &pEnvelope
->m_lPoints
[i
].m_Curvetype
;
2748 const char *paTypeName
[] = {
2749 "N", "L", "S", "F", "M"
2752 if(DoButton_Editor(pID
, paTypeName
[pEnvelope
->m_lPoints
[i
].m_Curvetype
], 0, &v
, 0, "Switch curve type"))
2753 pEnvelope
->m_lPoints
[i
].m_Curvetype
= (pEnvelope
->m_lPoints
[i
].m_Curvetype
+1)%NUM_CURVETYPES
;
2760 Graphics()->TextureSet(-1);
2761 Graphics()->QuadsBegin();
2762 for(int i
= 0; i
< pEnvelope
->m_lPoints
.size()-1; i
++)
2764 float r0
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[0]);
2765 float g0
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[1]);
2766 float b0
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[2]);
2767 float a0
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[3]);
2768 float r1
= fx2f(pEnvelope
->m_lPoints
[i
+1].m_aValues
[0]);
2769 float g1
= fx2f(pEnvelope
->m_lPoints
[i
+1].m_aValues
[1]);
2770 float b1
= fx2f(pEnvelope
->m_lPoints
[i
+1].m_aValues
[2]);
2771 float a1
= fx2f(pEnvelope
->m_lPoints
[i
+1].m_aValues
[3]);
2773 IGraphics::CColorVertex Array
[4] = {IGraphics::CColorVertex(0, r0
, g0
, b0
, a0
),
2774 IGraphics::CColorVertex(1, r1
, g1
, b1
, a1
),
2775 IGraphics::CColorVertex(2, r1
, g1
, b1
, a1
),
2776 IGraphics::CColorVertex(3, r0
, g0
, b0
, a0
)};
2777 Graphics()->SetColorVertex(Array
, 4);
2779 float x0
= pEnvelope
->m_lPoints
[i
].m_Time
/1000.0f
/EndTime
;
2780 // float y0 = (fx2f(envelope->points[i].values[c])-bottom)/(top-bottom);
2781 float x1
= pEnvelope
->m_lPoints
[i
+1].m_Time
/1000.0f
/EndTime
;
2782 //float y1 = (fx2f(envelope->points[i+1].values[c])-bottom)/(top-bottom);
2784 v
.x
= ColorBar
.x
+ x0
*ColorBar
.w
;
2786 v
.w
= (x1
-x0
)*ColorBar
.w
;
2789 IGraphics::CQuadItem
QuadItem(v
.x
, v
.y
, v
.w
, v
.h
);
2790 Graphics()->QuadsDrawTL(&QuadItem
, 1);
2792 Graphics()->QuadsEnd();
2797 int CurrentValue
= 0, CurrentTime
= 0;
2799 Graphics()->TextureSet(-1);
2800 Graphics()->QuadsBegin();
2801 for(int c
= 0; c
< pEnvelope
->m_Channels
; c
++)
2803 if(!(s_ActiveChannels
&(1<<c
)))
2806 for(int i
= 0; i
< pEnvelope
->m_lPoints
.size(); i
++)
2808 float x0
= pEnvelope
->m_lPoints
[i
].m_Time
/1000.0f
/EndTime
;
2809 float y0
= (fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[c
])-Bottom
)/(Top
-Bottom
);
2811 Final
.x
= View
.x
+ x0
*View
.w
;
2812 Final
.y
= View
.y
+View
.h
- y0
*View
.h
;
2818 void *pID
= &pEnvelope
->m_lPoints
[i
].m_aValues
[c
];
2820 if(UI()->MouseInside(&Final
))
2821 UI()->SetHotItem(pID
);
2823 float ColorMod
= 1.0f
;
2825 if(UI()->ActiveItem() == pID
)
2827 if(!UI()->MouseButton(0))
2829 UI()->SetActiveItem(0);
2833 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
2837 if((Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
)))
2838 pEnvelope
->m_lPoints
[i
].m_Time
+= (int)((m_MouseDeltaX
));
2840 pEnvelope
->m_lPoints
[i
].m_Time
+= (int)((m_MouseDeltaX
*TimeScale
)*1000.0f
);
2841 if(pEnvelope
->m_lPoints
[i
].m_Time
< pEnvelope
->m_lPoints
[i
-1].m_Time
)
2842 pEnvelope
->m_lPoints
[i
].m_Time
= pEnvelope
->m_lPoints
[i
-1].m_Time
+ 1;
2843 if(i
+1 != pEnvelope
->m_lPoints
.size() && pEnvelope
->m_lPoints
[i
].m_Time
> pEnvelope
->m_lPoints
[i
+1].m_Time
)
2844 pEnvelope
->m_lPoints
[i
].m_Time
= pEnvelope
->m_lPoints
[i
+1].m_Time
- 1;
2849 if((Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
)))
2850 pEnvelope
->m_lPoints
[i
].m_aValues
[c
] -= f2fx(m_MouseDeltaY
*0.001f
);
2852 pEnvelope
->m_lPoints
[i
].m_aValues
[c
] -= f2fx(m_MouseDeltaY
*ValueScale
);
2854 m_Map
.m_Modified
= true;
2858 Graphics()->SetColor(1,1,1,1);
2860 else if(UI()->HotItem() == pID
)
2862 if(UI()->MouseButton(0))
2866 UI()->SetActiveItem(pID
);
2870 if(UI()->MouseButtonClicked(1))
2872 pEnvelope
->m_lPoints
.remove_index(i
);
2873 m_Map
.m_Modified
= true;
2877 Graphics()->SetColor(1,0.75f
,0.75f
,1);
2878 m_pTooltip
= "Left mouse to drag. Hold ctrl to be more precise. Hold shift to alter time point aswell. Right click to delete.";
2881 if(UI()->ActiveItem() == pID
|| UI()->HotItem() == pID
)
2883 CurrentTime
= pEnvelope
->m_lPoints
[i
].m_Time
;
2884 CurrentValue
= pEnvelope
->m_lPoints
[i
].m_aValues
[c
];
2887 Graphics()->SetColor(aColors
[c
].r
*ColorMod
, aColors
[c
].g
*ColorMod
, aColors
[c
].b
*ColorMod
, 1.0f
);
2888 IGraphics::CQuadItem
QuadItem(Final
.x
, Final
.y
, Final
.w
, Final
.h
);
2889 Graphics()->QuadsDrawTL(&QuadItem
, 1);
2892 Graphics()->QuadsEnd();
2895 str_format(aBuf
, sizeof(aBuf
),"%.3f %.3f", CurrentTime
/1000.0f
, fx2f(CurrentValue
));
2896 UI()->DoLabel(&ToolBar
, aBuf
, 10.0f
, 0, -1);
2901 int CEditor::PopupMenuFile(CEditor
*pEditor
, CUIRect View
)
2903 static int s_NewMapButton
= 0;
2904 static int s_SaveButton
= 0;
2905 static int s_SaveAsButton
= 0;
2906 static int s_OpenButton
= 0;
2907 static int s_AppendButton
= 0;
2908 static int s_ExitButton
= 0;
2911 View
.HSplitTop(2.0f
, &Slot
, &View
);
2912 View
.HSplitTop(12.0f
, &Slot
, &View
);
2913 if(pEditor
->DoButton_MenuItem(&s_NewMapButton
, "New", 0, &Slot
, 0, "Creates a new map"))
2915 if(pEditor
->HasUnsavedData())
2917 pEditor
->m_PopupEventType
= POPEVENT_NEW
;
2918 pEditor
->m_PopupEventActivated
= true;
2923 pEditor
->m_aFileName
[0] = 0;
2928 View
.HSplitTop(10.0f
, &Slot
, &View
);
2929 View
.HSplitTop(12.0f
, &Slot
, &View
);
2930 if(pEditor
->DoButton_MenuItem(&s_OpenButton
, "Load", 0, &Slot
, 0, "Opens a map for editing"))
2932 if(pEditor
->HasUnsavedData())
2934 pEditor
->m_PopupEventType
= POPEVENT_LOAD
;
2935 pEditor
->m_PopupEventActivated
= true;
2938 pEditor
->InvokeFileDialog(IStorage::TYPE_ALL
, FILETYPE_MAP
, "Load map", "Load", "maps", "", pEditor
->CallbackOpenMap
, pEditor
);
2942 View
.HSplitTop(10.0f
, &Slot
, &View
);
2943 View
.HSplitTop(12.0f
, &Slot
, &View
);
2944 if(pEditor
->DoButton_MenuItem(&s_AppendButton
, "Append", 0, &Slot
, 0, "Opens a map and adds everything from that map to the current one"))
2946 pEditor
->InvokeFileDialog(IStorage::TYPE_ALL
, FILETYPE_MAP
, "Append map", "Append", "maps", "", pEditor
->CallbackAppendMap
, pEditor
);
2950 View
.HSplitTop(10.0f
, &Slot
, &View
);
2951 View
.HSplitTop(12.0f
, &Slot
, &View
);
2952 if(pEditor
->DoButton_MenuItem(&s_SaveButton
, "Save", 0, &Slot
, 0, "Saves the current map"))
2954 if(pEditor
->m_aFileName
[0] && pEditor
->m_ValidSaveFilename
)
2956 str_copy(pEditor
->m_aFileSaveName
, pEditor
->m_aFileName
, sizeof(pEditor
->m_aFileSaveName
));
2957 pEditor
->m_PopupEventType
= POPEVENT_SAVE
;
2958 pEditor
->m_PopupEventActivated
= true;
2961 pEditor
->InvokeFileDialog(IStorage::TYPE_SAVE
, FILETYPE_MAP
, "Save map", "Save", "maps", "", pEditor
->CallbackSaveMap
, pEditor
);
2965 View
.HSplitTop(2.0f
, &Slot
, &View
);
2966 View
.HSplitTop(12.0f
, &Slot
, &View
);
2967 if(pEditor
->DoButton_MenuItem(&s_SaveAsButton
, "Save As", 0, &Slot
, 0, "Saves the current map under a new name"))
2969 pEditor
->InvokeFileDialog(IStorage::TYPE_SAVE
, FILETYPE_MAP
, "Save map", "Save", "maps", "", pEditor
->CallbackSaveMap
, pEditor
);
2973 View
.HSplitTop(10.0f
, &Slot
, &View
);
2974 View
.HSplitTop(12.0f
, &Slot
, &View
);
2975 if(pEditor
->DoButton_MenuItem(&s_ExitButton
, "Exit", 0, &Slot
, 0, "Exits from the editor"))
2977 if(pEditor
->HasUnsavedData())
2979 pEditor
->m_PopupEventType
= POPEVENT_EXIT
;
2980 pEditor
->m_PopupEventActivated
= true;
2983 g_Config
.m_ClEditor
= 0;
2990 void CEditor::RenderMenubar(CUIRect MenuBar
)
2992 static CUIRect s_File
/*, view, help*/;
2994 MenuBar
.VSplitLeft(60.0f
, &s_File
, &MenuBar
);
2995 if(DoButton_Menu(&s_File
, "File", 0, &s_File
, 0, 0))
2996 UiInvokePopupMenu(&s_File
, 1, s_File
.x
, s_File
.y
+s_File
.h
-1.0f
, 120, 150, PopupMenuFile
, this);
2999 menubar.VSplitLeft(5.0f, 0, &menubar);
3000 menubar.VSplitLeft(60.0f, &view, &menubar);
3001 if(do_editor_button(&view, "View", 0, &view, draw_editor_button_menu, 0, 0))
3004 menubar.VSplitLeft(5.0f, 0, &menubar);
3005 menubar.VSplitLeft(60.0f, &help, &menubar);
3006 if(do_editor_button(&help, "Help", 0, &help, draw_editor_button_menu, 0, 0))
3010 MenuBar
.VSplitLeft(40.0f
, 0, &MenuBar
);
3012 str_format(aBuf
, sizeof(aBuf
), "File: %s", m_aFileName
);
3013 UI()->DoLabel(&MenuBar
, aBuf
, 10.0f
, -1, -1);
3016 void CEditor::Render()
3019 Graphics()->Clear(1.0f
, 0.0f
, 1.0f
);
3020 CUIRect View
= *UI()->Screen();
3021 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
3023 float Width
= View
.w
;
3024 float Height
= View
.h
;
3030 RenderBackground(View
, ms_CheckerTexture
, 32.0f
, 1.0f
);
3032 CUIRect MenuBar
, CModeBar
, ToolBar
, StatusBar
, EnvelopeEditor
, ToolBox
;
3033 m_ShowPicker
= Input()->KeyPressed(KEY_SPACE
) != 0 && m_Dialog
== DIALOG_NONE
;
3038 View
.HSplitTop(16.0f
, &MenuBar
, &View
);
3039 View
.HSplitTop(53.0f
, &ToolBar
, &View
);
3040 View
.VSplitLeft(100.0f
, &ToolBox
, &View
);
3041 View
.HSplitBottom(16.0f
, &View
, &StatusBar
);
3043 if(m_ShowEnvelopeEditor
&& !m_ShowPicker
)
3045 float size
= 125.0f
;
3046 if(m_ShowEnvelopeEditor
== 2)
3048 else if(m_ShowEnvelopeEditor
== 3)
3050 View
.HSplitBottom(size
, &View
, &EnvelopeEditor
);
3054 // a little hack for now
3055 if(m_Mode
== MODE_LAYERS
)
3056 DoMapEditor(View
, ToolBar
);
3060 float Brightness
= 0.25f
;
3061 RenderBackground(MenuBar
, ms_BackgroundTexture
, 128.0f
, Brightness
*0);
3062 MenuBar
.Margin(2.0f
, &MenuBar
);
3064 RenderBackground(ToolBox
, ms_BackgroundTexture
, 128.0f
, Brightness
);
3065 ToolBox
.Margin(2.0f
, &ToolBox
);
3067 RenderBackground(ToolBar
, ms_BackgroundTexture
, 128.0f
, Brightness
);
3068 ToolBar
.Margin(2.0f
, &ToolBar
);
3069 ToolBar
.VSplitLeft(100.0f
, &CModeBar
, &ToolBar
);
3071 RenderBackground(StatusBar
, ms_BackgroundTexture
, 128.0f
, Brightness
);
3072 StatusBar
.Margin(2.0f
, &StatusBar
);
3075 if(m_Mode
== MODE_LAYERS
)
3078 if(m_ShowEnvelopeEditor
)
3080 RenderBackground(EnvelopeEditor
, ms_BackgroundTexture
, 128.0f
, Brightness
);
3081 EnvelopeEditor
.Margin(2.0f
, &EnvelopeEditor
);
3086 if(m_Mode
== MODE_LAYERS
)
3087 RenderLayers(ToolBox
, ToolBar
, View
);
3088 else if(m_Mode
== MODE_IMAGES
)
3089 RenderImages(ToolBox
, ToolBar
, View
);
3091 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
3095 RenderMenubar(MenuBar
);
3097 RenderModebar(CModeBar
);
3098 if(m_ShowEnvelopeEditor
)
3099 RenderEnvelopeEditor(EnvelopeEditor
);
3102 if(m_Dialog
== DIALOG_FILE
)
3104 static int s_NullUiTarget
= 0;
3105 UI()->SetHotItem(&s_NullUiTarget
);
3109 if(m_PopupEventActivated
)
3111 static int s_PopupID
= 0;
3112 UiInvokePopupMenu(&s_PopupID
, 0, Width
/2.0f
-200.0f
, Height
/2.0f
-100.0f
, 400.0f
, 200.0f
, PopupEvent
);
3113 m_PopupEventActivated
= false;
3120 RenderStatusbar(StatusBar
);
3123 if(g_Config
.m_EdShowkeys
)
3125 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
3127 TextRender()->SetCursor(&Cursor
, View
.x
+10, View
.y
+View
.h
-24-10, 24.0f
, TEXTFLAG_RENDER
);
3130 for(int i
= 0; i
< KEY_LAST
; i
++)
3132 if(Input()->KeyPressed(i
))
3135 TextRender()->TextEx(&Cursor
, " + ", -1);
3136 TextRender()->TextEx(&Cursor
, Input()->KeyName(i
), -1);
3142 if(m_ShowMousePointer
)
3144 // render butt ugly mouse cursor
3145 float mx
= UI()->MouseX();
3146 float my
= UI()->MouseY();
3147 Graphics()->TextureSet(ms_CursorTexture
);
3148 Graphics()->QuadsBegin();
3149 if(ms_pUiGotContext
== UI()->HotItem())
3150 Graphics()->SetColor(1,0,0,1);
3151 IGraphics::CQuadItem
QuadItem(mx
,my
, 16.0f
, 16.0f
);
3152 Graphics()->QuadsDrawTL(&QuadItem
, 1);
3153 Graphics()->QuadsEnd();
3158 void CEditor::Reset(bool CreateDefault
)
3162 // create default layers
3164 m_Map
.CreateDefault(ms_EntitiesTexture
);
3170 m_SelectedLayer
= 0;
3171 m_SelectedGroup
= 0;
3172 m_SelectedQuad
= -1;
3173 m_SelectedPoints
= 0;
3174 m_SelectedEnvelope
= 0;
3175 m_SelectedImage
= 0;
3179 m_EditorOffsetX
= 0.0f
;
3180 m_EditorOffsetY
= 0.0f
;
3190 m_Map
.m_Modified
= false;
3193 void CEditorMap::DeleteEnvelope(int Index
)
3195 if(Index
< 0 || Index
>= m_lEnvelopes
.size())
3200 // fix links between envelopes and quads
3201 for(int i
= 0; i
< m_lGroups
.size(); ++i
)
3202 for(int j
= 0; j
< m_lGroups
[i
]->m_lLayers
.size(); ++j
)
3203 if(m_lGroups
[i
]->m_lLayers
[j
]->m_Type
== LAYERTYPE_QUADS
)
3205 CLayerQuads
*Layer
= static_cast<CLayerQuads
*>(m_lGroups
[i
]->m_lLayers
[j
]);
3206 for(int k
= 0; k
< Layer
->m_lQuads
.size(); ++k
)
3208 if(Layer
->m_lQuads
[k
].m_PosEnv
== Index
)
3209 Layer
->m_lQuads
[k
].m_PosEnv
= -1;
3210 else if(Layer
->m_lQuads
[k
].m_PosEnv
> Index
)
3211 Layer
->m_lQuads
[k
].m_PosEnv
--;
3212 if(Layer
->m_lQuads
[k
].m_ColorEnv
== Index
)
3213 Layer
->m_lQuads
[k
].m_ColorEnv
= -1;
3214 else if(Layer
->m_lQuads
[k
].m_ColorEnv
> Index
)
3215 Layer
->m_lQuads
[k
].m_ColorEnv
--;
3219 m_lEnvelopes
.remove_index(Index
);
3222 void CEditorMap::MakeGameLayer(CLayer
*pLayer
)
3224 m_pGameLayer
= (CLayerGame
*)pLayer
;
3225 m_pGameLayer
->m_pEditor
= m_pEditor
;
3226 m_pGameLayer
->m_TexID
= m_pEditor
->ms_EntitiesTexture
;
3229 void CEditorMap::MakeGameGroup(CLayerGroup
*pGroup
)
3231 m_pGameGroup
= pGroup
;
3232 m_pGameGroup
->m_GameGroup
= true;
3233 m_pGameGroup
->m_pName
= "Game";
3238 void CEditorMap::Clean()
3240 m_lGroups
.delete_all();
3241 m_lEnvelopes
.delete_all();
3242 m_lImages
.delete_all();
3250 void CEditorMap::CreateDefault(int EntitiesTexture
)
3253 CLayerGroup
*pGroup
= NewGroup();
3254 pGroup
->m_ParallaxX
= 0;
3255 pGroup
->m_ParallaxY
= 0;
3256 CLayerQuads
*pLayer
= new CLayerQuads
;
3257 pLayer
->m_pEditor
= m_pEditor
;
3258 CQuad
*pQuad
= pLayer
->NewQuad();
3259 const int Width
= 800000;
3260 const int Height
= 600000;
3261 pQuad
->m_aPoints
[0].x
= pQuad
->m_aPoints
[2].x
= -Width
;
3262 pQuad
->m_aPoints
[1].x
= pQuad
->m_aPoints
[3].x
= Width
;
3263 pQuad
->m_aPoints
[0].y
= pQuad
->m_aPoints
[1].y
= -Height
;
3264 pQuad
->m_aPoints
[2].y
= pQuad
->m_aPoints
[3].y
= Height
;
3265 pQuad
->m_aColors
[0].r
= pQuad
->m_aColors
[1].r
= 94;
3266 pQuad
->m_aColors
[0].g
= pQuad
->m_aColors
[1].g
= 132;
3267 pQuad
->m_aColors
[0].b
= pQuad
->m_aColors
[1].b
= 174;
3268 pQuad
->m_aColors
[2].r
= pQuad
->m_aColors
[3].r
= 204;
3269 pQuad
->m_aColors
[2].g
= pQuad
->m_aColors
[3].g
= 232;
3270 pQuad
->m_aColors
[2].b
= pQuad
->m_aColors
[3].b
= 255;
3271 pGroup
->AddLayer(pLayer
);
3274 MakeGameGroup(NewGroup());
3275 MakeGameLayer(new CLayerGame(50, 50));
3276 m_pGameGroup
->AddLayer(m_pGameLayer
);
3279 void CEditor::Init()
3281 m_pInput
= Kernel()->RequestInterface
<IInput
>();
3282 m_pClient
= Kernel()->RequestInterface
<IClient
>();
3283 m_pConsole
= Kernel()->RequestInterface
<IConsole
>();
3284 m_pGraphics
= Kernel()->RequestInterface
<IGraphics
>();
3285 m_pTextRender
= Kernel()->RequestInterface
<ITextRender
>();
3286 m_pStorage
= Kernel()->RequestInterface
<IStorage
>();
3287 m_RenderTools
.m_pGraphics
= m_pGraphics
;
3288 m_RenderTools
.m_pUI
= &m_UI
;
3289 m_UI
.SetGraphics(m_pGraphics
, m_pTextRender
);
3290 m_Map
.m_pEditor
= this;
3292 ms_CheckerTexture
= Graphics()->LoadTexture("editor/checker.png", IStorage::TYPE_ALL
, CImageInfo::FORMAT_AUTO
, 0);
3293 ms_BackgroundTexture
= Graphics()->LoadTexture("editor/background.png", IStorage::TYPE_ALL
, CImageInfo::FORMAT_AUTO
, 0);
3294 ms_CursorTexture
= Graphics()->LoadTexture("editor/cursor.png", IStorage::TYPE_ALL
, CImageInfo::FORMAT_AUTO
, 0);
3295 ms_EntitiesTexture
= Graphics()->LoadTexture("editor/entities.png", IStorage::TYPE_ALL
, CImageInfo::FORMAT_AUTO
, 0);
3297 m_TilesetPicker
.m_pEditor
= this;
3298 m_TilesetPicker
.MakePalette();
3299 m_TilesetPicker
.m_Readonly
= true;
3301 m_Brush
.m_pMap
= &m_Map
;
3304 m_Map
.m_Modified
= false;
3307 void CEditor::DoMapBorder()
3309 CLayerTiles
*pT
= (CLayerTiles
*)GetSelectedLayerType(0, LAYERTYPE_TILES
);
3311 for(int i
= 0; i
< pT
->m_Width
*2; ++i
)
3312 pT
->m_pTiles
[i
].m_Index
= 1;
3314 for(int i
= 0; i
< pT
->m_Width
*pT
->m_Height
; ++i
)
3316 if(i
%pT
->m_Width
< 2 || i
%pT
->m_Width
> pT
->m_Width
-3)
3317 pT
->m_pTiles
[i
].m_Index
= 1;
3320 for(int i
= (pT
->m_Width
*(pT
->m_Height
-2)); i
< pT
->m_Width
*pT
->m_Height
; ++i
)
3321 pT
->m_pTiles
[i
].m_Index
= 1;
3324 void CEditor::UpdateAndRender()
3326 static float s_MouseX
= 0.0f
;
3327 static float s_MouseY
= 0.0f
;
3330 m_AnimateTime
= (time_get()-m_AnimateStart
)/(float)time_freq();
3333 ms_pUiGotContext
= 0;
3335 // handle mouse movement
3336 float mx
, my
, Mwx
, Mwy
;
3339 Input()->MouseRelative(&rx
, &ry
);
3340 UI()->ConvertMouseMove(&rx
, &ry
);
3350 s_MouseX
= clamp(s_MouseX
, 0.0f
, UI()->Screen()->w
);
3351 s_MouseY
= clamp(s_MouseY
, 0.0f
, UI()->Screen()->h
);
3359 // fix correct world x and y
3360 CLayerGroup
*g
= GetSelectedGroup();
3364 g
->Mapping(aPoints
);
3366 float WorldWidth
= aPoints
[2]-aPoints
[0];
3367 float WorldHeight
= aPoints
[3]-aPoints
[1];
3369 Mwx
= aPoints
[0] + WorldWidth
* (s_MouseX
/UI()->Screen()->w
);
3370 Mwy
= aPoints
[1] + WorldHeight
* (s_MouseY
/UI()->Screen()->h
);
3371 m_MouseDeltaWx
= m_MouseDeltaX
*(WorldWidth
/ UI()->Screen()->w
);
3372 m_MouseDeltaWy
= m_MouseDeltaY
*(WorldHeight
/ UI()->Screen()->h
);
3376 if(Input()->KeyPressed(KEY_MOUSE_1
)) Buttons
|= 1;
3377 if(Input()->KeyPressed(KEY_MOUSE_2
)) Buttons
|= 2;
3378 if(Input()->KeyPressed(KEY_MOUSE_3
)) Buttons
|= 4;
3380 UI()->Update(mx
,my
,Mwx
,Mwy
,Buttons
);
3384 if(Input()->KeyDown(KEY_TAB
))
3385 m_GuiActive
= !m_GuiActive
;
3387 if(Input()->KeyDown(KEY_F10
))
3388 m_ShowMousePointer
= false;
3392 if(Input()->KeyDown(KEY_F10
))
3394 Graphics()->TakeScreenshot(0);
3395 m_ShowMousePointer
= true;
3398 Input()->ClearEvents();
3401 IEditor
*CreateEditor() { return new CEditor
; }