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/input.h>
12 #include <engine/keys.h>
13 #include <engine/storage.h>
14 #include <engine/textrender.h>
16 #include <game/gamecore.h>
17 #include <game/localization.h>
18 #include <game/client/lineinput.h>
19 #include <game/client/render.h>
20 #include <game/client/ui.h>
21 #include <game/generated/client_data.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()
61 CLayerGroup::~CLayerGroup()
66 void CLayerGroup::Convert(CUIRect
*pRect
)
68 pRect
->x
+= m_OffsetX
;
69 pRect
->y
+= m_OffsetY
;
72 void CLayerGroup::Mapping(float *pPoints
)
74 m_pMap
->m_pEditor
->RenderTools()->MapscreenToWorld(
75 m_pMap
->m_pEditor
->m_WorldOffsetX
, m_pMap
->m_pEditor
->m_WorldOffsetY
,
76 m_ParallaxX
/100.0f
, m_ParallaxY
/100.0f
,
78 m_pMap
->m_pEditor
->Graphics()->ScreenAspect(), m_pMap
->m_pEditor
->m_WorldZoom
, pPoints
);
80 pPoints
[0] += m_pMap
->m_pEditor
->m_EditorOffsetX
;
81 pPoints
[1] += m_pMap
->m_pEditor
->m_EditorOffsetY
;
82 pPoints
[2] += m_pMap
->m_pEditor
->m_EditorOffsetX
;
83 pPoints
[3] += m_pMap
->m_pEditor
->m_EditorOffsetY
;
86 void CLayerGroup::MapScreen()
90 m_pMap
->m_pEditor
->Graphics()->MapScreen(aPoints
[0], aPoints
[1], aPoints
[2], aPoints
[3]);
93 void CLayerGroup::Render()
96 IGraphics
*pGraphics
= m_pMap
->m_pEditor
->Graphics();
101 m_pMap
->m_pGameGroup
->Mapping(aPoints
);
102 float x0
= (m_ClipX
- aPoints
[0]) / (aPoints
[2]-aPoints
[0]);
103 float y0
= (m_ClipY
- aPoints
[1]) / (aPoints
[3]-aPoints
[1]);
104 float x1
= ((m_ClipX
+m_ClipW
) - aPoints
[0]) / (aPoints
[2]-aPoints
[0]);
105 float y1
= ((m_ClipY
+m_ClipH
) - aPoints
[1]) / (aPoints
[3]-aPoints
[1]);
107 pGraphics
->ClipEnable((int)(x0
*pGraphics
->ScreenWidth()), (int)(y0
*pGraphics
->ScreenHeight()),
108 (int)((x1
-x0
)*pGraphics
->ScreenWidth()), (int)((y1
-y0
)*pGraphics
->ScreenHeight()));
111 for(int i
= 0; i
< m_lLayers
.size(); i
++)
113 if(m_lLayers
[i
]->m_Visible
&& m_lLayers
[i
] != m_pMap
->m_pGameLayer
)
115 if(m_pMap
->m_pEditor
->m_ShowDetail
|| !(m_lLayers
[i
]->m_Flags
&LAYERFLAG_DETAIL
))
116 m_lLayers
[i
]->Render();
120 pGraphics
->ClipDisable();
123 void CLayerGroup::AddLayer(CLayer
*l
)
125 m_pMap
->m_Modified
= true;
129 void CLayerGroup::DeleteLayer(int Index
)
131 if(Index
< 0 || Index
>= m_lLayers
.size()) return;
132 delete m_lLayers
[Index
];
133 m_lLayers
.remove_index(Index
);
134 m_pMap
->m_Modified
= true;
137 void CLayerGroup::GetSize(float *w
, float *h
)
140 for(int i
= 0; i
< m_lLayers
.size(); i
++)
143 m_lLayers
[i
]->GetSize(&lw
, &lh
);
150 int CLayerGroup::SwapLayers(int Index0
, int Index1
)
152 if(Index0
< 0 || Index0
>= m_lLayers
.size()) return Index0
;
153 if(Index1
< 0 || Index1
>= m_lLayers
.size()) return Index0
;
154 if(Index0
== Index1
) return Index0
;
155 m_pMap
->m_Modified
= true;
156 swap(m_lLayers
[Index0
], m_lLayers
[Index1
]);
160 void CEditorImage::AnalyseTileFlags()
162 mem_zero(m_aTileFlags
, sizeof(m_aTileFlags
));
164 int tw
= m_Width
/16; // tilesizes
165 int th
= m_Height
/16;
168 unsigned char *pPixelData
= (unsigned char *)m_pData
;
171 for(int ty
= 0; ty
< 16; ty
++)
172 for(int tx
= 0; tx
< 16; tx
++, TileID
++)
175 for(int x
= 0; x
< tw
; x
++)
176 for(int y
= 0; y
< th
; y
++)
178 int p
= (ty
*tw
+y
)*m_Width
+ tx
*tw
+x
;
179 if(pPixelData
[p
*4+3] < 250)
187 m_aTileFlags
[TileID
] |= TILEFLAG_OPAQUE
;
193 void CEditor::EnvelopeEval(float TimeOffset
, int Env
, float *pChannels
, void *pUser
)
195 CEditor
*pThis
= (CEditor
*)pUser
;
196 if(Env
< 0 || Env
>= pThis
->m_Map
.m_lEnvelopes
.size())
205 CEnvelope
*e
= pThis
->m_Map
.m_lEnvelopes
[Env
];
206 float t
= pThis
->m_AnimateTime
+TimeOffset
;
207 t
*= pThis
->m_AnimateSpeed
;
208 e
->Eval(t
, pChannels
);
211 /********************************************************
213 *********************************************************/
215 // copied from gc_menu.cpp, should be more generalized
216 //extern int ui_do_edit_box(void *id, const CUIRect *rect, char *str, int str_size, float font_size, bool hidden=false);
218 int CEditor::DoEditBox(void *pID
, const CUIRect
*pRect
, char *pStr
, unsigned StrSize
, float FontSize
, float *Offset
, bool Hidden
, int Corners
)
220 int Inside
= UI()->MouseInside(pRect
);
221 bool ReturnValue
= false;
222 bool UpdateOffset
= false;
223 static int s_AtIndex
= 0;
224 static bool s_DoScroll
= false;
225 static float s_ScrollStart
= 0.0f
;
227 FontSize
*= UI()->Scale();
229 if(UI()->LastActiveItem() == pID
)
231 int Len
= str_length(pStr
);
235 if(Inside
&& UI()->MouseButton(0))
238 s_ScrollStart
= UI()->MouseX();
239 int MxRel
= (int)(UI()->MouseX() - pRect
->x
);
241 for(int i
= 1; i
<= Len
; i
++)
243 if(TextRender()->TextWidth(0, FontSize
, pStr
, i
) - *Offset
> MxRel
)
253 else if(!UI()->MouseButton(0))
258 if(UI()->MouseX() < pRect
->x
&& s_ScrollStart
-UI()->MouseX() > 10.0f
)
260 s_AtIndex
= max(0, s_AtIndex
-1);
261 s_ScrollStart
= UI()->MouseX();
264 else if(UI()->MouseX() > pRect
->x
+pRect
->w
&& UI()->MouseX()-s_ScrollStart
> 10.0f
)
266 s_AtIndex
= min(Len
, s_AtIndex
+1);
267 s_ScrollStart
= UI()->MouseX();
272 for(int i
= 0; i
< Input()->NumEvents(); i
++)
274 Len
= str_length(pStr
);
275 ReturnValue
|= CLineInput::Manipulate(Input()->GetEvent(i
), pStr
, StrSize
, &Len
, &s_AtIndex
);
279 bool JustGotActive
= false;
281 if(UI()->ActiveItem() == pID
)
283 if(!UI()->MouseButton(0))
285 s_AtIndex
= min(s_AtIndex
, str_length(pStr
));
287 UI()->SetActiveItem(0);
290 else if(UI()->HotItem() == pID
)
292 if(UI()->MouseButton(0))
294 if (UI()->LastActiveItem() != pID
)
295 JustGotActive
= true;
296 UI()->SetActiveItem(pID
);
301 UI()->SetHotItem(pID
);
303 CUIRect Textbox
= *pRect
;
304 RenderTools()->DrawUIRect(&Textbox
, vec4(1, 1, 1, 0.5f
), Corners
, 3.0f
);
305 Textbox
.VMargin(2.0f
, &Textbox
);
307 const char *pDisplayStr
= pStr
;
312 unsigned s
= str_length(pStr
);
313 if(s
>= sizeof(aStars
))
314 s
= sizeof(aStars
)-1;
315 for(unsigned int i
= 0; i
< s
; ++i
)
318 pDisplayStr
= aStars
;
321 // check if the text has to be moved
322 if(UI()->LastActiveItem() == pID
&& !JustGotActive
&& (UpdateOffset
|| Input()->NumEvents()))
324 float w
= TextRender()->TextWidth(0, FontSize
, pDisplayStr
, s_AtIndex
);
325 if(w
-*Offset
> Textbox
.w
)
328 float wt
= TextRender()->TextWidth(0, FontSize
, pDisplayStr
, -1);
331 *Offset
+= min(wt
-*Offset
-Textbox
.w
, Textbox
.w
/3);
333 while(w
-*Offset
> Textbox
.w
);
335 else if(w
-*Offset
< 0.0f
)
340 *Offset
= max(0.0f
, *Offset
-Textbox
.w
/3);
342 while(w
-*Offset
< 0.0f
);
345 UI()->ClipEnable(pRect
);
346 Textbox
.x
-= *Offset
;
348 UI()->DoLabel(&Textbox
, pDisplayStr
, FontSize
, -1);
351 if(UI()->LastActiveItem() == pID
&& !JustGotActive
)
353 float w
= TextRender()->TextWidth(0, FontSize
, pDisplayStr
, s_AtIndex
);
355 Textbox
.VSplitLeft(2.0f
, 0, &Textbox
);
356 Textbox
.x
+= (w
-*Offset
-TextRender()->TextWidth(0, FontSize
, "|", -1)/2);
358 if((2*time_get()/time_freq()) % 2) // make it blink
359 UI()->DoLabel(&Textbox
, "|", FontSize
, -1);
366 vec4
CEditor::ButtonColorMul(const void *pID
)
368 if(UI()->ActiveItem() == pID
)
369 return vec4(1,1,1,0.5f
);
370 else if(UI()->HotItem() == pID
)
371 return vec4(1,1,1,1.5f
);
372 return vec4(1,1,1,1);
375 float CEditor::UiDoScrollbarV(const void *pID
, const CUIRect
*pRect
, float Current
)
378 static float s_OffsetY
;
379 pRect
->HSplitTop(33, &Handle
, 0);
381 Handle
.y
+= (pRect
->h
-Handle
.h
)*Current
;
385 int Inside
= UI()->MouseInside(&Handle
);
387 if(UI()->ActiveItem() == pID
)
389 if(!UI()->MouseButton(0))
390 UI()->SetActiveItem(0);
392 float Min
= pRect
->y
;
393 float Max
= pRect
->h
-Handle
.h
;
394 float Cur
= UI()->MouseY()-s_OffsetY
;
396 if(Ret
< 0.0f
) Ret
= 0.0f
;
397 if(Ret
> 1.0f
) Ret
= 1.0f
;
399 else if(UI()->HotItem() == pID
)
401 if(UI()->MouseButton(0))
403 UI()->SetActiveItem(pID
);
404 s_OffsetY
= UI()->MouseY()-Handle
.y
;
409 UI()->SetHotItem(pID
);
413 pRect
->VMargin(5.0f
, &Rail
);
414 RenderTools()->DrawUIRect(&Rail
, vec4(1,1,1,0.25f
), 0, 0.0f
);
416 CUIRect Slider
= Handle
;
417 Slider
.w
= Rail
.x
-Slider
.x
;
418 RenderTools()->DrawUIRect(&Slider
, vec4(1,1,1,0.25f
), CUI::CORNER_L
, 2.5f
);
419 Slider
.x
= Rail
.x
+Rail
.w
;
420 RenderTools()->DrawUIRect(&Slider
, vec4(1,1,1,0.25f
), CUI::CORNER_R
, 2.5f
);
423 Slider
.Margin(5.0f
, &Slider
);
424 RenderTools()->DrawUIRect(&Slider
, vec4(1,1,1,0.25f
)*ButtonColorMul(pID
), CUI::CORNER_ALL
, 2.5f
);
429 vec4
CEditor::GetButtonColor(const void *pID
, int Checked
)
432 return vec4(0,0,0,0.5f
);
436 if(UI()->HotItem() == pID
)
437 return vec4(1,0,0,0.75f
);
438 return vec4(1,0,0,0.5f
);
441 if(UI()->HotItem() == pID
)
442 return vec4(1,1,1,0.75f
);
443 return vec4(1,1,1,0.5f
);
446 int CEditor::DoButton_Editor_Common(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
448 if(UI()->MouseInside(pRect
))
450 if(Flags
&BUTTON_CONTEXT
)
451 ms_pUiGotContext
= pID
;
453 m_pTooltip
= pToolTip
;
456 if(UI()->HotItem() == pID
&& pToolTip
)
457 m_pTooltip
= (const char *)pToolTip
;
459 return UI()->DoButtonLogic(pID
, pText
, Checked
, pRect
);
462 //return UI()->DoButton(id, text, checked, r, draw_func, 0);
466 int CEditor::DoButton_Editor(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
468 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_ALL
, 3.0f
);
469 CUIRect NewRect
= *pRect
;
470 NewRect
.y
+= NewRect
.h
/2.0f
-7.0f
;
471 float tw
= min(TextRender()->TextWidth(0, 10.0f
, pText
, -1), NewRect
.w
);
473 TextRender()->SetCursor(&Cursor
, NewRect
.x
+ NewRect
.w
/2-tw
/2, NewRect
.y
- 1.0f
, 10.0f
, TEXTFLAG_RENDER
|TEXTFLAG_STOP_AT_END
);
474 Cursor
.m_LineWidth
= NewRect
.w
;
475 TextRender()->TextEx(&Cursor
, pText
, -1);
476 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
479 int CEditor::DoButton_File(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
482 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_ALL
, 3.0f
);
486 UI()->DoLabel(&t
, pText
, 10, -1, -1);
487 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
490 int CEditor::DoButton_Menu(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
493 RenderTools()->DrawUIRect(&r
, vec4(0.5f
, 0.5f
, 0.5f
, 1.0f
), CUI::CORNER_T
, 3.0f
);
497 UI()->DoLabel(&r
, pText
, 10, -1, -1);
498 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
501 int CEditor::DoButton_MenuItem(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
503 if(UI()->HotItem() == pID
|| Checked
)
504 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_ALL
, 3.0f
);
509 TextRender()->SetCursor(&Cursor
, t
.x
, t
.y
- 1.0f
, 10.0f
, TEXTFLAG_RENDER
|TEXTFLAG_STOP_AT_END
);
510 Cursor
.m_LineWidth
= t
.w
;
511 TextRender()->TextEx(&Cursor
, pText
, -1);
512 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
515 int CEditor::DoButton_Tab(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
517 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_T
, 5.0f
);
518 CUIRect NewRect
= *pRect
;
519 NewRect
.y
+= NewRect
.h
/2.0f
-7.0f
;
520 UI()->DoLabel(&NewRect
, pText
, 10, 0, -1);
521 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
524 int CEditor::DoButton_Ex(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
, int Corners
, float FontSize
)
526 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), Corners
, 3.0f
);
527 CUIRect NewRect
= *pRect
;
528 NewRect
.HMargin(NewRect
.h
/2.0f
-FontSize
/2.0f
-1.0f
, &NewRect
);
529 UI()->DoLabel(&NewRect
, pText
, FontSize
, 0, -1);
530 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
533 int CEditor::DoButton_ButtonInc(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
535 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_R
, 3.0f
);
536 UI()->DoLabel(pRect
, pText
?pText
:"+", 10, 0, -1);
537 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
540 int CEditor::DoButton_ButtonDec(const void *pID
, const char *pText
, int Checked
, const CUIRect
*pRect
, int Flags
, const char *pToolTip
)
542 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, Checked
), CUI::CORNER_L
, 3.0f
);
543 UI()->DoLabel(pRect
, pText
?pText
:"-", 10, 0, -1);
544 return DoButton_Editor_Common(pID
, pText
, Checked
, pRect
, Flags
, pToolTip
);
547 void CEditor::RenderGrid(CLayerGroup
*pGroup
)
552 float aGroupPoints
[4];
553 pGroup
->Mapping(aGroupPoints
);
555 float w
= UI()->Screen()->w
;
556 float h
= UI()->Screen()->h
;
558 int LineDistance
= GetLineDistance();
560 int XOffset
= aGroupPoints
[0]/LineDistance
;
561 int YOffset
= aGroupPoints
[1]/LineDistance
;
562 int XGridOffset
= XOffset
% m_GridFactor
;
563 int YGridOffset
= YOffset
% m_GridFactor
;
565 Graphics()->TextureSet(-1);
566 Graphics()->LinesBegin();
568 for(int i
= 0; i
< (int)w
; i
++)
570 if((i
+YGridOffset
) % m_GridFactor
== 0)
571 Graphics()->SetColor(1.0f
, 0.3f
, 0.3f
, 0.3f
);
573 Graphics()->SetColor(1.0f
, 1.0f
, 1.0f
, 0.15f
);
575 IGraphics::CLineItem Line
= IGraphics::CLineItem(LineDistance
*XOffset
, LineDistance
*i
+LineDistance
*YOffset
, w
+aGroupPoints
[2], LineDistance
*i
+LineDistance
*YOffset
);
576 Graphics()->LinesDraw(&Line
, 1);
578 if((i
+XGridOffset
) % m_GridFactor
== 0)
579 Graphics()->SetColor(1.0f
, 0.3f
, 0.3f
, 0.3f
);
581 Graphics()->SetColor(1.0f
, 1.0f
, 1.0f
, 0.15f
);
583 Line
= IGraphics::CLineItem(LineDistance
*i
+LineDistance
*XOffset
, LineDistance
*YOffset
, LineDistance
*i
+LineDistance
*XOffset
, h
+aGroupPoints
[3]);
584 Graphics()->LinesDraw(&Line
, 1);
586 Graphics()->SetColor(1.0f
, 1.0f
, 1.0f
, 1.0f
);
587 Graphics()->LinesEnd();
590 void CEditor::RenderBackground(CUIRect View
, int Texture
, float Size
, float Brightness
)
592 Graphics()->TextureSet(Texture
);
593 Graphics()->BlendNormal();
594 Graphics()->QuadsBegin();
595 Graphics()->SetColor(Brightness
, Brightness
, Brightness
, 1.0f
);
596 Graphics()->QuadsSetSubset(0,0, View
.w
/Size
, View
.h
/Size
);
597 IGraphics::CQuadItem
QuadItem(View
.x
, View
.y
, View
.w
, View
.h
);
598 Graphics()->QuadsDrawTL(&QuadItem
, 1);
599 Graphics()->QuadsEnd();
602 int CEditor::UiDoValueSelector(void *pID
, CUIRect
*pRect
, const char *pLabel
, int Current
, int Min
, int Max
, int Step
, float Scale
, const char *pToolTip
)
605 static float s_Value
;
606 int Inside
= UI()->MouseInside(pRect
);
608 if(UI()->ActiveItem() == pID
)
610 if(!UI()->MouseButton(0))
613 UI()->SetActiveItem(0);
617 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
618 s_Value
+= m_MouseDeltaX
*0.05f
;
620 s_Value
+= m_MouseDeltaX
;
622 if(absolute(s_Value
) > Scale
)
624 int Count
= (int)(s_Value
/Scale
);
625 s_Value
= fmod(s_Value
, Scale
);
626 Current
+= Step
*Count
;
634 m_pTooltip
= pToolTip
;
636 else if(UI()->HotItem() == pID
)
638 if(UI()->MouseButton(0))
642 UI()->SetActiveItem(pID
);
645 m_pTooltip
= pToolTip
;
649 UI()->SetHotItem(pID
);
653 str_format(aBuf
, sizeof(aBuf
),"%s %d", pLabel
, Current
);
654 RenderTools()->DrawUIRect(pRect
, GetButtonColor(pID
, 0), CUI::CORNER_ALL
, 5.0f
);
655 pRect
->y
+= pRect
->h
/2.0f
-7.0f
;
656 UI()->DoLabel(pRect
, aBuf
, 10, 0, -1);
661 CLayerGroup
*CEditor::GetSelectedGroup()
663 if(m_SelectedGroup
>= 0 && m_SelectedGroup
< m_Map
.m_lGroups
.size())
664 return m_Map
.m_lGroups
[m_SelectedGroup
];
668 CLayer
*CEditor::GetSelectedLayer(int Index
)
670 CLayerGroup
*pGroup
= GetSelectedGroup();
674 if(m_SelectedLayer
>= 0 && m_SelectedLayer
< m_Map
.m_lGroups
[m_SelectedGroup
]->m_lLayers
.size())
675 return pGroup
->m_lLayers
[m_SelectedLayer
];
679 CLayer
*CEditor::GetSelectedLayerType(int Index
, int Type
)
681 CLayer
*p
= GetSelectedLayer(Index
);
682 if(p
&& p
->m_Type
== Type
)
687 CQuad
*CEditor::GetSelectedQuad()
689 CLayerQuads
*ql
= (CLayerQuads
*)GetSelectedLayerType(0, LAYERTYPE_QUADS
);
692 if(m_SelectedQuad
>= 0 && m_SelectedQuad
< ql
->m_lQuads
.size())
693 return &ql
->m_lQuads
[m_SelectedQuad
];
697 void CEditor::CallbackOpenMap(const char *pFileName
, int StorageType
, void *pUser
)
699 CEditor
*pEditor
= (CEditor
*)pUser
;
700 if(pEditor
->Load(pFileName
, StorageType
))
702 str_copy(pEditor
->m_aFileName
, pFileName
, 512);
703 pEditor
->m_ValidSaveFilename
= StorageType
== IStorage::TYPE_SAVE
&& pEditor
->m_pFileDialogPath
== pEditor
->m_aFileDialogCurrentFolder
;
704 pEditor
->SortImages();
705 pEditor
->m_Dialog
= DIALOG_NONE
;
706 pEditor
->m_Map
.m_Modified
= false;
709 void CEditor::CallbackAppendMap(const char *pFileName
, int StorageType
, void *pUser
)
711 CEditor
*pEditor
= (CEditor
*)pUser
;
712 if(pEditor
->Append(pFileName
, StorageType
))
713 pEditor
->m_aFileName
[0] = 0;
715 pEditor
->SortImages();
717 pEditor
->m_Dialog
= DIALOG_NONE
;
719 void CEditor::CallbackSaveMap(const char *pFileName
, int StorageType
, void *pUser
)
721 CEditor
*pEditor
= static_cast<CEditor
*>(pUser
);
723 const int Length
= str_length(pFileName
);
725 if(Length
<= 4 || pFileName
[Length
-4] != '.' || str_comp_nocase(pFileName
+Length
-3, "map"))
727 str_format(aBuf
, sizeof(aBuf
), "%s.map", pFileName
);
731 if(pEditor
->Save(pFileName
))
733 str_copy(pEditor
->m_aFileName
, pFileName
, sizeof(pEditor
->m_aFileName
));
734 pEditor
->m_ValidSaveFilename
= StorageType
== IStorage::TYPE_SAVE
&& pEditor
->m_pFileDialogPath
== pEditor
->m_aFileDialogCurrentFolder
;
735 pEditor
->m_Map
.m_Modified
= false;
738 pEditor
->m_Dialog
= DIALOG_NONE
;
741 void CEditor::DoToolbar(CUIRect ToolBar
)
743 CUIRect TB_Top
, TB_Bottom
;
746 ToolBar
.HSplitTop(ToolBar
.h
/2.0f
, &TB_Top
, &TB_Bottom
);
748 TB_Top
.HSplitBottom(2.5f
, &TB_Top
, 0);
749 TB_Bottom
.HSplitTop(2.5f
, 0, &TB_Bottom
);
752 if(Input()->KeyDown('o') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
)) && m_Dialog
== DIALOG_NONE
)
756 if(!m_PopupEventWasActivated
)
758 m_PopupEventType
= POPEVENT_LOAD
;
759 m_PopupEventActivated
= true;
763 InvokeFileDialog(IStorage::TYPE_ALL
, FILETYPE_MAP
, "Load map", "Load", "maps", "", CallbackOpenMap
, this);
767 if(Input()->KeyDown('s') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
)) && m_Dialog
== DIALOG_NONE
)
769 if(m_aFileName
[0] && m_ValidSaveFilename
)
771 if(!m_PopupEventWasActivated
)
773 str_copy(m_aFileSaveName
, m_aFileName
, sizeof(m_aFileSaveName
));
774 m_PopupEventType
= POPEVENT_SAVE
;
775 m_PopupEventActivated
= true;
779 InvokeFileDialog(IStorage::TYPE_SAVE
, FILETYPE_MAP
, "Save map", "Save", "maps", "", CallbackSaveMap
, this);
783 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
784 static int s_HqButton
= 0;
785 if(DoButton_Editor(&s_HqButton
, "HD", m_ShowDetail
, &Button
, 0, "[ctrl+h] Toggle High Detail") ||
786 (Input()->KeyDown('h') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
))))
788 m_ShowDetail
= !m_ShowDetail
;
791 TB_Top
.VSplitLeft(5.0f
, 0, &TB_Top
);
794 TB_Top
.VSplitLeft(40.0f
, &Button
, &TB_Top
);
795 static int s_AnimateButton
= 0;
796 if(DoButton_Editor(&s_AnimateButton
, "Anim", m_Animate
, &Button
, 0, "[ctrl+m] Toggle animation") ||
797 (Input()->KeyDown('m') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
))))
799 m_AnimateStart
= time_get();
800 m_Animate
= !m_Animate
;
803 TB_Top
.VSplitLeft(5.0f
, 0, &TB_Top
);
806 TB_Top
.VSplitLeft(40.0f
, &Button
, &TB_Top
);
807 static int s_ProofButton
= 0;
808 if(DoButton_Editor(&s_ProofButton
, "Proof", m_ProofBorders
, &Button
, 0, "[ctrl+p] Toggles proof borders. These borders represent what a player maximum can see.") ||
809 (Input()->KeyDown('p') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
))))
811 m_ProofBorders
= !m_ProofBorders
;
814 TB_Top
.VSplitLeft(5.0f
, 0, &TB_Top
);
817 TB_Top
.VSplitLeft(40.0f
, &Button
, &TB_Top
);
818 static int s_TileInfoButton
= 0;
819 if(DoButton_Editor(&s_TileInfoButton
, "Info", m_ShowTileInfo
, &Button
, 0, "[ctrl+i] Show tile informations") ||
820 (Input()->KeyDown('i') && (Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
))))
822 m_ShowTileInfo
= !m_ShowTileInfo
;
823 m_ShowEnvelopePreview
= 0;
826 TB_Top
.VSplitLeft(15.0f
, 0, &TB_Top
);
829 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
830 static int s_ZoomOutButton
= 0;
831 if(DoButton_Ex(&s_ZoomOutButton
, "ZO", 0, &Button
, 0, "[NumPad-] Zoom out", CUI::CORNER_L
) || Input()->KeyDown(KEY_KP_MINUS
))
834 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
835 static int s_ZoomNormalButton
= 0;
836 if(DoButton_Ex(&s_ZoomNormalButton
, "1:1", 0, &Button
, 0, "[NumPad*] Zoom to normal and remove editor offset", 0) || Input()->KeyDown(KEY_KP_MULTIPLY
))
843 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
844 static int s_ZoomInButton
= 0;
845 if(DoButton_Ex(&s_ZoomInButton
, "ZI", 0, &Button
, 0, "[NumPad+] Zoom in", CUI::CORNER_R
) || Input()->KeyDown(KEY_KP_PLUS
))
848 TB_Top
.VSplitLeft(10.0f
, 0, &TB_Top
);
851 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
852 static int s_AnimFasterButton
= 0;
853 if(DoButton_Ex(&s_AnimFasterButton
, "A+", 0, &Button
, 0, "Increase animation speed", CUI::CORNER_L
))
854 m_AnimateSpeed
+= 0.5f
;
856 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
857 static int s_AnimNormalButton
= 0;
858 if(DoButton_Ex(&s_AnimNormalButton
, "1", 0, &Button
, 0, "Normal animation speed", 0))
859 m_AnimateSpeed
= 1.0f
;
861 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
862 static int s_AnimSlowerButton
= 0;
863 if(DoButton_Ex(&s_AnimSlowerButton
, "A-", 0, &Button
, 0, "Decrease animation speed", CUI::CORNER_R
))
865 if(m_AnimateSpeed
> 0.5f
)
866 m_AnimateSpeed
-= 0.5f
;
869 m_WorldZoom
= m_ZoomLevel
/100.0f
;
871 TB_Top
.VSplitLeft(10.0f
, &Button
, &TB_Top
);
874 // brush manipulation
876 int Enabled
= m_Brush
.IsEmpty()?-1:0;
879 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
880 static int s_FlipXButton
= 0;
881 if(DoButton_Ex(&s_FlipXButton
, "X/X", Enabled
, &Button
, 0, "[N] Flip brush horizontal", CUI::CORNER_L
) || Input()->KeyDown('n'))
883 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
884 m_Brush
.m_lLayers
[i
]->BrushFlipX();
887 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
888 static int s_FlipyButton
= 0;
889 if(DoButton_Ex(&s_FlipyButton
, "Y/Y", Enabled
, &Button
, 0, "[M] Flip brush vertical", CUI::CORNER_R
) || Input()->KeyDown('m'))
891 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
892 m_Brush
.m_lLayers
[i
]->BrushFlipY();
896 TB_Top
.VSplitLeft(15.0f
, &Button
, &TB_Top
);
898 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
899 static int s_RotationAmount
= 90;
900 bool TileLayer
= false;
901 // check for tile layers in brush selection
902 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
903 if(m_Brush
.m_lLayers
[i
]->m_Type
== LAYERTYPE_TILES
)
906 s_RotationAmount
= max(90, (s_RotationAmount
/90)*90);
909 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.");
911 TB_Top
.VSplitLeft(5.0f
, &Button
, &TB_Top
);
912 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
913 static int s_CcwButton
= 0;
914 if(DoButton_Ex(&s_CcwButton
, "CCW", Enabled
, &Button
, 0, "[R] Rotates the brush counter clockwise", CUI::CORNER_L
) || Input()->KeyDown('r'))
916 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
917 m_Brush
.m_lLayers
[i
]->BrushRotate(-s_RotationAmount
/360.0f
*pi
*2);
920 TB_Top
.VSplitLeft(30.0f
, &Button
, &TB_Top
);
921 static int s_CwButton
= 0;
922 if(DoButton_Ex(&s_CwButton
, "CW", Enabled
, &Button
, 0, "[T] Rotates the brush clockwise", CUI::CORNER_R
) || Input()->KeyDown('t'))
924 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
925 m_Brush
.m_lLayers
[i
]->BrushRotate(s_RotationAmount
/360.0f
*pi
*2);
932 TB_Top
.VSplitLeft(10.0f
, &Button
, &TB_Top
);
933 TB_Top
.VSplitLeft(60.0f
, &Button
, &TB_Top
);
934 static int s_NewButton
= 0;
936 CLayerQuads
*pQLayer
= (CLayerQuads
*)GetSelectedLayerType(0, LAYERTYPE_QUADS
);
937 //CLayerTiles *tlayer = (CLayerTiles *)get_selected_layer_type(0, LAYERTYPE_TILES);
938 if(DoButton_Editor(&s_NewButton
, "Add Quad", pQLayer
?0:-1, &Button
, 0, "Adds a new quad"))
943 CLayerGroup
*g
= GetSelectedGroup();
945 int AddX
= f2fx(Mapping
[0] + (Mapping
[2]-Mapping
[0])/2);
946 int AddY
= f2fx(Mapping
[1] + (Mapping
[3]-Mapping
[1])/2);
948 CQuad
*q
= pQLayer
->NewQuad();
949 for(int i
= 0; i
< 5; i
++)
951 q
->m_aPoints
[i
].x
+= AddX
;
952 q
->m_aPoints
[i
].y
+= AddY
;
960 TB_Bottom
.VSplitLeft(40.0f
, &Button
, &TB_Bottom
);
961 static int s_BorderBut
= 0;
962 CLayerTiles
*pT
= (CLayerTiles
*)GetSelectedLayerType(0, LAYERTYPE_TILES
);
964 if(DoButton_Editor(&s_BorderBut
, "Border", pT
?0:-1, &Button
, 0, "Adds border tiles"))
971 TB_Bottom
.VSplitLeft(5.0f
, 0, &TB_Bottom
);
974 TB_Bottom
.VSplitLeft(50.0f
, &Button
, &TB_Bottom
);
975 static int s_RefocusButton
= 0;
976 if(DoButton_Editor(&s_RefocusButton
, "Refocus", m_WorldOffsetX
&&m_WorldOffsetY
?0:-1, &Button
, 0, "[HOME] Restore map focus") || Input()->KeyDown(KEY_HOME
))
982 TB_Bottom
.VSplitLeft(5.0f
, 0, &TB_Bottom
);
985 TB_Bottom
.VSplitLeft(50.0f
, &Button
, &TB_Bottom
);
986 static int s_GridButton
= 0;
987 if(DoButton_Editor(&s_GridButton
, "Grid", m_GridActive
, &Button
, 0, "Toggle Grid"))
989 m_GridActive
= !m_GridActive
;
992 TB_Bottom
.VSplitLeft(30.0f
, 0, &TB_Bottom
);
995 TB_Bottom
.VSplitLeft(30.0f
, &Button
, &TB_Bottom
);
996 static int s_GridIncreaseButton
= 0;
997 if(DoButton_Ex(&s_GridIncreaseButton
, "G-", 0, &Button
, 0, "Decrease grid", CUI::CORNER_L
))
1003 TB_Bottom
.VSplitLeft(30.0f
, &Button
, &TB_Bottom
);
1004 static int s_GridNormalButton
= 0;
1005 if(DoButton_Ex(&s_GridNormalButton
, "1", 0, &Button
, 0, "Normal grid", 0))
1008 TB_Bottom
.VSplitLeft(30.0f
, &Button
, &TB_Bottom
);
1010 static int s_GridDecreaseButton
= 0;
1011 if(DoButton_Ex(&s_GridDecreaseButton
, "G+", 0, &Button
, 0, "Increase grid", CUI::CORNER_R
))
1013 if(m_GridFactor
< 15)
1018 static void Rotate(CPoint
*pCenter
, CPoint
*pPoint
, float Rotation
)
1020 int x
= pPoint
->x
- pCenter
->x
;
1021 int y
= pPoint
->y
- pCenter
->y
;
1022 pPoint
->x
= (int)(x
* cosf(Rotation
) - y
* sinf(Rotation
) + pCenter
->x
);
1023 pPoint
->y
= (int)(x
* sinf(Rotation
) + y
* cosf(Rotation
) + pCenter
->y
);
1026 void CEditor::DoQuad(CQuad
*q
, int Index
)
1037 // some basic values
1038 void *pID
= &q
->m_aPoints
[4]; // use pivot addr as id
1039 static CPoint s_RotatePoints
[4];
1040 static float s_LastWx
;
1041 static float s_LastWy
;
1042 static int s_Operation
= OP_NONE
;
1043 static float s_RotateAngle
= 0;
1044 float wx
= UI()->MouseWorldX();
1045 float wy
= UI()->MouseWorldY();
1048 float CenterX
= fx2f(q
->m_aPoints
[4].x
);
1049 float CenterY
= fx2f(q
->m_aPoints
[4].y
);
1051 float dx
= (CenterX
- wx
)/m_WorldZoom
;
1052 float dy
= (CenterY
- wy
)/m_WorldZoom
;
1053 if(dx
*dx
+dy
*dy
< 50)
1054 UI()->SetHotItem(pID
);
1056 // draw selection background
1057 if(m_SelectedQuad
== Index
)
1059 Graphics()->SetColor(0,0,0,1);
1060 IGraphics::CQuadItem
QuadItem(CenterX
, CenterY
, 7.0f
, 7.0f
);
1061 Graphics()->QuadsDraw(&QuadItem
, 1);
1064 if(UI()->ActiveItem() == pID
)
1066 if(m_MouseDeltaWx
*m_MouseDeltaWx
+m_MouseDeltaWy
*m_MouseDeltaWy
> 0.5f
)
1068 // check if we only should move pivot
1069 if(s_Operation
== OP_MOVE_PIVOT
)
1073 int LineDistance
= GetLineDistance();
1078 x
= (int)((wx
+(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1080 x
= (int)((wx
-(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1082 y
= (int)((wy
+(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1084 y
= (int)((wy
-(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1086 q
->m_aPoints
[4].x
= f2fx(x
);
1087 q
->m_aPoints
[4].y
= f2fx(y
);
1091 q
->m_aPoints
[4].x
+= f2fx(wx
-s_LastWx
);
1092 q
->m_aPoints
[4].y
+= f2fx(wy
-s_LastWy
);
1095 else if(s_Operation
== OP_MOVE_ALL
)
1097 // move all points including pivot
1100 int LineDistance
= GetLineDistance();
1105 x
= (int)((wx
+(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1107 x
= (int)((wx
-(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1109 y
= (int)((wy
+(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1111 y
= (int)((wy
-(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1113 int OldX
= q
->m_aPoints
[4].x
;
1114 int OldY
= q
->m_aPoints
[4].y
;
1115 q
->m_aPoints
[4].x
= f2fx(x
);
1116 q
->m_aPoints
[4].y
= f2fx(y
);
1117 int DiffX
= q
->m_aPoints
[4].x
- OldX
;
1118 int DiffY
= q
->m_aPoints
[4].y
- OldY
;
1120 for(int v
= 0; v
< 4; v
++)
1122 q
->m_aPoints
[v
].x
+= DiffX
;
1123 q
->m_aPoints
[v
].y
+= DiffY
;
1128 for(int v
= 0; v
< 5; v
++)
1130 q
->m_aPoints
[v
].x
+= f2fx(wx
-s_LastWx
);
1131 q
->m_aPoints
[v
].y
+= f2fx(wy
-s_LastWy
);
1135 else if(s_Operation
== OP_ROTATE
)
1137 for(int v
= 0; v
< 4; v
++)
1139 q
->m_aPoints
[v
] = s_RotatePoints
[v
];
1140 Rotate(&q
->m_aPoints
[4], &q
->m_aPoints
[v
], s_RotateAngle
);
1145 s_RotateAngle
+= (m_MouseDeltaX
) * 0.002f
;
1149 if(s_Operation
== OP_CONTEXT_MENU
)
1151 if(!UI()->MouseButton(1))
1153 static int s_QuadPopupID
= 0;
1154 UiInvokePopupMenu(&s_QuadPopupID
, 0, UI()->MouseX(), UI()->MouseY(), 120, 180, PopupQuad
);
1155 m_LockMouse
= false;
1156 s_Operation
= OP_NONE
;
1157 UI()->SetActiveItem(0);
1162 if(!UI()->MouseButton(0))
1164 m_LockMouse
= false;
1165 s_Operation
= OP_NONE
;
1166 UI()->SetActiveItem(0);
1170 Graphics()->SetColor(1,1,1,1);
1172 else if(UI()->HotItem() == pID
)
1174 ms_pUiGotContext
= pID
;
1176 Graphics()->SetColor(1,1,1,1);
1177 m_pTooltip
= "Left mouse button to move. Hold shift to move pivot. Hold ctrl to rotate.";
1179 if(UI()->MouseButton(0))
1181 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
1182 s_Operation
= OP_MOVE_PIVOT
;
1183 else if(Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
))
1186 s_Operation
= OP_ROTATE
;
1188 s_RotatePoints
[0] = q
->m_aPoints
[0];
1189 s_RotatePoints
[1] = q
->m_aPoints
[1];
1190 s_RotatePoints
[2] = q
->m_aPoints
[2];
1191 s_RotatePoints
[3] = q
->m_aPoints
[3];
1194 s_Operation
= OP_MOVE_ALL
;
1196 UI()->SetActiveItem(pID
);
1197 if(m_SelectedQuad
!= Index
)
1198 m_SelectedPoints
= 0;
1199 m_SelectedQuad
= Index
;
1204 if(UI()->MouseButton(1))
1206 if(m_SelectedQuad
!= Index
)
1207 m_SelectedPoints
= 0;
1208 m_SelectedQuad
= Index
;
1209 s_Operation
= OP_CONTEXT_MENU
;
1210 UI()->SetActiveItem(pID
);
1214 Graphics()->SetColor(0,1,0,1);
1216 IGraphics::CQuadItem
QuadItem(CenterX
, CenterY
, 5.0f
*m_WorldZoom
, 5.0f
*m_WorldZoom
);
1217 Graphics()->QuadsDraw(&QuadItem
, 1);
1220 void CEditor::DoQuadPoint(CQuad
*pQuad
, int QuadIndex
, int V
)
1222 void *pID
= &pQuad
->m_aPoints
[V
];
1224 float wx
= UI()->MouseWorldX();
1225 float wy
= UI()->MouseWorldY();
1227 float px
= fx2f(pQuad
->m_aPoints
[V
].x
);
1228 float py
= fx2f(pQuad
->m_aPoints
[V
].y
);
1230 float dx
= (px
- wx
)/m_WorldZoom
;
1231 float dy
= (py
- wy
)/m_WorldZoom
;
1232 if(dx
*dx
+dy
*dy
< 50)
1233 UI()->SetHotItem(pID
);
1235 // draw selection background
1236 if(m_SelectedQuad
== QuadIndex
&& m_SelectedPoints
&(1<<V
))
1238 Graphics()->SetColor(0,0,0,1);
1239 IGraphics::CQuadItem
QuadItem(px
, py
, 7.0f
, 7.0f
);
1240 Graphics()->QuadsDraw(&QuadItem
, 1);
1251 static bool s_Moved
;
1252 static int s_Operation
= OP_NONE
;
1254 if(UI()->ActiveItem() == pID
)
1256 float dx
= m_MouseDeltaWx
;
1257 float dy
= m_MouseDeltaWy
;
1260 if(dx
*dx
+dy
*dy
> 0.5f
)
1266 if(s_Operation
== OP_MOVEPOINT
)
1270 for(int m
= 0; m
< 4; m
++)
1271 if(m_SelectedPoints
&(1<<m
))
1273 int LineDistance
= GetLineDistance();
1278 x
= (int)((wx
+(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1280 x
= (int)((wx
-(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1282 y
= (int)((wy
+(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1284 y
= (int)((wy
-(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1286 pQuad
->m_aPoints
[m
].x
= f2fx(x
);
1287 pQuad
->m_aPoints
[m
].y
= f2fx(y
);
1292 for(int m
= 0; m
< 4; m
++)
1293 if(m_SelectedPoints
&(1<<m
))
1295 pQuad
->m_aPoints
[m
].x
+= f2fx(dx
);
1296 pQuad
->m_aPoints
[m
].y
+= f2fx(dy
);
1300 else if(s_Operation
== OP_MOVEUV
)
1302 for(int m
= 0; m
< 4; m
++)
1303 if(m_SelectedPoints
&(1<<m
))
1308 pQuad
->m_aTexcoords
[m
].x
+= f2fx(dx
*0.001f
);
1309 pQuad
->m_aTexcoords
[(m
+2)%4].x
+= f2fx(dx
*0.001f
);
1311 pQuad
->m_aTexcoords
[m
].y
+= f2fx(dy
*0.001f
);
1312 pQuad
->m_aTexcoords
[m
^1].y
+= f2fx(dy
*0.001f
);
1317 if(s_Operation
== OP_CONTEXT_MENU
)
1319 if(!UI()->MouseButton(1))
1321 static int s_PointPopupID
= 0;
1322 UiInvokePopupMenu(&s_PointPopupID
, 0, UI()->MouseX(), UI()->MouseY(), 120, 150, PopupPoint
);
1323 UI()->SetActiveItem(0);
1328 if(!UI()->MouseButton(0))
1332 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
1333 m_SelectedPoints
^= 1<<V
;
1335 m_SelectedPoints
= 1<<V
;
1337 m_LockMouse
= false;
1338 UI()->SetActiveItem(0);
1342 Graphics()->SetColor(1,1,1,1);
1344 else if(UI()->HotItem() == pID
)
1346 ms_pUiGotContext
= pID
;
1348 Graphics()->SetColor(1,1,1,1);
1349 m_pTooltip
= "Left mouse button to move. Hold shift to move the texture.";
1351 if(UI()->MouseButton(0))
1353 UI()->SetActiveItem(pID
);
1355 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
1357 s_Operation
= OP_MOVEUV
;
1361 s_Operation
= OP_MOVEPOINT
;
1363 if(!(m_SelectedPoints
&(1<<V
)))
1365 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
1366 m_SelectedPoints
|= 1<<V
;
1368 m_SelectedPoints
= 1<<V
;
1371 m_SelectedQuad
= QuadIndex
;
1373 else if(UI()->MouseButton(1))
1375 s_Operation
= OP_CONTEXT_MENU
;
1376 m_SelectedQuad
= QuadIndex
;
1377 UI()->SetActiveItem(pID
);
1378 if(!(m_SelectedPoints
&(1<<V
)))
1380 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
1381 m_SelectedPoints
|= 1<<V
;
1383 m_SelectedPoints
= 1<<V
;
1389 Graphics()->SetColor(1,0,0,1);
1391 IGraphics::CQuadItem
QuadItem(px
, py
, 5.0f
*m_WorldZoom
, 5.0f
*m_WorldZoom
);
1392 Graphics()->QuadsDraw(&QuadItem
, 1);
1395 void CEditor::DoQuadEnvelopes(CQuad
*pQuad
, int Index
, int TexID
)
1397 CEnvelope
*pEnvelope
= 0x0;
1398 if(pQuad
->m_PosEnv
>= 0 && pQuad
->m_PosEnv
< m_Map
.m_lEnvelopes
.size())
1399 pEnvelope
= m_Map
.m_lEnvelopes
[pQuad
->m_PosEnv
];
1404 CPoint
*pPoints
= pQuad
->m_aPoints
;
1407 Graphics()->TextureSet(-1);
1408 Graphics()->LinesBegin();
1409 Graphics()->SetColor(80.0f
/255, 150.0f
/255, 230.f
/255, 0.5f
);
1410 for(int i
= 0; i
< pEnvelope
->m_lPoints
.size()-1; i
++)
1412 float OffsetX
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[0]);
1413 float OffsetY
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[1]);
1414 vec2 Pos0
= vec2(fx2f(pPoints
[4].x
)+OffsetX
, fx2f(pPoints
[4].y
)+OffsetY
);
1416 OffsetX
= fx2f(pEnvelope
->m_lPoints
[i
+1].m_aValues
[0]);
1417 OffsetY
= fx2f(pEnvelope
->m_lPoints
[i
+1].m_aValues
[1]);
1418 vec2 Pos1
= vec2(fx2f(pPoints
[4].x
)+OffsetX
, fx2f(pPoints
[4].y
)+OffsetY
);
1420 IGraphics::CLineItem Line
= IGraphics::CLineItem(Pos0
.x
, Pos0
.y
, Pos1
.x
, Pos1
.y
);
1421 Graphics()->LinesDraw(&Line
, 1);
1423 Graphics()->SetColor(1.0f
, 1.0f
, 1.0f
, 1.0f
);
1424 Graphics()->LinesEnd();
1427 for(int i
= 0; i
< pEnvelope
->m_lPoints
.size(); i
++)
1429 Graphics()->TextureSet(TexID
);
1430 Graphics()->QuadsBegin();
1433 float OffsetX
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[0]);
1434 float OffsetY
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[1]);
1435 float Rot
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[2])/360.0f
*pi
*2;
1438 float Alpha
= (m_SelectedQuadEnvelope
== pQuad
->m_PosEnv
&& m_SelectedEnvelopePoint
== i
) ? 0.65f
: 0.35f
;
1439 IGraphics::CColorVertex aArray
[4] = {
1440 IGraphics::CColorVertex(0, pQuad
->m_aColors
[0].r
, pQuad
->m_aColors
[0].g
, pQuad
->m_aColors
[0].b
, Alpha
),
1441 IGraphics::CColorVertex(1, pQuad
->m_aColors
[1].r
, pQuad
->m_aColors
[1].g
, pQuad
->m_aColors
[1].b
, Alpha
),
1442 IGraphics::CColorVertex(2, pQuad
->m_aColors
[2].r
, pQuad
->m_aColors
[2].g
, pQuad
->m_aColors
[2].b
, Alpha
),
1443 IGraphics::CColorVertex(3, pQuad
->m_aColors
[3].r
, pQuad
->m_aColors
[3].g
, pQuad
->m_aColors
[3].b
, Alpha
)};
1444 Graphics()->SetColorVertex(aArray
, 4);
1449 static CPoint aRotated
[4];
1450 aRotated
[0] = pQuad
->m_aPoints
[0];
1451 aRotated
[1] = pQuad
->m_aPoints
[1];
1452 aRotated
[2] = pQuad
->m_aPoints
[2];
1453 aRotated
[3] = pQuad
->m_aPoints
[3];
1456 Rotate(&pQuad
->m_aPoints
[4], &aRotated
[0], Rot
);
1457 Rotate(&pQuad
->m_aPoints
[4], &aRotated
[1], Rot
);
1458 Rotate(&pQuad
->m_aPoints
[4], &aRotated
[2], Rot
);
1459 Rotate(&pQuad
->m_aPoints
[4], &aRotated
[3], Rot
);
1462 //Set Texture Coords
1463 Graphics()->QuadsSetSubsetFree(
1464 fx2f(pQuad
->m_aTexcoords
[0].x
), fx2f(pQuad
->m_aTexcoords
[0].y
),
1465 fx2f(pQuad
->m_aTexcoords
[1].x
), fx2f(pQuad
->m_aTexcoords
[1].y
),
1466 fx2f(pQuad
->m_aTexcoords
[2].x
), fx2f(pQuad
->m_aTexcoords
[2].y
),
1467 fx2f(pQuad
->m_aTexcoords
[3].x
), fx2f(pQuad
->m_aTexcoords
[3].y
)
1470 //Set Quad Coords & Draw
1471 IGraphics::CFreeformItem
Freeform(
1472 fx2f(pPoints
[0].x
)+OffsetX
, fx2f(pPoints
[0].y
)+OffsetY
,
1473 fx2f(pPoints
[1].x
)+OffsetX
, fx2f(pPoints
[1].y
)+OffsetY
,
1474 fx2f(pPoints
[2].x
)+OffsetX
, fx2f(pPoints
[2].y
)+OffsetY
,
1475 fx2f(pPoints
[3].x
)+OffsetX
, fx2f(pPoints
[3].y
)+OffsetY
);
1476 Graphics()->QuadsDrawFreeform(&Freeform
, 1);
1478 Graphics()->QuadsEnd();
1480 Graphics()->TextureSet(-1);
1481 Graphics()->QuadsBegin();
1482 DoQuadEnvPoint(pQuad
, Index
, i
);
1483 Graphics()->QuadsEnd();
1487 void CEditor::DoQuadEnvPoint(CQuad
*pQuad
, int QIndex
, int PIndex
)
1496 // some basic values
1497 static float s_LastWx
;
1498 static float s_LastWy
;
1499 static int s_Operation
= OP_NONE
;
1500 float wx
= UI()->MouseWorldX();
1501 float wy
= UI()->MouseWorldY();
1502 CEnvelope
*pEnvelope
= m_Map
.m_lEnvelopes
[pQuad
->m_PosEnv
];
1503 void *pID
= &pEnvelope
->m_lPoints
[PIndex
];
1504 static int s_ActQIndex
= -1;
1507 float CenterX
= fx2f(pQuad
->m_aPoints
[4].x
)+fx2f(pEnvelope
->m_lPoints
[PIndex
].m_aValues
[0]);
1508 float CenterY
= fx2f(pQuad
->m_aPoints
[4].y
)+fx2f(pEnvelope
->m_lPoints
[PIndex
].m_aValues
[1]);
1510 float dx
= (CenterX
- wx
)/m_WorldZoom
;
1511 float dy
= (CenterY
- wy
)/m_WorldZoom
;
1512 if(dx
*dx
+dy
*dy
< 50.0f
&& UI()->ActiveItem() == 0)
1514 UI()->SetHotItem(pID
);
1515 s_ActQIndex
= QIndex
;
1518 if(UI()->ActiveItem() == pID
&& s_ActQIndex
== QIndex
)
1520 if(s_Operation
== OP_MOVE
)
1524 int LineDistance
= GetLineDistance();
1529 x
= (int)((wx
+(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1531 x
= (int)((wx
-(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1533 y
= (int)((wy
+(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1535 y
= (int)((wy
-(LineDistance
/2)*m_GridFactor
)/(LineDistance
*m_GridFactor
)) * (LineDistance
*m_GridFactor
);
1537 pEnvelope
->m_lPoints
[PIndex
].m_aValues
[0] = f2fx(x
);
1538 pEnvelope
->m_lPoints
[PIndex
].m_aValues
[1] = f2fx(y
);
1542 pEnvelope
->m_lPoints
[PIndex
].m_aValues
[0] += f2fx(wx
-s_LastWx
);
1543 pEnvelope
->m_lPoints
[PIndex
].m_aValues
[1] += f2fx(wy
-s_LastWy
);
1546 else if(s_Operation
== OP_ROTATE
)
1547 pEnvelope
->m_lPoints
[PIndex
].m_aValues
[2] += 10*m_MouseDeltaX
;
1552 if(!UI()->MouseButton(0))
1554 m_LockMouse
= false;
1555 s_Operation
= OP_NONE
;
1556 UI()->SetActiveItem(0);
1559 Graphics()->SetColor(1.0f
, 1.0f
, 1.0f
, 1.0f
);
1561 else if(UI()->HotItem() == pID
&& s_ActQIndex
== QIndex
)
1563 ms_pUiGotContext
= pID
;
1565 Graphics()->SetColor(1.0f
, 1.0f
, 1.0f
, 1.0f
);
1566 m_pTooltip
= "Left mouse button to move. Hold ctrl to rotate.";
1568 if(UI()->MouseButton(0))
1570 if(Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
))
1573 s_Operation
= OP_ROTATE
;
1576 s_Operation
= OP_MOVE
;
1578 m_SelectedEnvelopePoint
= PIndex
;
1579 m_SelectedQuadEnvelope
= pQuad
->m_PosEnv
;
1581 UI()->SetActiveItem(pID
);
1582 if(m_SelectedQuad
!= QIndex
)
1583 m_SelectedPoints
= 0;
1584 m_SelectedQuad
= QIndex
;
1590 m_SelectedEnvelopePoint
= -1;
1591 m_SelectedQuadEnvelope
= -1;
1595 Graphics()->SetColor(0.0f
, 1.0f
, 0.0f
, 1.0f
);
1597 IGraphics::CQuadItem
QuadItem(CenterX
, CenterY
, 5.0f
*m_WorldZoom
, 5.0f
*m_WorldZoom
);
1598 Graphics()->QuadsDraw(&QuadItem
, 1);
1601 void CEditor::DoMapEditor(CUIRect View
, CUIRect ToolBar
)
1603 // render all good stuff
1606 for(int g
= 0; g
< m_Map
.m_lGroups
.size(); g
++)
1608 if(m_Map
.m_lGroups
[g
]->m_Visible
)
1609 m_Map
.m_lGroups
[g
]->Render();
1610 //UI()->ClipEnable(&view);
1613 // render the game above everything else
1614 if(m_Map
.m_pGameGroup
->m_Visible
&& m_Map
.m_pGameLayer
->m_Visible
)
1616 m_Map
.m_pGameGroup
->MapScreen();
1617 m_Map
.m_pGameLayer
->Render();
1620 CLayerTiles
*pT
= static_cast<CLayerTiles
*>(GetSelectedLayerType(0, LAYERTYPE_TILES
));
1621 if(m_ShowTileInfo
&& pT
&& pT
->m_Visible
&& m_ZoomLevel
<= 300)
1623 GetSelectedGroup()->MapScreen();
1628 static void *s_pEditorID
= (void *)&s_pEditorID
;
1629 int Inside
= UI()->MouseInside(&View
);
1631 // fetch mouse position
1632 float wx
= UI()->MouseWorldX();
1633 float wy
= UI()->MouseWorldY();
1634 float mx
= UI()->MouseX();
1635 float my
= UI()->MouseY();
1637 static float s_StartWx
= 0;
1638 static float s_StartWy
= 0;
1650 // remap the screen so it can display the whole tileset
1653 CUIRect Screen
= *UI()->Screen();
1654 float Size
= 32.0*16.0f
;
1655 float w
= Size
*(Screen
.w
/View
.w
);
1656 float h
= Size
*(Screen
.h
/View
.h
);
1657 float x
= -(View
.x
/Screen
.w
)*w
;
1658 float y
= -(View
.y
/Screen
.h
)*h
;
1659 wx
= x
+w
*mx
/Screen
.w
;
1660 wy
= y
+h
*my
/Screen
.h
;
1661 Graphics()->MapScreen(x
, y
, x
+w
, y
+h
);
1662 CLayerTiles
*t
= (CLayerTiles
*)GetSelectedLayerType(0, LAYERTYPE_TILES
);
1665 m_TilesetPicker
.m_Image
= t
->m_Image
;
1666 m_TilesetPicker
.m_TexID
= t
->m_TexID
;
1667 m_TilesetPicker
.Render();
1669 m_TilesetPicker
.ShowInfo();
1673 static int s_Operation
= OP_NONE
;
1675 // draw layer borders
1676 CLayer
*pEditLayers
[16];
1677 int NumEditLayers
= 0;
1682 pEditLayers
[0] = &m_TilesetPicker
;
1687 pEditLayers
[0] = GetSelectedLayer(0);
1691 CLayerGroup
*g
= GetSelectedGroup();
1698 for(int i
= 0; i
< NumEditLayers
; i
++)
1700 if(pEditLayers
[i
]->m_Type
!= LAYERTYPE_TILES
)
1704 pEditLayers
[i
]->GetSize(&w
, &h
);
1706 IGraphics::CLineItem Array
[4] = {
1707 IGraphics::CLineItem(0, 0, w
, 0),
1708 IGraphics::CLineItem(w
, 0, w
, h
),
1709 IGraphics::CLineItem(w
, h
, 0, h
),
1710 IGraphics::CLineItem(0, h
, 0, 0)};
1711 Graphics()->TextureSet(-1);
1712 Graphics()->LinesBegin();
1713 Graphics()->LinesDraw(Array
, 4);
1714 Graphics()->LinesEnd();
1721 UI()->SetHotItem(s_pEditorID
);
1723 // do global operations like pan and zoom
1724 if(UI()->ActiveItem() == 0 && (UI()->MouseButton(0) || UI()->MouseButton(2)))
1729 if(Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
) || UI()->MouseButton(2))
1731 if(Input()->KeyPressed(KEY_LSHIFT
))
1732 s_Operation
= OP_PAN_EDITOR
;
1734 s_Operation
= OP_PAN_WORLD
;
1735 UI()->SetActiveItem(s_pEditorID
);
1740 if(UI()->HotItem() == s_pEditorID
)
1742 if(m_Brush
.IsEmpty())
1743 m_pTooltip
= "Use left mouse button to drag and create a brush.";
1745 m_pTooltip
= "Use left mouse button to paint with the brush. Right button clears the brush.";
1747 if(UI()->ActiveItem() == s_pEditorID
)
1766 if(s_Operation
== OP_BRUSH_DRAW
)
1768 if(!m_Brush
.IsEmpty())
1771 for(int k
= 0; k
< NumEditLayers
; k
++)
1773 if(pEditLayers
[k
]->m_Type
== m_Brush
.m_lLayers
[0]->m_Type
)
1774 pEditLayers
[k
]->BrushDraw(m_Brush
.m_lLayers
[0], wx
, wy
);
1778 else if(s_Operation
== OP_BRUSH_GRAB
)
1780 if(!UI()->MouseButton(0))
1784 str_format(aBuf
, sizeof(aBuf
),"grabbing %f %f %f %f", r
.x
, r
.y
, r
.w
, r
.h
);
1785 Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG
, "editor", aBuf
);
1787 // TODO: do all layers
1789 for(int k
= 0; k
< NumEditLayers
; k
++)
1790 Grabs
+= pEditLayers
[k
]->BrushGrab(&m_Brush
, r
);
1796 //editor.map.groups[selected_group]->mapscreen();
1797 for(int k
= 0; k
< NumEditLayers
; k
++)
1798 pEditLayers
[k
]->BrushSelecting(r
);
1799 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
1802 else if(s_Operation
== OP_BRUSH_PAINT
)
1804 if(!UI()->MouseButton(0))
1806 for(int k
= 0; k
< NumEditLayers
; k
++)
1807 pEditLayers
[k
]->FillSelection(m_Brush
.IsEmpty(), m_Brush
.m_lLayers
[0], r
);
1811 //editor.map.groups[selected_group]->mapscreen();
1812 for(int k
= 0; k
< NumEditLayers
; k
++)
1813 pEditLayers
[k
]->BrushSelecting(r
);
1814 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
1820 if(UI()->MouseButton(1))
1823 if(UI()->MouseButton(0) && s_Operation
== OP_NONE
)
1825 UI()->SetActiveItem(s_pEditorID
);
1827 if(m_Brush
.IsEmpty())
1828 s_Operation
= OP_BRUSH_GRAB
;
1831 s_Operation
= OP_BRUSH_DRAW
;
1832 for(int k
= 0; k
< NumEditLayers
; k
++)
1834 if(pEditLayers
[k
]->m_Type
== m_Brush
.m_lLayers
[0]->m_Type
)
1835 pEditLayers
[k
]->BrushPlace(m_Brush
.m_lLayers
[0], wx
, wy
);
1840 CLayerTiles
*pLayer
= (CLayerTiles
*)GetSelectedLayerType(0, LAYERTYPE_TILES
);
1841 if((Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
)) && pLayer
)
1842 s_Operation
= OP_BRUSH_PAINT
;
1845 if(!m_Brush
.IsEmpty())
1847 m_Brush
.m_OffsetX
= -(int)wx
;
1848 m_Brush
.m_OffsetY
= -(int)wy
;
1849 for(int i
= 0; i
< m_Brush
.m_lLayers
.size(); i
++)
1851 if(m_Brush
.m_lLayers
[i
]->m_Type
== LAYERTYPE_TILES
)
1853 m_Brush
.m_OffsetX
= -(int)(wx
/32.0f
)*32;
1854 m_Brush
.m_OffsetY
= -(int)(wy
/32.0f
)*32;
1859 CLayerGroup
*g
= GetSelectedGroup();
1862 m_Brush
.m_OffsetX
+= g
->m_OffsetX
;
1863 m_Brush
.m_OffsetY
+= g
->m_OffsetY
;
1864 m_Brush
.m_ParallaxX
= g
->m_ParallaxX
;
1865 m_Brush
.m_ParallaxY
= g
->m_ParallaxY
;
1868 m_Brush
.GetSize(&w
, &h
);
1870 IGraphics::CLineItem Array
[4] = {
1871 IGraphics::CLineItem(0, 0, w
, 0),
1872 IGraphics::CLineItem(w
, 0, w
, h
),
1873 IGraphics::CLineItem(w
, h
, 0, h
),
1874 IGraphics::CLineItem(0, h
, 0, 0)};
1875 Graphics()->TextureSet(-1);
1876 Graphics()->LinesBegin();
1877 Graphics()->LinesDraw(Array
, 4);
1878 Graphics()->LinesEnd();
1886 if(!m_ShowPicker
&& m_Brush
.IsEmpty())
1889 CLayerGroup
*g
= GetSelectedGroup();
1893 for(int k
= 0; k
< NumEditLayers
; k
++)
1895 if(pEditLayers
[k
]->m_Type
== LAYERTYPE_QUADS
)
1897 CLayerQuads
*pLayer
= (CLayerQuads
*)pEditLayers
[k
];
1899 if(!m_ShowEnvelopePreview
)
1900 m_ShowEnvelopePreview
= 2;
1902 Graphics()->TextureSet(-1);
1903 Graphics()->QuadsBegin();
1904 for(int i
= 0; i
< pLayer
->m_lQuads
.size(); i
++)
1906 for(int v
= 0; v
< 4; v
++)
1907 DoQuadPoint(&pLayer
->m_lQuads
[i
], i
, v
);
1909 DoQuad(&pLayer
->m_lQuads
[i
], i
);
1911 Graphics()->QuadsEnd();
1915 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
1919 if(UI()->ActiveItem() == s_pEditorID
)
1921 if(s_Operation
== OP_PAN_WORLD
)
1923 m_WorldOffsetX
-= m_MouseDeltaX
*m_WorldZoom
;
1924 m_WorldOffsetY
-= m_MouseDeltaY
*m_WorldZoom
;
1926 else if(s_Operation
== OP_PAN_EDITOR
)
1928 m_EditorOffsetX
-= m_MouseDeltaX
*m_WorldZoom
;
1929 m_EditorOffsetY
-= m_MouseDeltaY
*m_WorldZoom
;
1933 if(!UI()->MouseButton(0))
1935 s_Operation
= OP_NONE
;
1936 UI()->SetActiveItem(0);
1941 else if(UI()->ActiveItem() == s_pEditorID
)
1944 if(!UI()->MouseButton(0))
1946 s_Operation
= OP_NONE
;
1947 UI()->SetActiveItem(0);
1951 if(GetSelectedGroup() && GetSelectedGroup()->m_UseClipping
)
1953 CLayerGroup
*g
= m_Map
.m_pGameGroup
;
1956 Graphics()->TextureSet(-1);
1957 Graphics()->LinesBegin();
1960 r
.x
= GetSelectedGroup()->m_ClipX
;
1961 r
.y
= GetSelectedGroup()->m_ClipY
;
1962 r
.w
= GetSelectedGroup()->m_ClipW
;
1963 r
.h
= GetSelectedGroup()->m_ClipH
;
1965 IGraphics::CLineItem Array
[4] = {
1966 IGraphics::CLineItem(r
.x
, r
.y
, r
.x
+r
.w
, r
.y
),
1967 IGraphics::CLineItem(r
.x
+r
.w
, r
.y
, r
.x
+r
.w
, r
.y
+r
.h
),
1968 IGraphics::CLineItem(r
.x
+r
.w
, r
.y
+r
.h
, r
.x
, r
.y
+r
.h
),
1969 IGraphics::CLineItem(r
.x
, r
.y
+r
.h
, r
.x
, r
.y
)};
1970 Graphics()->SetColor(1,0,0,1);
1971 Graphics()->LinesDraw(Array
, 4);
1973 Graphics()->LinesEnd();
1976 // render screen sizes
1979 CLayerGroup
*g
= m_Map
.m_pGameGroup
;
1982 Graphics()->TextureSet(-1);
1983 Graphics()->LinesBegin();
1985 float aLastPoints
[4];
1986 float Start
= 1.0f
; //9.0f/16.0f;
1987 float End
= 16.0f
/9.0f
;
1988 const int NumSteps
= 20;
1989 for(int i
= 0; i
<= NumSteps
; i
++)
1992 float Aspect
= Start
+ (End
-Start
)*(i
/(float)NumSteps
);
1994 RenderTools()->MapscreenToWorld(
1995 m_WorldOffsetX
, m_WorldOffsetY
,
1996 1.0f
, 1.0f
, 0.0f
, 0.0f
, Aspect
, 1.0f
, aPoints
);
2000 IGraphics::CLineItem Array
[2] = {
2001 IGraphics::CLineItem(aPoints
[0], aPoints
[1], aPoints
[2], aPoints
[1]),
2002 IGraphics::CLineItem(aPoints
[0], aPoints
[3], aPoints
[2], aPoints
[3])};
2003 Graphics()->LinesDraw(Array
, 2);
2008 IGraphics::CLineItem Array
[4] = {
2009 IGraphics::CLineItem(aPoints
[0], aPoints
[1], aLastPoints
[0], aLastPoints
[1]),
2010 IGraphics::CLineItem(aPoints
[2], aPoints
[1], aLastPoints
[2], aLastPoints
[1]),
2011 IGraphics::CLineItem(aPoints
[0], aPoints
[3], aLastPoints
[0], aLastPoints
[3]),
2012 IGraphics::CLineItem(aPoints
[2], aPoints
[3], aLastPoints
[2], aLastPoints
[3])};
2013 Graphics()->LinesDraw(Array
, 4);
2018 IGraphics::CLineItem Array
[2] = {
2019 IGraphics::CLineItem(aPoints
[0], aPoints
[1], aPoints
[0], aPoints
[3]),
2020 IGraphics::CLineItem(aPoints
[2], aPoints
[1], aPoints
[2], aPoints
[3])};
2021 Graphics()->LinesDraw(Array
, 2);
2024 mem_copy(aLastPoints
, aPoints
, sizeof(aPoints
));
2029 Graphics()->SetColor(1,0,0,1);
2030 for(int i
= 0; i
< 2; i
++)
2033 float aAspects
[] = {4.0f
/3.0f
, 16.0f
/10.0f
, 5.0f
/4.0f
, 16.0f
/9.0f
};
2034 float Aspect
= aAspects
[i
];
2036 RenderTools()->MapscreenToWorld(
2037 m_WorldOffsetX
, m_WorldOffsetY
,
2038 1.0f
, 1.0f
, 0.0f
, 0.0f
, Aspect
, 1.0f
, aPoints
);
2043 r
.w
= aPoints
[2]-aPoints
[0];
2044 r
.h
= aPoints
[3]-aPoints
[1];
2046 IGraphics::CLineItem Array
[4] = {
2047 IGraphics::CLineItem(r
.x
, r
.y
, r
.x
+r
.w
, r
.y
),
2048 IGraphics::CLineItem(r
.x
+r
.w
, r
.y
, r
.x
+r
.w
, r
.y
+r
.h
),
2049 IGraphics::CLineItem(r
.x
+r
.w
, r
.y
+r
.h
, r
.x
, r
.y
+r
.h
),
2050 IGraphics::CLineItem(r
.x
, r
.y
+r
.h
, r
.x
, r
.y
)};
2051 Graphics()->LinesDraw(Array
, 4);
2052 Graphics()->SetColor(0,1,0,1);
2056 Graphics()->LinesEnd();
2059 if (!m_ShowPicker
&& m_ShowTileInfo
&& m_ShowEnvelopePreview
!= 0 && GetSelectedLayer(0) && GetSelectedLayer(0)->m_Type
== LAYERTYPE_QUADS
)
2061 GetSelectedGroup()->MapScreen();
2063 CLayerQuads
*pLayer
= (CLayerQuads
*)GetSelectedLayer(0);
2065 if(pLayer
->m_Image
>= 0 && pLayer
->m_Image
< m_Map
.m_lImages
.size())
2066 TexID
= m_Map
.m_lImages
[pLayer
->m_Image
]->m_TexID
;
2068 for(int i
= 0; i
< pLayer
->m_lQuads
.size(); i
++)
2070 if((m_ShowEnvelopePreview
== 1 && pLayer
->m_lQuads
[i
].m_PosEnv
== m_SelectedEnvelope
) || m_ShowEnvelopePreview
== 2)
2071 DoQuadEnvelopes(&pLayer
->m_lQuads
[i
], i
, TexID
);
2074 m_ShowEnvelopePreview
= 0;
2077 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
2078 //UI()->ClipDisable();
2082 int CEditor::DoProperties(CUIRect
*pToolBox
, CProperty
*pProps
, int *pIDs
, int *pNewVal
)
2086 for(int i
= 0; pProps
[i
].m_pName
; i
++)
2089 pToolBox
->HSplitTop(13.0f
, &Slot
, pToolBox
);
2090 CUIRect Label
, Shifter
;
2091 Slot
.VSplitMid(&Label
, &Shifter
);
2092 Shifter
.HMargin(1.0f
, &Shifter
);
2093 UI()->DoLabel(&Label
, pProps
[i
].m_pName
, 10.0f
, -1, -1);
2095 if(pProps
[i
].m_Type
== PROPTYPE_INT_STEP
)
2100 Shifter
.VSplitRight(10.0f
, &Shifter
, &Inc
);
2101 Shifter
.VSplitLeft(10.0f
, &Dec
, &Shifter
);
2102 str_format(aBuf
, sizeof(aBuf
),"%d", pProps
[i
].m_Value
);
2103 RenderTools()->DrawUIRect(&Shifter
, vec4(1,1,1,0.5f
), 0, 0.0f
);
2104 UI()->DoLabel(&Shifter
, aBuf
, 10.0f
, 0, -1);
2106 if(DoButton_ButtonDec(&pIDs
[i
], 0, 0, &Dec
, 0, "Decrease"))
2108 *pNewVal
= pProps
[i
].m_Value
-1;
2111 if(DoButton_ButtonInc(((char *)&pIDs
[i
])+1, 0, 0, &Inc
, 0, "Increase"))
2113 *pNewVal
= pProps
[i
].m_Value
+1;
2117 else if(pProps
[i
].m_Type
== PROPTYPE_BOOL
)
2120 Shifter
.VSplitMid(&No
, &Yes
);
2121 if(DoButton_ButtonDec(&pIDs
[i
], "No", !pProps
[i
].m_Value
, &No
, 0, ""))
2126 if(DoButton_ButtonInc(((char *)&pIDs
[i
])+1, "Yes", pProps
[i
].m_Value
, &Yes
, 0, ""))
2132 else if(pProps
[i
].m_Type
== PROPTYPE_INT_SCROLL
)
2134 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.");
2135 if(NewValue
!= pProps
[i
].m_Value
)
2137 *pNewVal
= NewValue
;
2141 else if(pProps
[i
].m_Type
== PROPTYPE_COLOR
)
2143 static const char *s_paTexts
[4] = {"R", "G", "B", "A"};
2144 static int s_aShift
[] = {24, 16, 8, 0};
2147 for(int c
= 0; c
< 4; c
++)
2149 int v
= (pProps
[i
].m_Value
>> s_aShift
[c
])&0xff;
2150 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
];
2154 pToolBox
->HSplitTop(13.0f
, &Slot
, pToolBox
);
2155 Slot
.VSplitMid(0, &Shifter
);
2156 Shifter
.HMargin(1.0f
, &Shifter
);
2160 if(NewColor
!= pProps
[i
].m_Value
)
2162 *pNewVal
= NewColor
;
2166 else if(pProps
[i
].m_Type
== PROPTYPE_IMAGE
)
2169 if(pProps
[i
].m_Value
< 0)
2170 str_copy(aBuf
, "None", sizeof(aBuf
));
2172 str_format(aBuf
, sizeof(aBuf
),"%s", m_Map
.m_lImages
[pProps
[i
].m_Value
]->m_aName
);
2174 if(DoButton_Editor(&pIDs
[i
], aBuf
, 0, &Shifter
, 0, 0))
2175 PopupSelectImageInvoke(pProps
[i
].m_Value
, UI()->MouseX(), UI()->MouseY());
2177 int r
= PopupSelectImageResult();
2184 else if(pProps
[i
].m_Type
== PROPTYPE_SHIFT
)
2186 CUIRect Left
, Right
, Up
, Down
;
2187 Shifter
.VSplitMid(&Left
, &Up
);
2188 Left
.VSplitRight(1.0f
, &Left
, 0);
2189 Up
.VSplitLeft(1.0f
, 0, &Up
);
2190 Left
.VSplitLeft(10.0f
, &Left
, &Shifter
);
2191 Shifter
.VSplitRight(10.0f
, &Shifter
, &Right
);
2192 RenderTools()->DrawUIRect(&Shifter
, vec4(1,1,1,0.5f
), 0, 0.0f
);
2193 UI()->DoLabel(&Shifter
, "X", 10.0f
, 0, -1);
2194 Up
.VSplitLeft(10.0f
, &Up
, &Shifter
);
2195 Shifter
.VSplitRight(10.0f
, &Shifter
, &Down
);
2196 RenderTools()->DrawUIRect(&Shifter
, vec4(1,1,1,0.5f
), 0, 0.0f
);
2197 UI()->DoLabel(&Shifter
, "Y", 10.0f
, 0, -1);
2198 if(DoButton_ButtonDec(&pIDs
[i
], "-", 0, &Left
, 0, "Left"))
2203 if(DoButton_ButtonInc(((char *)&pIDs
[i
])+3, "+", 0, &Right
, 0, "Right"))
2208 if(DoButton_ButtonDec(((char *)&pIDs
[i
])+1, "-", 0, &Up
, 0, "Up"))
2213 if(DoButton_ButtonInc(((char *)&pIDs
[i
])+2, "+", 0, &Down
, 0, "Down"))
2224 void CEditor::RenderLayers(CUIRect ToolBox
, CUIRect ToolBar
, CUIRect View
)
2226 CUIRect LayersBox
= ToolBox
;
2231 CUIRect Slot
, Button
;
2234 float LayersHeight
= 12.0f
; // Height of AddGroup button
2235 static int s_ScrollBar
= 0;
2236 static float s_ScrollValue
= 0;
2238 for(int g
= 0; g
< m_Map
.m_lGroups
.size(); g
++)
2240 // Each group is 19.0f
2241 // Each layer is 14.0f
2242 LayersHeight
+= 19.0f
;
2243 if(!m_Map
.m_lGroups
[g
]->m_Collapse
)
2244 LayersHeight
+= m_Map
.m_lGroups
[g
]->m_lLayers
.size() * 14.0f
;
2247 float ScrollDifference
= LayersHeight
- LayersBox
.h
;
2249 if(LayersHeight
> LayersBox
.h
) // Do we even need a scrollbar?
2252 LayersBox
.VSplitRight(15.0f
, &LayersBox
, &Scroll
);
2253 LayersBox
.VSplitRight(3.0f
, &LayersBox
, 0); // extra spacing
2254 Scroll
.HMargin(5.0f
, &Scroll
);
2255 s_ScrollValue
= UiDoScrollbarV(&s_ScrollBar
, &Scroll
, s_ScrollValue
);
2257 if(UI()->MouseInside(&Scroll
) || UI()->MouseInside(&LayersBox
))
2259 int ScrollNum
= (int)((LayersHeight
-LayersBox
.h
)/15.0f
)+1;
2262 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP
))
2263 s_ScrollValue
= clamp(s_ScrollValue
- 1.0f
/ScrollNum
, 0.0f
, 1.0f
);
2264 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN
))
2265 s_ScrollValue
= clamp(s_ScrollValue
+ 1.0f
/ScrollNum
, 0.0f
, 1.0f
);
2272 float LayerStartAt
= ScrollDifference
* s_ScrollValue
;
2273 if(LayerStartAt
< 0.0f
)
2274 LayerStartAt
= 0.0f
;
2276 float LayerStopAt
= LayersHeight
- ScrollDifference
* (1 - s_ScrollValue
);
2281 for(int g
= 0; g
< m_Map
.m_lGroups
.size(); g
++)
2283 if(LayerCur
> LayerStopAt
)
2285 else if(LayerCur
+ m_Map
.m_lGroups
[g
]->m_lLayers
.size() * 14.0f
+ 19.0f
< LayerStartAt
)
2287 LayerCur
+= m_Map
.m_lGroups
[g
]->m_lLayers
.size() * 14.0f
+ 19.0f
;
2291 CUIRect VisibleToggle
, SaveCheck
;
2292 if(LayerCur
>= LayerStartAt
)
2294 LayersBox
.HSplitTop(12.0f
, &Slot
, &LayersBox
);
2295 Slot
.VSplitLeft(12, &VisibleToggle
, &Slot
);
2296 if(DoButton_Ex(&m_Map
.m_lGroups
[g
]->m_Visible
, m_Map
.m_lGroups
[g
]->m_Visible
?"V":"H", m_Map
.m_lGroups
[g
]->m_Collapse
? 1 : 0, &VisibleToggle
, 0, "Toggle group visibility", CUI::CORNER_L
))
2297 m_Map
.m_lGroups
[g
]->m_Visible
= !m_Map
.m_lGroups
[g
]->m_Visible
;
2299 Slot
.VSplitRight(12.0f
, &Slot
, &SaveCheck
);
2300 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
))
2301 if(!m_Map
.m_lGroups
[g
]->m_GameGroup
)
2302 m_Map
.m_lGroups
[g
]->m_SaveToMap
= !m_Map
.m_lGroups
[g
]->m_SaveToMap
;
2304 str_format(aBuf
, sizeof(aBuf
),"#%d %s", g
, m_Map
.m_lGroups
[g
]->m_aName
);
2305 float FontSize
= 10.0f
;
2306 while(TextRender()->TextWidth(0, FontSize
, aBuf
, -1) > Slot
.w
)
2308 if(int Result
= DoButton_Ex(&m_Map
.m_lGroups
[g
], aBuf
, g
==m_SelectedGroup
, &Slot
,
2309 BUTTON_CONTEXT
, m_Map
.m_lGroups
[g
]->m_Collapse
? "Select group. Double click to expand." : "Select group. Double click to collapse.", 0, FontSize
))
2311 m_SelectedGroup
= g
;
2312 m_SelectedLayer
= 0;
2314 static int s_GroupPopupId
= 0;
2316 UiInvokePopupMenu(&s_GroupPopupId
, 0, UI()->MouseX(), UI()->MouseY(), 145, 220, PopupGroup
);
2318 if(m_Map
.m_lGroups
[g
]->m_lLayers
.size() && Input()->MouseDoubleClick())
2319 m_Map
.m_lGroups
[g
]->m_Collapse
^= 1;
2321 LayersBox
.HSplitTop(2.0f
, &Slot
, &LayersBox
);
2325 for(int i
= 0; i
< m_Map
.m_lGroups
[g
]->m_lLayers
.size(); i
++)
2327 if(LayerCur
> LayerStopAt
)
2329 else if(LayerCur
< LayerStartAt
)
2335 if(m_Map
.m_lGroups
[g
]->m_Collapse
)
2339 LayersBox
.HSplitTop(12.0f
, &Slot
, &LayersBox
);
2340 Slot
.VSplitLeft(12.0f
, 0, &Button
);
2341 Button
.VSplitLeft(15, &VisibleToggle
, &Button
);
2343 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
))
2344 m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_Visible
= !m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_Visible
;
2346 Button
.VSplitRight(12.0f
, &Button
, &SaveCheck
);
2347 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
))
2348 if(m_Map
.m_lGroups
[g
]->m_lLayers
[i
] != m_Map
.m_pGameLayer
)
2349 m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_SaveToMap
= !m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_SaveToMap
;
2351 if(m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_aName
[0])
2352 str_format(aBuf
, sizeof(aBuf
), "%s", m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_aName
);
2353 else if(m_Map
.m_lGroups
[g
]->m_lLayers
[i
]->m_Type
== LAYERTYPE_TILES
)
2354 str_copy(aBuf
, "Tiles", sizeof(aBuf
));
2356 str_copy(aBuf
, "Quads", sizeof(aBuf
));
2358 float FontSize
= 10.0f
;
2359 while(TextRender()->TextWidth(0, FontSize
, aBuf
, -1) > Button
.w
)
2361 if(int Result
= DoButton_Ex(m_Map
.m_lGroups
[g
]->m_lLayers
[i
], aBuf
, g
==m_SelectedGroup
&&i
==m_SelectedLayer
, &Button
,
2362 BUTTON_CONTEXT
, "Select layer.", 0, FontSize
))
2364 m_SelectedLayer
= i
;
2365 m_SelectedGroup
= g
;
2366 static int s_LayerPopupID
= 0;
2368 UiInvokePopupMenu(&s_LayerPopupID
, 0, UI()->MouseX(), UI()->MouseY(), 120, 245, PopupLayer
);
2372 LayersBox
.HSplitTop(2.0f
, &Slot
, &LayersBox
);
2374 if(LayerCur
> LayerStartAt
&& LayerCur
< LayerStopAt
)
2375 LayersBox
.HSplitTop(5.0f
, &Slot
, &LayersBox
);
2380 if(LayerCur
<= LayerStopAt
)
2382 LayersBox
.HSplitTop(12.0f
, &Slot
, &LayersBox
);
2384 static int s_NewGroupButton
= 0;
2385 if(DoButton_Editor(&s_NewGroupButton
, "Add group", 0, &Slot
, 0, "Adds a new group"))
2388 m_SelectedGroup
= m_Map
.m_lGroups
.size()-1;
2393 void CEditor::ReplaceImage(const char *pFileName
, int StorageType
, void *pUser
)
2395 CEditor
*pEditor
= (CEditor
*)pUser
;
2396 CEditorImage
ImgInfo(pEditor
);
2397 if(!pEditor
->Graphics()->LoadPNG(&ImgInfo
, pFileName
, StorageType
))
2400 CEditorImage
*pImg
= pEditor
->m_Map
.m_lImages
[pEditor
->m_SelectedImage
];
2401 int External
= pImg
->m_External
;
2402 pEditor
->Graphics()->UnloadTexture(pImg
->m_TexID
);
2404 pImg
->m_External
= External
;
2405 pEditor
->ExtractName(pFileName
, pImg
->m_aName
, sizeof(pImg
->m_aName
));
2406 pImg
->m_AutoMapper
.Load(pImg
->m_aName
);
2407 pImg
->m_TexID
= pEditor
->Graphics()->LoadTextureRaw(ImgInfo
.m_Width
, ImgInfo
.m_Height
, ImgInfo
.m_Format
, ImgInfo
.m_pData
, CImageInfo::FORMAT_AUTO
, 0);
2408 pEditor
->SortImages();
2409 for(int i
= 0; i
< pEditor
->m_Map
.m_lImages
.size(); ++i
)
2411 if(!str_comp(pEditor
->m_Map
.m_lImages
[i
]->m_aName
, pImg
->m_aName
))
2412 pEditor
->m_SelectedImage
= i
;
2414 pEditor
->m_Dialog
= DIALOG_NONE
;
2417 void CEditor::AddImage(const char *pFileName
, int StorageType
, void *pUser
)
2419 CEditor
*pEditor
= (CEditor
*)pUser
;
2420 CEditorImage
ImgInfo(pEditor
);
2421 if(!pEditor
->Graphics()->LoadPNG(&ImgInfo
, pFileName
, StorageType
))
2424 // check if we have that image already
2426 ExtractName(pFileName
, aBuf
, sizeof(aBuf
));
2427 for(int i
= 0; i
< pEditor
->m_Map
.m_lImages
.size(); ++i
)
2429 if(!str_comp(pEditor
->m_Map
.m_lImages
[i
]->m_aName
, aBuf
))
2433 CEditorImage
*pImg
= new CEditorImage(pEditor
);
2435 pImg
->m_TexID
= pEditor
->Graphics()->LoadTextureRaw(ImgInfo
.m_Width
, ImgInfo
.m_Height
, ImgInfo
.m_Format
, ImgInfo
.m_pData
, CImageInfo::FORMAT_AUTO
, 0);
2436 pImg
->m_External
= 1; // external by default
2437 str_copy(pImg
->m_aName
, aBuf
, sizeof(pImg
->m_aName
));
2438 pImg
->m_AutoMapper
.Load(pImg
->m_aName
);
2439 pEditor
->m_Map
.m_lImages
.add(pImg
);
2440 pEditor
->SortImages();
2441 if(pEditor
->m_SelectedImage
> -1 && pEditor
->m_SelectedImage
< pEditor
->m_Map
.m_lImages
.size())
2443 for(int i
= 0; i
<= pEditor
->m_SelectedImage
; ++i
)
2444 if(!str_comp(pEditor
->m_Map
.m_lImages
[i
]->m_aName
, aBuf
))
2446 pEditor
->m_SelectedImage
++;
2450 pEditor
->m_Dialog
= DIALOG_NONE
;
2454 static int gs_ModifyIndexDeletedIndex
;
2455 static void ModifyIndexDeleted(int *pIndex
)
2457 if(*pIndex
== gs_ModifyIndexDeletedIndex
)
2459 else if(*pIndex
> gs_ModifyIndexDeletedIndex
)
2460 *pIndex
= *pIndex
- 1;
2463 int CEditor::PopupImage(CEditor
*pEditor
, CUIRect View
)
2465 static int s_ReplaceButton
= 0;
2466 static int s_RemoveButton
= 0;
2469 View
.HSplitTop(2.0f
, &Slot
, &View
);
2470 View
.HSplitTop(12.0f
, &Slot
, &View
);
2471 CEditorImage
*pImg
= pEditor
->m_Map
.m_lImages
[pEditor
->m_SelectedImage
];
2473 static int s_ExternalButton
= 0;
2474 if(pImg
->m_External
)
2476 if(pEditor
->DoButton_MenuItem(&s_ExternalButton
, "Embed", 0, &Slot
, 0, "Embeds the image into the map file."))
2478 pImg
->m_External
= 0;
2484 if(pEditor
->DoButton_MenuItem(&s_ExternalButton
, "Make external", 0, &Slot
, 0, "Removes the image from the map file."))
2486 pImg
->m_External
= 1;
2491 View
.HSplitTop(10.0f
, &Slot
, &View
);
2492 View
.HSplitTop(12.0f
, &Slot
, &View
);
2493 if(pEditor
->DoButton_MenuItem(&s_ReplaceButton
, "Replace", 0, &Slot
, 0, "Replaces the image with a new one"))
2495 pEditor
->InvokeFileDialog(IStorage::TYPE_ALL
, FILETYPE_IMG
, "Replace Image", "Replace", "mapres", "", ReplaceImage
, pEditor
);
2499 View
.HSplitTop(10.0f
, &Slot
, &View
);
2500 View
.HSplitTop(12.0f
, &Slot
, &View
);
2501 if(pEditor
->DoButton_MenuItem(&s_RemoveButton
, "Remove", 0, &Slot
, 0, "Removes the image from the map"))
2504 pEditor
->m_Map
.m_lImages
.remove_index(pEditor
->m_SelectedImage
);
2505 gs_ModifyIndexDeletedIndex
= pEditor
->m_SelectedImage
;
2506 pEditor
->m_Map
.ModifyImageIndex(ModifyIndexDeleted
);
2513 static int CompareImageName(const void *pObject1
, const void *pObject2
)
2515 CEditorImage
*pImage1
= *(CEditorImage
**)pObject1
;
2516 CEditorImage
*pImage2
= *(CEditorImage
**)pObject2
;
2518 return str_comp(pImage1
->m_aName
, pImage2
->m_aName
);
2521 static int *gs_pSortedIndex
= 0;
2522 static void ModifySortedIndex(int *pIndex
)
2525 *pIndex
= gs_pSortedIndex
[*pIndex
];
2528 void CEditor::SortImages()
2531 for(int i
= 1; i
< m_Map
.m_lImages
.size(); i
++)
2532 if( str_comp(m_Map
.m_lImages
[i
]->m_aName
, m_Map
.m_lImages
[i
-1]->m_aName
) < 0 )
2540 array
<CEditorImage
*> lTemp
= array
<CEditorImage
*>(m_Map
.m_lImages
);
2541 gs_pSortedIndex
= new int[lTemp
.size()];
2543 qsort(m_Map
.m_lImages
.base_ptr(), m_Map
.m_lImages
.size(), sizeof(CEditorImage
*), CompareImageName
);
2545 for(int OldIndex
= 0; OldIndex
< lTemp
.size(); OldIndex
++)
2546 for(int NewIndex
= 0; NewIndex
< m_Map
.m_lImages
.size(); NewIndex
++)
2547 if(lTemp
[OldIndex
] == m_Map
.m_lImages
[NewIndex
])
2548 gs_pSortedIndex
[OldIndex
] = NewIndex
;
2550 m_Map
.ModifyImageIndex(ModifySortedIndex
);
2552 delete [] gs_pSortedIndex
;
2553 gs_pSortedIndex
= 0;
2558 void CEditor::RenderImages(CUIRect ToolBox
, CUIRect ToolBar
, CUIRect View
)
2560 static int s_ScrollBar
= 0;
2561 static float s_ScrollValue
= 0;
2562 float ImagesHeight
= 30.0f
+ 14.0f
* m_Map
.m_lImages
.size() + 27.0f
;
2563 float ScrollDifference
= ImagesHeight
- ToolBox
.h
;
2565 if(ImagesHeight
> ToolBox
.h
) // Do we even need a scrollbar?
2568 ToolBox
.VSplitRight(15.0f
, &ToolBox
, &Scroll
);
2569 ToolBox
.VSplitRight(3.0f
, &ToolBox
, 0); // extra spacing
2570 Scroll
.HMargin(5.0f
, &Scroll
);
2571 s_ScrollValue
= UiDoScrollbarV(&s_ScrollBar
, &Scroll
, s_ScrollValue
);
2573 if(UI()->MouseInside(&Scroll
) || UI()->MouseInside(&ToolBox
))
2575 int ScrollNum
= (int)((ImagesHeight
-ToolBox
.h
)/14.0f
)+1;
2578 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP
))
2579 s_ScrollValue
= clamp(s_ScrollValue
- 1.0f
/ScrollNum
, 0.0f
, 1.0f
);
2580 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN
))
2581 s_ScrollValue
= clamp(s_ScrollValue
+ 1.0f
/ScrollNum
, 0.0f
, 1.0f
);
2588 float ImageStartAt
= ScrollDifference
* s_ScrollValue
;
2589 if(ImageStartAt
< 0.0f
)
2590 ImageStartAt
= 0.0f
;
2592 float ImageStopAt
= ImagesHeight
- ScrollDifference
* (1 - s_ScrollValue
);
2593 float ImageCur
= 0.0f
;
2595 for(int e
= 0; e
< 2; e
++) // two passes, first embedded, then external
2599 if(ImageCur
> ImageStopAt
)
2601 else if(ImageCur
>= ImageStartAt
)
2604 ToolBox
.HSplitTop(15.0f
, &Slot
, &ToolBox
);
2606 UI()->DoLabel(&Slot
, "Embedded", 12.0f
, 0);
2608 UI()->DoLabel(&Slot
, "External", 12.0f
, 0);
2612 for(int i
= 0; i
< m_Map
.m_lImages
.size(); i
++)
2614 if((e
&& !m_Map
.m_lImages
[i
]->m_External
) ||
2615 (!e
&& m_Map
.m_lImages
[i
]->m_External
))
2620 if(ImageCur
> ImageStopAt
)
2622 else if(ImageCur
< ImageStartAt
)
2630 str_copy(aBuf
, m_Map
.m_lImages
[i
]->m_aName
, sizeof(aBuf
));
2631 ToolBox
.HSplitTop(12.0f
, &Slot
, &ToolBox
);
2633 if(int Result
= DoButton_Editor(&m_Map
.m_lImages
[i
], aBuf
, m_SelectedImage
== i
, &Slot
,
2634 BUTTON_CONTEXT
, "Select image"))
2636 m_SelectedImage
= i
;
2638 static int s_PopupImageID
= 0;
2640 UiInvokePopupMenu(&s_PopupImageID
, 0, UI()->MouseX(), UI()->MouseY(), 120, 80, PopupImage
);
2643 ToolBox
.HSplitTop(2.0f
, 0, &ToolBox
);
2646 if(m_SelectedImage
== i
)
2649 View
.Margin(10.0f
, &r
);
2654 float Max
= (float)(max(m_Map
.m_lImages
[i
]->m_Width
, m_Map
.m_lImages
[i
]->m_Height
));
2655 r
.w
*= m_Map
.m_lImages
[i
]->m_Width
/Max
;
2656 r
.h
*= m_Map
.m_lImages
[i
]->m_Height
/Max
;
2657 Graphics()->TextureSet(m_Map
.m_lImages
[i
]->m_TexID
);
2658 Graphics()->BlendNormal();
2659 Graphics()->QuadsBegin();
2660 IGraphics::CQuadItem
QuadItem(r
.x
, r
.y
, r
.w
, r
.h
);
2661 Graphics()->QuadsDrawTL(&QuadItem
, 1);
2662 Graphics()->QuadsEnd();
2668 ToolBox
.HSplitTop(5.0f
, &Slot
, &ToolBox
);
2670 IGraphics::CLineItem
LineItem(Slot
.x
, Slot
.y
+Slot
.h
/2, Slot
.x
+Slot
.w
, Slot
.y
+Slot
.h
/2);
2671 Graphics()->TextureSet(-1);
2672 Graphics()->LinesBegin();
2673 Graphics()->LinesDraw(&LineItem
, 1);
2674 Graphics()->LinesEnd();
2677 if(ImageCur
+ 27.0f
> ImageStopAt
)
2681 ToolBox
.HSplitTop(5.0f
, &Slot
, &ToolBox
);
2684 static int s_NewImageButton
= 0;
2685 ToolBox
.HSplitTop(12.0f
, &Slot
, &ToolBox
);
2686 if(DoButton_Editor(&s_NewImageButton
, "Add", 0, &Slot
, 0, "Load a new image to use in the map"))
2687 InvokeFileDialog(IStorage::TYPE_ALL
, FILETYPE_IMG
, "Add Image", "Add", "mapres", "", AddImage
, this);
2691 static int EditorListdirCallback(const char *pName
, int IsDir
, int StorageType
, void *pUser
)
2693 CEditor
*pEditor
= (CEditor
*)pUser
;
2694 int Length
= str_length(pName
);
2695 if((pName
[0] == '.' && (pName
[1] == 0 ||
2696 (pName
[1] == '.' && pName
[2] == 0 && (!str_comp(pEditor
->m_pFileDialogPath
, "maps") || !str_comp(pEditor
->m_pFileDialogPath
, "mapres"))))) ||
2697 (!IsDir
&& ((pEditor
->m_FileDialogFileType
== CEditor::FILETYPE_MAP
&& (Length
< 4 || str_comp(pName
+Length
-4, ".map"))) ||
2698 (pEditor
->m_FileDialogFileType
== CEditor::FILETYPE_IMG
&& (Length
< 4 || str_comp(pName
+Length
-4, ".png"))))))
2701 CEditor::CFilelistItem Item
;
2702 str_copy(Item
.m_aFilename
, pName
, sizeof(Item
.m_aFilename
));
2704 str_format(Item
.m_aName
, sizeof(Item
.m_aName
), "%s/", pName
);
2706 str_copy(Item
.m_aName
, pName
, min(static_cast<int>(sizeof(Item
.m_aName
)), Length
-3));
2707 Item
.m_IsDir
= IsDir
!= 0;
2708 Item
.m_IsLink
= false;
2709 Item
.m_StorageType
= StorageType
;
2710 pEditor
->m_FileList
.add(Item
);
2715 void CEditor::AddFileDialogEntry(int Index
, CUIRect
*pView
)
2718 if(m_FilesCur
-1 < m_FilesStartAt
|| m_FilesCur
>= m_FilesStopAt
)
2721 CUIRect Button
, FileIcon
;
2722 pView
->HSplitTop(15.0f
, &Button
, pView
);
2723 pView
->HSplitTop(2.0f
, 0, pView
);
2724 Button
.VSplitLeft(Button
.h
, &FileIcon
, &Button
);
2725 Button
.VSplitLeft(5.0f
, 0, &Button
);
2727 Graphics()->TextureSet(g_pData
->m_aImages
[IMAGE_FILEICONS
].m_Id
);
2728 Graphics()->QuadsBegin();
2729 RenderTools()->SelectSprite(m_FileList
[Index
].m_IsDir
?SPRITE_FILE_FOLDER
:SPRITE_FILE_MAP2
);
2730 IGraphics::CQuadItem
QuadItem(FileIcon
.x
, FileIcon
.y
, FileIcon
.w
, FileIcon
.h
);
2731 Graphics()->QuadsDrawTL(&QuadItem
, 1);
2732 Graphics()->QuadsEnd();
2734 if(DoButton_File(&m_FileList
[Index
], m_FileList
[Index
].m_aName
, m_FilesSelectedIndex
== Index
, &Button
, 0, 0))
2736 if(!m_FileList
[Index
].m_IsDir
)
2737 str_copy(m_aFileDialogFileName
, m_FileList
[Index
].m_aFilename
, sizeof(m_aFileDialogFileName
));
2739 m_aFileDialogFileName
[0] = 0;
2740 m_FilesSelectedIndex
= Index
;
2742 if(Input()->MouseDoubleClick())
2743 m_aFileDialogActivate
= true;
2747 void CEditor::RenderFileDialog()
2750 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
2751 CUIRect View
= *UI()->Screen();
2752 float Width
= View
.w
, Height
= View
.h
;
2754 RenderTools()->DrawUIRect(&View
, vec4(0,0,0,0.25f
), 0, 0);
2755 View
.VMargin(150.0f
, &View
);
2756 View
.HMargin(50.0f
, &View
);
2757 RenderTools()->DrawUIRect(&View
, vec4(0,0,0,0.75f
), CUI::CORNER_ALL
, 5.0f
);
2758 View
.Margin(10.0f
, &View
);
2760 CUIRect Title
, FileBox
, FileBoxLabel
, ButtonBar
, Scroll
;
2761 View
.HSplitTop(18.0f
, &Title
, &View
);
2762 View
.HSplitTop(5.0f
, 0, &View
); // some spacing
2763 View
.HSplitBottom(14.0f
, &View
, &ButtonBar
);
2764 View
.HSplitBottom(10.0f
, &View
, 0); // some spacing
2765 View
.HSplitBottom(14.0f
, &View
, &FileBox
);
2766 FileBox
.VSplitLeft(55.0f
, &FileBoxLabel
, &FileBox
);
2767 View
.HSplitBottom(10.0f
, &View
, 0); // some spacing
2768 View
.VSplitRight(15.0f
, &View
, &Scroll
);
2771 RenderTools()->DrawUIRect(&Title
, vec4(1, 1, 1, 0.25f
), CUI::CORNER_ALL
, 4.0f
);
2772 Title
.VMargin(10.0f
, &Title
);
2773 UI()->DoLabel(&Title
, m_pFileDialogTitle
, 12.0f
, -1, -1);
2776 if(m_FileDialogStorageType
== IStorage::TYPE_SAVE
)
2778 static float s_FileBoxID
= 0;
2779 UI()->DoLabel(&FileBoxLabel
, "Filename:", 10.0f
, -1, -1);
2780 if(DoEditBox(&s_FileBoxID
, &FileBox
, m_aFileDialogFileName
, sizeof(m_aFileDialogFileName
), 10.0f
, &s_FileBoxID
))
2782 // remove '/' and '\'
2783 for(int i
= 0; m_aFileDialogFileName
[i
]; ++i
)
2784 if(m_aFileDialogFileName
[i
] == '/' || m_aFileDialogFileName
[i
] == '\\')
2785 str_copy(&m_aFileDialogFileName
[i
], &m_aFileDialogFileName
[i
+1], (int)(sizeof(m_aFileDialogFileName
))-i
);
2786 m_FilesSelectedIndex
= -1;
2790 int Num
= (int)(View
.h
/17.0f
)+1;
2791 static int ScrollBar
= 0;
2792 Scroll
.HMargin(5.0f
, &Scroll
);
2793 m_FileDialogScrollValue
= UiDoScrollbarV(&ScrollBar
, &Scroll
, m_FileDialogScrollValue
);
2795 int ScrollNum
= m_FileList
.size()-Num
+1;
2798 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP
))
2799 m_FileDialogScrollValue
-= 3.0f
/ScrollNum
;
2800 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN
))
2801 m_FileDialogScrollValue
+= 3.0f
/ScrollNum
;
2806 if(m_FilesSelectedIndex
> -1)
2808 for(int i
= 0; i
< Input()->NumEvents(); i
++)
2811 if(Input()->GetEvent(i
).m_Flags
&IInput::FLAG_PRESS
)
2813 if(Input()->GetEvent(i
).m_Key
== KEY_DOWN
) NewIndex
= m_FilesSelectedIndex
+ 1;
2814 if(Input()->GetEvent(i
).m_Key
== KEY_UP
) NewIndex
= m_FilesSelectedIndex
- 1;
2816 if(NewIndex
> -1 && NewIndex
< m_FileList
.size())
2819 float IndexY
= View
.y
- m_FileDialogScrollValue
*ScrollNum
*17.0f
+ NewIndex
*17.0f
;
2820 int Scroll
= View
.y
> IndexY
? -1 : View
.y
+View
.h
< IndexY
+17.0f
? 1 : 0;
2824 m_FileDialogScrollValue
= ((float)(NewIndex
)+0.5f
)/ScrollNum
;
2826 m_FileDialogScrollValue
= ((float)(NewIndex
-Num
)+2.5f
)/ScrollNum
;
2829 if(!m_FileList
[NewIndex
].m_IsDir
)
2830 str_copy(m_aFileDialogFileName
, m_FileList
[NewIndex
].m_aFilename
, sizeof(m_aFileDialogFileName
));
2832 m_aFileDialogFileName
[0] = 0;
2833 m_FilesSelectedIndex
= NewIndex
;
2838 for(int i
= 0; i
< Input()->NumEvents(); i
++)
2840 if(Input()->GetEvent(i
).m_Flags
&IInput::FLAG_PRESS
)
2842 if(Input()->GetEvent(i
).m_Key
== KEY_RETURN
|| Input()->GetEvent(i
).m_Key
== KEY_KP_ENTER
)
2843 m_aFileDialogActivate
= true;
2847 if(m_FileDialogScrollValue
< 0) m_FileDialogScrollValue
= 0;
2848 if(m_FileDialogScrollValue
> 1) m_FileDialogScrollValue
= 1;
2850 m_FilesStartAt
= (int)(ScrollNum
*m_FileDialogScrollValue
);
2851 if(m_FilesStartAt
< 0)
2854 m_FilesStopAt
= m_FilesStartAt
+Num
;
2859 UI()->ClipEnable(&View
);
2861 for(int i
= 0; i
< m_FileList
.size(); i
++)
2862 AddFileDialogEntry(i
, &View
);
2864 // disable clipping again
2865 UI()->ClipDisable();
2868 static int s_OkButton
= 0;
2869 static int s_CancelButton
= 0;
2870 static int s_NewFolderButton
= 0;
2873 ButtonBar
.VSplitRight(50.0f
, &ButtonBar
, &Button
);
2874 bool IsDir
= m_FilesSelectedIndex
>= 0 && m_FileList
[m_FilesSelectedIndex
].m_IsDir
;
2875 if(DoButton_Editor(&s_OkButton
, IsDir
? "Open" : m_pFileDialogButtonText
, 0, &Button
, 0, 0) || m_aFileDialogActivate
)
2877 m_aFileDialogActivate
= false;
2880 if(str_comp(m_FileList
[m_FilesSelectedIndex
].m_aFilename
, "..") == 0) // parent folder
2882 if(fs_parent_dir(m_pFileDialogPath
))
2883 m_pFileDialogPath
= m_aFileDialogCurrentFolder
; // leave the link
2887 if(m_FileList
[m_FilesSelectedIndex
].m_IsLink
)
2889 m_pFileDialogPath
= m_aFileDialogCurrentLink
; // follow the link
2890 str_copy(m_aFileDialogCurrentLink
, m_FileList
[m_FilesSelectedIndex
].m_aFilename
, sizeof(m_aFileDialogCurrentLink
));
2894 char aTemp
[MAX_PATH_LENGTH
];
2895 str_copy(aTemp
, m_pFileDialogPath
, sizeof(aTemp
));
2896 str_format(m_pFileDialogPath
, MAX_PATH_LENGTH
, "%s/%s", aTemp
, m_FileList
[m_FilesSelectedIndex
].m_aFilename
);
2899 FilelistPopulate(!str_comp(m_pFileDialogPath
, "maps") || !str_comp(m_pFileDialogPath
, "mapres") ? m_FileDialogStorageType
:
2900 m_FileList
[m_FilesSelectedIndex
].m_StorageType
);
2901 if(m_FilesSelectedIndex
>= 0 && !m_FileList
[m_FilesSelectedIndex
].m_IsDir
)
2902 str_copy(m_aFileDialogFileName
, m_FileList
[m_FilesSelectedIndex
].m_aFilename
, sizeof(m_aFileDialogFileName
));
2904 m_aFileDialogFileName
[0] = 0;
2908 str_format(m_aFileSaveName
, sizeof(m_aFileSaveName
), "%s/%s", m_pFileDialogPath
, m_aFileDialogFileName
);
2909 if(!str_comp(m_pFileDialogButtonText
, "Save"))
2911 IOHANDLE File
= Storage()->OpenFile(m_aFileSaveName
, IOFLAG_READ
, IStorage::TYPE_SAVE
);
2915 m_PopupEventType
= POPEVENT_SAVE
;
2916 m_PopupEventActivated
= true;
2919 if(m_pfnFileDialogFunc
)
2920 m_pfnFileDialogFunc(m_aFileSaveName
, m_FilesSelectedIndex
>= 0 ? m_FileList
[m_FilesSelectedIndex
].m_StorageType
: m_FileDialogStorageType
, m_pFileDialogUser
);
2923 if(m_pfnFileDialogFunc
)
2924 m_pfnFileDialogFunc(m_aFileSaveName
, m_FilesSelectedIndex
>= 0 ? m_FileList
[m_FilesSelectedIndex
].m_StorageType
: m_FileDialogStorageType
, m_pFileDialogUser
);
2928 ButtonBar
.VSplitRight(40.0f
, &ButtonBar
, &Button
);
2929 ButtonBar
.VSplitRight(50.0f
, &ButtonBar
, &Button
);
2930 if(DoButton_Editor(&s_CancelButton
, "Cancel", 0, &Button
, 0, 0) || Input()->KeyPressed(KEY_ESCAPE
))
2931 m_Dialog
= DIALOG_NONE
;
2933 if(m_FileDialogStorageType
== IStorage::TYPE_SAVE
)
2935 ButtonBar
.VSplitLeft(40.0f
, 0, &ButtonBar
);
2936 ButtonBar
.VSplitLeft(70.0f
, &Button
, &ButtonBar
);
2937 if(DoButton_Editor(&s_NewFolderButton
, "New folder", 0, &Button
, 0, 0))
2939 m_FileDialogNewFolderName
[0] = 0;
2940 m_FileDialogErrString
[0] = 0;
2941 static int s_NewFolderPopupID
= 0;
2942 UiInvokePopupMenu(&s_NewFolderPopupID
, 0, Width
/2.0f
-200.0f
, Height
/2.0f
-100.0f
, 400.0f
, 200.0f
, PopupNewFolder
);
2943 UI()->SetActiveItem(0);
2948 void CEditor::FilelistPopulate(int StorageType
)
2951 if(m_FileDialogStorageType
!= IStorage::TYPE_SAVE
&& !str_comp(m_pFileDialogPath
, "maps"))
2954 str_copy(Item
.m_aFilename
, "downloadedmaps", sizeof(Item
.m_aFilename
));
2955 str_copy(Item
.m_aName
, "downloadedmaps/", sizeof(Item
.m_aName
));
2956 Item
.m_IsDir
= true;
2957 Item
.m_IsLink
= true;
2958 Item
.m_StorageType
= IStorage::TYPE_SAVE
;
2959 m_FileList
.add(Item
);
2961 Storage()->ListDirectory(StorageType
, m_pFileDialogPath
, EditorListdirCallback
, this);
2962 m_FilesSelectedIndex
= m_FileList
.size() ? 0 : -1;
2963 m_aFileDialogActivate
= false;
2966 void CEditor::InvokeFileDialog(int StorageType
, int FileType
, const char *pTitle
, const char *pButtonText
,
2967 const char *pBasePath
, const char *pDefaultName
,
2968 void (*pfnFunc
)(const char *pFileName
, int StorageType
, void *pUser
), void *pUser
)
2970 m_FileDialogStorageType
= StorageType
;
2971 m_pFileDialogTitle
= pTitle
;
2972 m_pFileDialogButtonText
= pButtonText
;
2973 m_pfnFileDialogFunc
= pfnFunc
;
2974 m_pFileDialogUser
= pUser
;
2975 m_aFileDialogFileName
[0] = 0;
2976 m_aFileDialogCurrentFolder
[0] = 0;
2977 m_aFileDialogCurrentLink
[0] = 0;
2978 m_pFileDialogPath
= m_aFileDialogCurrentFolder
;
2979 m_FileDialogFileType
= FileType
;
2980 m_FileDialogScrollValue
= 0.0f
;
2983 str_copy(m_aFileDialogFileName
, pDefaultName
, sizeof(m_aFileDialogFileName
));
2985 str_copy(m_aFileDialogCurrentFolder
, pBasePath
, sizeof(m_aFileDialogCurrentFolder
));
2987 FilelistPopulate(m_FileDialogStorageType
);
2989 m_Dialog
= DIALOG_FILE
;
2994 void CEditor::RenderModebar(CUIRect View
)
3000 View
.VSplitLeft(65.0f
, &Button
, &View
);
3001 Button
.HSplitTop(30.0f
, 0, &Button
);
3002 static int s_Button
= 0;
3003 const char *pButName
= m_Mode
== MODE_LAYERS
? "Layers" : "Images";
3004 if(DoButton_Tab(&s_Button
, pButName
, 0, &Button
, 0, "Switch between images and layers managment."))
3006 if(m_Mode
== MODE_LAYERS
)
3007 m_Mode
= MODE_IMAGES
;
3009 m_Mode
= MODE_LAYERS
;
3013 View
.VSplitLeft(5.0f
, 0, &View
);
3016 void CEditor::RenderStatusbar(CUIRect View
)
3019 View
.VSplitRight(60.0f
, &View
, &Button
);
3020 static int s_EnvelopeButton
= 0;
3021 if(DoButton_Editor(&s_EnvelopeButton
, "Envelopes", m_ShowEnvelopeEditor
, &Button
, 0, "Toggles the envelope editor."))
3022 m_ShowEnvelopeEditor
= (m_ShowEnvelopeEditor
+1)%4;
3026 if(ms_pUiGotContext
&& ms_pUiGotContext
== UI()->HotItem())
3029 str_format(aBuf
, sizeof(aBuf
), "%s Right click for context menu.", m_pTooltip
);
3030 UI()->DoLabel(&View
, aBuf
, 10.0f
, -1, -1);
3033 UI()->DoLabel(&View
, m_pTooltip
, 10.0f
, -1, -1);
3037 void CEditor::RenderEnvelopeEditor(CUIRect View
)
3039 if(m_SelectedEnvelope
< 0) m_SelectedEnvelope
= 0;
3040 if(m_SelectedEnvelope
>= m_Map
.m_lEnvelopes
.size()) m_SelectedEnvelope
= m_Map
.m_lEnvelopes
.size()-1;
3042 CEnvelope
*pEnvelope
= 0;
3043 if(m_SelectedEnvelope
>= 0 && m_SelectedEnvelope
< m_Map
.m_lEnvelopes
.size())
3044 pEnvelope
= m_Map
.m_lEnvelopes
[m_SelectedEnvelope
];
3046 CUIRect ToolBar
, CurveBar
, ColorBar
;
3047 View
.HSplitTop(15.0f
, &ToolBar
, &View
);
3048 View
.HSplitTop(15.0f
, &CurveBar
, &View
);
3049 ToolBar
.Margin(2.0f
, &ToolBar
);
3050 CurveBar
.Margin(2.0f
, &CurveBar
);
3055 CEnvelope
*pNewEnv
= 0;
3057 ToolBar
.VSplitRight(50.0f
, &ToolBar
, &Button
);
3058 static int s_New4dButton
= 0;
3059 if(DoButton_Editor(&s_New4dButton
, "Color+", 0, &Button
, 0, "Creates a new color envelope"))
3061 m_Map
.m_Modified
= true;
3062 pNewEnv
= m_Map
.NewEnvelope(4);
3065 ToolBar
.VSplitRight(5.0f
, &ToolBar
, &Button
);
3066 ToolBar
.VSplitRight(50.0f
, &ToolBar
, &Button
);
3067 static int s_New2dButton
= 0;
3068 if(DoButton_Editor(&s_New2dButton
, "Pos.+", 0, &Button
, 0, "Creates a new pos envelope"))
3070 m_Map
.m_Modified
= true;
3071 pNewEnv
= m_Map
.NewEnvelope(3);
3075 if(m_SelectedEnvelope
>= 0)
3077 ToolBar
.VSplitRight(10.0f
, &ToolBar
, &Button
);
3078 ToolBar
.VSplitRight(50.0f
, &ToolBar
, &Button
);
3079 static int s_DelButton
= 0;
3080 if(DoButton_Editor(&s_DelButton
, "Delete", 0, &Button
, 0, "Delete this envelope"))
3082 m_Map
.m_Modified
= true;
3083 m_Map
.DeleteEnvelope(m_SelectedEnvelope
);
3084 if(m_SelectedEnvelope
>= m_Map
.m_lEnvelopes
.size())
3085 m_SelectedEnvelope
= m_Map
.m_lEnvelopes
.size()-1;
3086 pEnvelope
= m_SelectedEnvelope
>= 0 ? m_Map
.m_lEnvelopes
[m_SelectedEnvelope
] : 0;
3090 if(pNewEnv
) // add the default points
3092 if(pNewEnv
->m_Channels
== 4)
3094 pNewEnv
->AddPoint(0, 1,1,1,1);
3095 pNewEnv
->AddPoint(1000, 1,1,1,1);
3099 pNewEnv
->AddPoint(0, 0);
3100 pNewEnv
->AddPoint(1000, 0);
3104 CUIRect Shifter
, Inc
, Dec
;
3105 ToolBar
.VSplitLeft(60.0f
, &Shifter
, &ToolBar
);
3106 Shifter
.VSplitRight(15.0f
, &Shifter
, &Inc
);
3107 Shifter
.VSplitLeft(15.0f
, &Dec
, &Shifter
);
3109 str_format(aBuf
, sizeof(aBuf
),"%d/%d", m_SelectedEnvelope
+1, m_Map
.m_lEnvelopes
.size());
3110 RenderTools()->DrawUIRect(&Shifter
, vec4(1,1,1,0.5f
), 0, 0.0f
);
3111 UI()->DoLabel(&Shifter
, aBuf
, 10.0f
, 0, -1);
3113 static int s_PrevButton
= 0;
3114 if(DoButton_ButtonDec(&s_PrevButton
, 0, 0, &Dec
, 0, "Previous Envelope"))
3115 m_SelectedEnvelope
--;
3117 static int s_NextButton
= 0;
3118 if(DoButton_ButtonInc(&s_NextButton
, 0, 0, &Inc
, 0, "Next Envelope"))
3119 m_SelectedEnvelope
++;
3123 ToolBar
.VSplitLeft(15.0f
, &Button
, &ToolBar
);
3124 ToolBar
.VSplitLeft(35.0f
, &Button
, &ToolBar
);
3125 UI()->DoLabel(&Button
, "Name:", 10.0f
, -1, -1);
3127 ToolBar
.VSplitLeft(80.0f
, &Button
, &ToolBar
);
3129 static float s_NameBox
= 0;
3130 if(DoEditBox(&s_NameBox
, &Button
, pEnvelope
->m_aName
, sizeof(pEnvelope
->m_aName
), 10.0f
, &s_NameBox
))
3131 m_Map
.m_Modified
= true;
3135 bool ShowColorBar
= false;
3136 if(pEnvelope
&& pEnvelope
->m_Channels
== 4)
3138 ShowColorBar
= true;
3139 View
.HSplitTop(20.0f
, &ColorBar
, &View
);
3140 ColorBar
.Margin(2.0f
, &ColorBar
);
3141 RenderBackground(ColorBar
, ms_CheckerTexture
, 16.0f
, 1.0f
);
3144 RenderBackground(View
, ms_CheckerTexture
, 32.0f
, 0.1f
);
3148 static array
<int> Selection
;
3149 static int sEnvelopeEditorID
= 0;
3150 static int s_ActiveChannels
= 0xf;
3156 ToolBar
.VSplitLeft(15.0f
, &Button
, &ToolBar
);
3158 static const char *s_paNames
[2][4] = {
3159 {"X", "Y", "R", ""},
3160 {"R", "G", "B", "A"},
3163 const char *paDescriptions
[2][4] = {
3164 {"X-axis of the envelope", "Y-axis of the envelope", "Rotation of the envelope", ""},
3165 {"Red value of the envelope", "Green value of the envelope", "Blue value of the envelope", "Alpha value of the envelope"},
3168 static int s_aChannelButtons
[4] = {0};
3170 //ui_draw_button_func draw_func;
3172 for(int i
= 0; i
< pEnvelope
->m_Channels
; i
++, Bit
<<=1)
3174 ToolBar
.VSplitLeft(15.0f
, &Button
, &ToolBar
);
3176 /*if(i == 0) draw_func = draw_editor_button_l;
3177 else if(i == envelope->channels-1) draw_func = draw_editor_button_r;
3178 else draw_func = draw_editor_button_m;*/
3180 if(DoButton_Editor(&s_aChannelButtons
[i
], s_paNames
[pEnvelope
->m_Channels
-3][i
], s_ActiveChannels
&Bit
, &Button
, 0, paDescriptions
[pEnvelope
->m_Channels
-3][i
]))
3181 s_ActiveChannels
^= Bit
;
3185 float EndTime
= pEnvelope
->EndTime();
3189 pEnvelope
->FindTopBottom(s_ActiveChannels
);
3190 float Top
= pEnvelope
->m_Top
;
3191 float Bottom
= pEnvelope
->m_Bottom
;
3198 float TimeScale
= EndTime
/View
.w
;
3199 float ValueScale
= (Top
-Bottom
)/View
.h
;
3201 if(UI()->MouseInside(&View
))
3202 UI()->SetHotItem(&sEnvelopeEditorID
);
3204 if(UI()->HotItem() == &sEnvelopeEditorID
)
3209 if(UI()->MouseButtonClicked(1))
3212 int Time
= (int)(((UI()->MouseX()-View
.x
)*TimeScale
)*1000.0f
);
3213 //float env_y = (UI()->MouseY()-view.y)/TimeScale;
3215 pEnvelope
->Eval(Time
, aChannels
);
3216 pEnvelope
->AddPoint(Time
,
3217 f2fx(aChannels
[0]), f2fx(aChannels
[1]),
3218 f2fx(aChannels
[2]), f2fx(aChannels
[3]));
3219 m_Map
.m_Modified
= true;
3222 m_ShowEnvelopePreview
= 1;
3223 m_pTooltip
= "Press right mouse button to create a new point";
3227 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
)};
3231 UI()->ClipEnable(&View
);
3232 Graphics()->TextureSet(-1);
3233 Graphics()->LinesBegin();
3234 for(int c
= 0; c
< pEnvelope
->m_Channels
; c
++)
3236 if(s_ActiveChannels
&(1<<c
))
3237 Graphics()->SetColor(aColors
[c
].r
,aColors
[c
].g
,aColors
[c
].b
,1);
3239 Graphics()->SetColor(aColors
[c
].r
*0.5f
,aColors
[c
].g
*0.5f
,aColors
[c
].b
*0.5f
,1);
3243 pEnvelope
->Eval(0.000001f
, aResults
);
3244 float PrevValue
= aResults
[c
];
3246 int Steps
= (int)((View
.w
/UI()->Screen()->w
) * Graphics()->ScreenWidth());
3247 for(int i
= 1; i
<= Steps
; i
++)
3249 float a
= i
/(float)Steps
;
3250 pEnvelope
->Eval(a
*EndTime
, aResults
);
3251 float v
= aResults
[c
];
3252 v
= (v
-Bottom
)/(Top
-Bottom
);
3254 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
);
3255 Graphics()->LinesDraw(&LineItem
, 1);
3260 Graphics()->LinesEnd();
3261 UI()->ClipDisable();
3264 // render curve options
3266 for(int i
= 0; i
< pEnvelope
->m_lPoints
.size()-1; i
++)
3268 float t0
= pEnvelope
->m_lPoints
[i
].m_Time
/1000.0f
/EndTime
;
3269 float t1
= pEnvelope
->m_lPoints
[i
+1].m_Time
/1000.0f
/EndTime
;
3271 //dbg_msg("", "%f", end_time);
3274 v
.x
= CurveBar
.x
+ (t0
+(t1
-t0
)*0.5f
) * CurveBar
.w
;
3279 void *pID
= &pEnvelope
->m_lPoints
[i
].m_Curvetype
;
3280 const char *paTypeName
[] = {
3281 "N", "L", "S", "F", "M"
3284 if(DoButton_Editor(pID
, paTypeName
[pEnvelope
->m_lPoints
[i
].m_Curvetype
], 0, &v
, 0, "Switch curve type"))
3285 pEnvelope
->m_lPoints
[i
].m_Curvetype
= (pEnvelope
->m_lPoints
[i
].m_Curvetype
+1)%NUM_CURVETYPES
;
3292 Graphics()->TextureSet(-1);
3293 Graphics()->QuadsBegin();
3294 for(int i
= 0; i
< pEnvelope
->m_lPoints
.size()-1; i
++)
3296 float r0
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[0]);
3297 float g0
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[1]);
3298 float b0
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[2]);
3299 float a0
= fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[3]);
3300 float r1
= fx2f(pEnvelope
->m_lPoints
[i
+1].m_aValues
[0]);
3301 float g1
= fx2f(pEnvelope
->m_lPoints
[i
+1].m_aValues
[1]);
3302 float b1
= fx2f(pEnvelope
->m_lPoints
[i
+1].m_aValues
[2]);
3303 float a1
= fx2f(pEnvelope
->m_lPoints
[i
+1].m_aValues
[3]);
3305 IGraphics::CColorVertex Array
[4] = {IGraphics::CColorVertex(0, r0
, g0
, b0
, a0
),
3306 IGraphics::CColorVertex(1, r1
, g1
, b1
, a1
),
3307 IGraphics::CColorVertex(2, r1
, g1
, b1
, a1
),
3308 IGraphics::CColorVertex(3, r0
, g0
, b0
, a0
)};
3309 Graphics()->SetColorVertex(Array
, 4);
3311 float x0
= pEnvelope
->m_lPoints
[i
].m_Time
/1000.0f
/EndTime
;
3312 // float y0 = (fx2f(envelope->points[i].values[c])-bottom)/(top-bottom);
3313 float x1
= pEnvelope
->m_lPoints
[i
+1].m_Time
/1000.0f
/EndTime
;
3314 //float y1 = (fx2f(envelope->points[i+1].values[c])-bottom)/(top-bottom);
3316 v
.x
= ColorBar
.x
+ x0
*ColorBar
.w
;
3318 v
.w
= (x1
-x0
)*ColorBar
.w
;
3321 IGraphics::CQuadItem
QuadItem(v
.x
, v
.y
, v
.w
, v
.h
);
3322 Graphics()->QuadsDrawTL(&QuadItem
, 1);
3324 Graphics()->QuadsEnd();
3329 int CurrentValue
= 0, CurrentTime
= 0;
3331 Graphics()->TextureSet(-1);
3332 Graphics()->QuadsBegin();
3333 for(int c
= 0; c
< pEnvelope
->m_Channels
; c
++)
3335 if(!(s_ActiveChannels
&(1<<c
)))
3338 for(int i
= 0; i
< pEnvelope
->m_lPoints
.size(); i
++)
3340 float x0
= pEnvelope
->m_lPoints
[i
].m_Time
/1000.0f
/EndTime
;
3341 float y0
= (fx2f(pEnvelope
->m_lPoints
[i
].m_aValues
[c
])-Bottom
)/(Top
-Bottom
);
3343 Final
.x
= View
.x
+ x0
*View
.w
;
3344 Final
.y
= View
.y
+View
.h
- y0
*View
.h
;
3350 void *pID
= &pEnvelope
->m_lPoints
[i
].m_aValues
[c
];
3352 if(UI()->MouseInside(&Final
))
3353 UI()->SetHotItem(pID
);
3355 float ColorMod
= 1.0f
;
3357 if(UI()->ActiveItem() == pID
)
3359 if(!UI()->MouseButton(0))
3361 m_SelectedQuadEnvelope
= -1;
3362 m_SelectedEnvelopePoint
= -1;
3364 UI()->SetActiveItem(0);
3368 if(Input()->KeyPressed(KEY_LSHIFT
) || Input()->KeyPressed(KEY_RSHIFT
))
3372 if((Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
)))
3373 pEnvelope
->m_lPoints
[i
].m_Time
+= (int)((m_MouseDeltaX
));
3375 pEnvelope
->m_lPoints
[i
].m_Time
+= (int)((m_MouseDeltaX
*TimeScale
)*1000.0f
);
3376 if(pEnvelope
->m_lPoints
[i
].m_Time
< pEnvelope
->m_lPoints
[i
-1].m_Time
)
3377 pEnvelope
->m_lPoints
[i
].m_Time
= pEnvelope
->m_lPoints
[i
-1].m_Time
+ 1;
3378 if(i
+1 != pEnvelope
->m_lPoints
.size() && pEnvelope
->m_lPoints
[i
].m_Time
> pEnvelope
->m_lPoints
[i
+1].m_Time
)
3379 pEnvelope
->m_lPoints
[i
].m_Time
= pEnvelope
->m_lPoints
[i
+1].m_Time
- 1;
3384 if((Input()->KeyPressed(KEY_LCTRL
) || Input()->KeyPressed(KEY_RCTRL
)))
3385 pEnvelope
->m_lPoints
[i
].m_aValues
[c
] -= f2fx(m_MouseDeltaY
*0.001f
);
3387 pEnvelope
->m_lPoints
[i
].m_aValues
[c
] -= f2fx(m_MouseDeltaY
*ValueScale
);
3390 m_SelectedQuadEnvelope
= m_SelectedEnvelope
;
3391 m_ShowEnvelopePreview
= 1;
3392 m_SelectedEnvelopePoint
= i
;
3393 m_Map
.m_Modified
= true;
3397 Graphics()->SetColor(1,1,1,1);
3399 else if(UI()->HotItem() == pID
)
3401 if(UI()->MouseButton(0))
3405 UI()->SetActiveItem(pID
);
3409 if(UI()->MouseButtonClicked(1))
3411 pEnvelope
->m_lPoints
.remove_index(i
);
3412 m_Map
.m_Modified
= true;
3415 m_ShowEnvelopePreview
= 1;
3417 Graphics()->SetColor(1,0.75f
,0.75f
,1);
3418 m_pTooltip
= "Left mouse to drag. Hold ctrl to be more precise. Hold shift to alter time point aswell. Right click to delete.";
3421 if(UI()->ActiveItem() == pID
|| UI()->HotItem() == pID
)
3423 CurrentTime
= pEnvelope
->m_lPoints
[i
].m_Time
;
3424 CurrentValue
= pEnvelope
->m_lPoints
[i
].m_aValues
[c
];
3427 if (m_SelectedQuadEnvelope
== m_SelectedEnvelope
&& m_SelectedEnvelopePoint
== i
)
3428 Graphics()->SetColor(1.0f
, 1.0f
, 1.0f
, 1.0f
);
3430 Graphics()->SetColor(aColors
[c
].r
*ColorMod
, aColors
[c
].g
*ColorMod
, aColors
[c
].b
*ColorMod
, 1.0f
);
3431 IGraphics::CQuadItem
QuadItem(Final
.x
, Final
.y
, Final
.w
, Final
.h
);
3432 Graphics()->QuadsDrawTL(&QuadItem
, 1);
3435 Graphics()->QuadsEnd();
3438 str_format(aBuf
, sizeof(aBuf
),"%.3f %.3f", CurrentTime
/1000.0f
, fx2f(CurrentValue
));
3439 UI()->DoLabel(&ToolBar
, aBuf
, 10.0f
, 0, -1);
3444 int CEditor::PopupMenuFile(CEditor
*pEditor
, CUIRect View
)
3446 static int s_NewMapButton
= 0;
3447 static int s_SaveButton
= 0;
3448 static int s_SaveAsButton
= 0;
3449 static int s_OpenButton
= 0;
3450 static int s_AppendButton
= 0;
3451 static int s_ExitButton
= 0;
3454 View
.HSplitTop(2.0f
, &Slot
, &View
);
3455 View
.HSplitTop(12.0f
, &Slot
, &View
);
3456 if(pEditor
->DoButton_MenuItem(&s_NewMapButton
, "New", 0, &Slot
, 0, "Creates a new map"))
3458 if(pEditor
->HasUnsavedData())
3460 pEditor
->m_PopupEventType
= POPEVENT_NEW
;
3461 pEditor
->m_PopupEventActivated
= true;
3466 pEditor
->m_aFileName
[0] = 0;
3471 View
.HSplitTop(10.0f
, &Slot
, &View
);
3472 View
.HSplitTop(12.0f
, &Slot
, &View
);
3473 if(pEditor
->DoButton_MenuItem(&s_OpenButton
, "Load", 0, &Slot
, 0, "Opens a map for editing"))
3475 if(pEditor
->HasUnsavedData())
3477 pEditor
->m_PopupEventType
= POPEVENT_LOAD
;
3478 pEditor
->m_PopupEventActivated
= true;
3481 pEditor
->InvokeFileDialog(IStorage::TYPE_ALL
, FILETYPE_MAP
, "Load map", "Load", "maps", "", pEditor
->CallbackOpenMap
, pEditor
);
3485 View
.HSplitTop(10.0f
, &Slot
, &View
);
3486 View
.HSplitTop(12.0f
, &Slot
, &View
);
3487 if(pEditor
->DoButton_MenuItem(&s_AppendButton
, "Append", 0, &Slot
, 0, "Opens a map and adds everything from that map to the current one"))
3489 pEditor
->InvokeFileDialog(IStorage::TYPE_ALL
, FILETYPE_MAP
, "Append map", "Append", "maps", "", pEditor
->CallbackAppendMap
, pEditor
);
3493 View
.HSplitTop(10.0f
, &Slot
, &View
);
3494 View
.HSplitTop(12.0f
, &Slot
, &View
);
3495 if(pEditor
->DoButton_MenuItem(&s_SaveButton
, "Save", 0, &Slot
, 0, "Saves the current map"))
3497 if(pEditor
->m_aFileName
[0] && pEditor
->m_ValidSaveFilename
)
3499 str_copy(pEditor
->m_aFileSaveName
, pEditor
->m_aFileName
, sizeof(pEditor
->m_aFileSaveName
));
3500 pEditor
->m_PopupEventType
= POPEVENT_SAVE
;
3501 pEditor
->m_PopupEventActivated
= true;
3504 pEditor
->InvokeFileDialog(IStorage::TYPE_SAVE
, FILETYPE_MAP
, "Save map", "Save", "maps", "", pEditor
->CallbackSaveMap
, pEditor
);
3508 View
.HSplitTop(2.0f
, &Slot
, &View
);
3509 View
.HSplitTop(12.0f
, &Slot
, &View
);
3510 if(pEditor
->DoButton_MenuItem(&s_SaveAsButton
, "Save As", 0, &Slot
, 0, "Saves the current map under a new name"))
3512 pEditor
->InvokeFileDialog(IStorage::TYPE_SAVE
, FILETYPE_MAP
, "Save map", "Save", "maps", "", pEditor
->CallbackSaveMap
, pEditor
);
3516 View
.HSplitTop(10.0f
, &Slot
, &View
);
3517 View
.HSplitTop(12.0f
, &Slot
, &View
);
3518 if(pEditor
->DoButton_MenuItem(&s_ExitButton
, "Exit", 0, &Slot
, 0, "Exits from the editor"))
3520 if(pEditor
->HasUnsavedData())
3522 pEditor
->m_PopupEventType
= POPEVENT_EXIT
;
3523 pEditor
->m_PopupEventActivated
= true;
3526 g_Config
.m_ClEditor
= 0;
3533 void CEditor::RenderMenubar(CUIRect MenuBar
)
3535 static CUIRect s_File
/*, view, help*/;
3537 MenuBar
.VSplitLeft(60.0f
, &s_File
, &MenuBar
);
3538 if(DoButton_Menu(&s_File
, "File", 0, &s_File
, 0, 0))
3539 UiInvokePopupMenu(&s_File
, 1, s_File
.x
, s_File
.y
+s_File
.h
-1.0f
, 120, 150, PopupMenuFile
, this);
3542 menubar.VSplitLeft(5.0f, 0, &menubar);
3543 menubar.VSplitLeft(60.0f, &view, &menubar);
3544 if(do_editor_button(&view, "View", 0, &view, draw_editor_button_menu, 0, 0))
3547 menubar.VSplitLeft(5.0f, 0, &menubar);
3548 menubar.VSplitLeft(60.0f, &help, &menubar);
3549 if(do_editor_button(&help, "Help", 0, &help, draw_editor_button_menu, 0, 0))
3553 MenuBar
.VSplitLeft(40.0f
, 0, &MenuBar
);
3555 str_format(aBuf
, sizeof(aBuf
), "File: %s", m_aFileName
);
3556 UI()->DoLabel(&MenuBar
, aBuf
, 10.0f
, -1, -1);
3559 void CEditor::Render()
3562 Graphics()->Clear(1.0f
, 0.0f
, 1.0f
);
3563 CUIRect View
= *UI()->Screen();
3564 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
3566 float Width
= View
.w
;
3567 float Height
= View
.h
;
3573 RenderBackground(View
, ms_CheckerTexture
, 32.0f
, 1.0f
);
3575 CUIRect MenuBar
, CModeBar
, ToolBar
, StatusBar
, EnvelopeEditor
, ToolBox
;
3576 m_ShowPicker
= Input()->KeyPressed(KEY_SPACE
) != 0 && m_Dialog
== DIALOG_NONE
;
3581 View
.HSplitTop(16.0f
, &MenuBar
, &View
);
3582 View
.HSplitTop(53.0f
, &ToolBar
, &View
);
3583 View
.VSplitLeft(100.0f
, &ToolBox
, &View
);
3584 View
.HSplitBottom(16.0f
, &View
, &StatusBar
);
3586 if(m_ShowEnvelopeEditor
&& !m_ShowPicker
)
3588 float size
= 125.0f
;
3589 if(m_ShowEnvelopeEditor
== 2)
3591 else if(m_ShowEnvelopeEditor
== 3)
3593 View
.HSplitBottom(size
, &View
, &EnvelopeEditor
);
3597 // a little hack for now
3598 if(m_Mode
== MODE_LAYERS
)
3599 DoMapEditor(View
, ToolBar
);
3602 if(m_Dialog
== DIALOG_NONE
&& UI()->MouseInside(&View
))
3604 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP
))
3607 if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN
))
3610 m_ZoomLevel
= clamp(m_ZoomLevel
, 50, 2000);
3615 float Brightness
= 0.25f
;
3616 RenderBackground(MenuBar
, ms_BackgroundTexture
, 128.0f
, Brightness
*0);
3617 MenuBar
.Margin(2.0f
, &MenuBar
);
3619 RenderBackground(ToolBox
, ms_BackgroundTexture
, 128.0f
, Brightness
);
3620 ToolBox
.Margin(2.0f
, &ToolBox
);
3622 RenderBackground(ToolBar
, ms_BackgroundTexture
, 128.0f
, Brightness
);
3623 ToolBar
.Margin(2.0f
, &ToolBar
);
3624 ToolBar
.VSplitLeft(100.0f
, &CModeBar
, &ToolBar
);
3626 RenderBackground(StatusBar
, ms_BackgroundTexture
, 128.0f
, Brightness
);
3627 StatusBar
.Margin(2.0f
, &StatusBar
);
3630 if(m_Mode
== MODE_LAYERS
)
3633 if(m_ShowEnvelopeEditor
)
3635 RenderBackground(EnvelopeEditor
, ms_BackgroundTexture
, 128.0f
, Brightness
);
3636 EnvelopeEditor
.Margin(2.0f
, &EnvelopeEditor
);
3641 if(m_Mode
== MODE_LAYERS
)
3642 RenderLayers(ToolBox
, ToolBar
, View
);
3643 else if(m_Mode
== MODE_IMAGES
)
3644 RenderImages(ToolBox
, ToolBar
, View
);
3646 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
3650 RenderMenubar(MenuBar
);
3652 RenderModebar(CModeBar
);
3653 if(m_ShowEnvelopeEditor
)
3654 RenderEnvelopeEditor(EnvelopeEditor
);
3657 if(m_Dialog
== DIALOG_FILE
)
3659 static int s_NullUiTarget
= 0;
3660 UI()->SetHotItem(&s_NullUiTarget
);
3664 if(m_PopupEventActivated
)
3666 static int s_PopupID
= 0;
3667 UiInvokePopupMenu(&s_PopupID
, 0, Width
/2.0f
-200.0f
, Height
/2.0f
-100.0f
, 400.0f
, 200.0f
, PopupEvent
);
3668 m_PopupEventActivated
= false;
3669 m_PopupEventWasActivated
= true;
3676 RenderStatusbar(StatusBar
);
3679 if(g_Config
.m_EdShowkeys
)
3681 Graphics()->MapScreen(UI()->Screen()->x
, UI()->Screen()->y
, UI()->Screen()->w
, UI()->Screen()->h
);
3683 TextRender()->SetCursor(&Cursor
, View
.x
+10, View
.y
+View
.h
-24-10, 24.0f
, TEXTFLAG_RENDER
);
3686 for(int i
= 0; i
< KEY_LAST
; i
++)
3688 if(Input()->KeyPressed(i
))
3691 TextRender()->TextEx(&Cursor
, " + ", -1);
3692 TextRender()->TextEx(&Cursor
, Input()->KeyName(i
), -1);
3698 if(m_ShowMousePointer
)
3700 // render butt ugly mouse cursor
3701 float mx
= UI()->MouseX();
3702 float my
= UI()->MouseY();
3703 Graphics()->TextureSet(ms_CursorTexture
);
3704 Graphics()->QuadsBegin();
3705 if(ms_pUiGotContext
== UI()->HotItem())
3706 Graphics()->SetColor(1,0,0,1);
3707 IGraphics::CQuadItem
QuadItem(mx
,my
, 16.0f
, 16.0f
);
3708 Graphics()->QuadsDrawTL(&QuadItem
, 1);
3709 Graphics()->QuadsEnd();
3713 void CEditor::Reset(bool CreateDefault
)
3717 // create default layers
3719 m_Map
.CreateDefault(ms_EntitiesTexture
);
3725 m_SelectedLayer
= 0;
3726 m_SelectedGroup
= 0;
3727 m_SelectedQuad
= -1;
3728 m_SelectedPoints
= 0;
3729 m_SelectedEnvelope
= 0;
3730 m_SelectedImage
= 0;
3734 m_EditorOffsetX
= 0.0f
;
3735 m_EditorOffsetY
= 0.0f
;
3745 m_Map
.m_Modified
= false;
3747 m_ShowEnvelopePreview
= 0;
3750 int CEditor::GetLineDistance()
3752 int LineDistance
= 512;
3754 if(m_ZoomLevel
<= 100)
3756 else if(m_ZoomLevel
<= 250)
3758 else if(m_ZoomLevel
<= 450)
3760 else if(m_ZoomLevel
<= 850)
3762 else if(m_ZoomLevel
<= 1550)
3765 return LineDistance
;
3768 void CEditorMap::DeleteEnvelope(int Index
)
3770 if(Index
< 0 || Index
>= m_lEnvelopes
.size())
3775 // fix links between envelopes and quads
3776 for(int i
= 0; i
< m_lGroups
.size(); ++i
)
3777 for(int j
= 0; j
< m_lGroups
[i
]->m_lLayers
.size(); ++j
)
3778 if(m_lGroups
[i
]->m_lLayers
[j
]->m_Type
== LAYERTYPE_QUADS
)
3780 CLayerQuads
*Layer
= static_cast<CLayerQuads
*>(m_lGroups
[i
]->m_lLayers
[j
]);
3781 for(int k
= 0; k
< Layer
->m_lQuads
.size(); ++k
)
3783 if(Layer
->m_lQuads
[k
].m_PosEnv
== Index
)
3784 Layer
->m_lQuads
[k
].m_PosEnv
= -1;
3785 else if(Layer
->m_lQuads
[k
].m_PosEnv
> Index
)
3786 Layer
->m_lQuads
[k
].m_PosEnv
--;
3787 if(Layer
->m_lQuads
[k
].m_ColorEnv
== Index
)
3788 Layer
->m_lQuads
[k
].m_ColorEnv
= -1;
3789 else if(Layer
->m_lQuads
[k
].m_ColorEnv
> Index
)
3790 Layer
->m_lQuads
[k
].m_ColorEnv
--;
3794 m_lEnvelopes
.remove_index(Index
);
3797 void CEditorMap::MakeGameLayer(CLayer
*pLayer
)
3799 m_pGameLayer
= (CLayerGame
*)pLayer
;
3800 m_pGameLayer
->m_pEditor
= m_pEditor
;
3801 m_pGameLayer
->m_TexID
= m_pEditor
->ms_EntitiesTexture
;
3804 void CEditorMap::MakeGameGroup(CLayerGroup
*pGroup
)
3806 m_pGameGroup
= pGroup
;
3807 m_pGameGroup
->m_GameGroup
= true;
3808 str_copy(m_pGameGroup
->m_aName
, "Game", sizeof(m_pGameGroup
->m_aName
));
3813 void CEditorMap::Clean()
3815 m_lGroups
.delete_all();
3816 m_lEnvelopes
.delete_all();
3817 m_lImages
.delete_all();
3825 void CEditorMap::CreateDefault(int EntitiesTexture
)
3828 CLayerGroup
*pGroup
= NewGroup();
3829 pGroup
->m_ParallaxX
= 0;
3830 pGroup
->m_ParallaxY
= 0;
3831 CLayerQuads
*pLayer
= new CLayerQuads
;
3832 pLayer
->m_pEditor
= m_pEditor
;
3833 CQuad
*pQuad
= pLayer
->NewQuad();
3834 const int Width
= 800000;
3835 const int Height
= 600000;
3836 pQuad
->m_aPoints
[0].x
= pQuad
->m_aPoints
[2].x
= -Width
;
3837 pQuad
->m_aPoints
[1].x
= pQuad
->m_aPoints
[3].x
= Width
;
3838 pQuad
->m_aPoints
[0].y
= pQuad
->m_aPoints
[1].y
= -Height
;
3839 pQuad
->m_aPoints
[2].y
= pQuad
->m_aPoints
[3].y
= Height
;
3840 pQuad
->m_aColors
[0].r
= pQuad
->m_aColors
[1].r
= 94;
3841 pQuad
->m_aColors
[0].g
= pQuad
->m_aColors
[1].g
= 132;
3842 pQuad
->m_aColors
[0].b
= pQuad
->m_aColors
[1].b
= 174;
3843 pQuad
->m_aColors
[2].r
= pQuad
->m_aColors
[3].r
= 204;
3844 pQuad
->m_aColors
[2].g
= pQuad
->m_aColors
[3].g
= 232;
3845 pQuad
->m_aColors
[2].b
= pQuad
->m_aColors
[3].b
= 255;
3846 pGroup
->AddLayer(pLayer
);
3849 MakeGameGroup(NewGroup());
3850 MakeGameLayer(new CLayerGame(50, 50));
3851 m_pGameGroup
->AddLayer(m_pGameLayer
);
3854 void CEditor::Init()
3856 m_pInput
= Kernel()->RequestInterface
<IInput
>();
3857 m_pClient
= Kernel()->RequestInterface
<IClient
>();
3858 m_pConsole
= Kernel()->RequestInterface
<IConsole
>();
3859 m_pGraphics
= Kernel()->RequestInterface
<IGraphics
>();
3860 m_pTextRender
= Kernel()->RequestInterface
<ITextRender
>();
3861 m_pStorage
= Kernel()->RequestInterface
<IStorage
>();
3862 m_RenderTools
.m_pGraphics
= m_pGraphics
;
3863 m_RenderTools
.m_pUI
= &m_UI
;
3864 m_UI
.SetGraphics(m_pGraphics
, m_pTextRender
);
3865 m_Map
.m_pEditor
= this;
3867 ms_CheckerTexture
= Graphics()->LoadTexture("editor/checker.png", IStorage::TYPE_ALL
, CImageInfo::FORMAT_AUTO
, 0);
3868 ms_BackgroundTexture
= Graphics()->LoadTexture("editor/background.png", IStorage::TYPE_ALL
, CImageInfo::FORMAT_AUTO
, 0);
3869 ms_CursorTexture
= Graphics()->LoadTexture("editor/cursor.png", IStorage::TYPE_ALL
, CImageInfo::FORMAT_AUTO
, 0);
3870 ms_EntitiesTexture
= Graphics()->LoadTexture("editor/entities.png", IStorage::TYPE_ALL
, CImageInfo::FORMAT_AUTO
, 0);
3872 m_TilesetPicker
.m_pEditor
= this;
3873 m_TilesetPicker
.MakePalette();
3874 m_TilesetPicker
.m_Readonly
= true;
3876 m_Brush
.m_pMap
= &m_Map
;
3879 m_Map
.m_Modified
= false;
3882 void CEditor::DoMapBorder()
3884 CLayerTiles
*pT
= (CLayerTiles
*)GetSelectedLayerType(0, LAYERTYPE_TILES
);
3886 for(int i
= 0; i
< pT
->m_Width
*2; ++i
)
3887 pT
->m_pTiles
[i
].m_Index
= 1;
3889 for(int i
= 0; i
< pT
->m_Width
*pT
->m_Height
; ++i
)
3891 if(i
%pT
->m_Width
< 2 || i
%pT
->m_Width
> pT
->m_Width
-3)
3892 pT
->m_pTiles
[i
].m_Index
= 1;
3895 for(int i
= (pT
->m_Width
*(pT
->m_Height
-2)); i
< pT
->m_Width
*pT
->m_Height
; ++i
)
3896 pT
->m_pTiles
[i
].m_Index
= 1;
3899 void CEditor::UpdateAndRender()
3901 static float s_MouseX
= 0.0f
;
3902 static float s_MouseY
= 0.0f
;
3905 m_AnimateTime
= (time_get()-m_AnimateStart
)/(float)time_freq();
3908 ms_pUiGotContext
= 0;
3910 // handle mouse movement
3911 float mx
, my
, Mwx
, Mwy
;
3914 Input()->MouseRelative(&rx
, &ry
);
3915 UI()->ConvertMouseMove(&rx
, &ry
);
3925 s_MouseX
= clamp(s_MouseX
, 0.0f
, UI()->Screen()->w
);
3926 s_MouseY
= clamp(s_MouseY
, 0.0f
, UI()->Screen()->h
);
3934 // fix correct world x and y
3935 CLayerGroup
*g
= GetSelectedGroup();
3939 g
->Mapping(aPoints
);
3941 float WorldWidth
= aPoints
[2]-aPoints
[0];
3942 float WorldHeight
= aPoints
[3]-aPoints
[1];
3944 Mwx
= aPoints
[0] + WorldWidth
* (s_MouseX
/UI()->Screen()->w
);
3945 Mwy
= aPoints
[1] + WorldHeight
* (s_MouseY
/UI()->Screen()->h
);
3946 m_MouseDeltaWx
= m_MouseDeltaX
*(WorldWidth
/ UI()->Screen()->w
);
3947 m_MouseDeltaWy
= m_MouseDeltaY
*(WorldHeight
/ UI()->Screen()->h
);
3951 if(Input()->KeyPressed(KEY_MOUSE_1
)) Buttons
|= 1;
3952 if(Input()->KeyPressed(KEY_MOUSE_2
)) Buttons
|= 2;
3953 if(Input()->KeyPressed(KEY_MOUSE_3
)) Buttons
|= 4;
3955 UI()->Update(mx
,my
,Mwx
,Mwy
,Buttons
);
3959 if(Input()->KeyDown(KEY_TAB
))
3960 m_GuiActive
= !m_GuiActive
;
3962 if(Input()->KeyDown(KEY_F10
))
3963 m_ShowMousePointer
= false;
3967 if(Input()->KeyDown(KEY_F10
))
3969 Graphics()->TakeScreenshot(0);
3970 m_ShowMousePointer
= true;
3973 Input()->ClearEvents();
3976 IEditor
*CreateEditor() { return new CEditor
; }