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. */
3#ifndef GAME_EDITOR_EDITOR_H
4#define GAME_EDITOR_EDITOR_H
5
6#include <base/bezier.h>
7#include <base/system.h>
8
9#include <game/client/render.h>
10#include <game/client/ui.h>
11#include <game/client/ui_listbox.h>
12#include <game/mapitems.h>
13
14#include <game/editor/mapitems/envelope.h>
15#include <game/editor/mapitems/layer.h>
16#include <game/editor/mapitems/layer_front.h>
17#include <game/editor/mapitems/layer_game.h>
18#include <game/editor/mapitems/layer_group.h>
19#include <game/editor/mapitems/layer_quads.h>
20#include <game/editor/mapitems/layer_sounds.h>
21#include <game/editor/mapitems/layer_speedup.h>
22#include <game/editor/mapitems/layer_switch.h>
23#include <game/editor/mapitems/layer_tele.h>
24#include <game/editor/mapitems/layer_tiles.h>
25#include <game/editor/mapitems/layer_tune.h>
26
27#include <engine/console.h>
28#include <engine/editor.h>
29#include <engine/engine.h>
30#include <engine/graphics.h>
31#include <engine/shared/datafile.h>
32#include <engine/shared/jobs.h>
33
34#include "auto_map.h"
35#include "editor_history.h"
36#include "editor_server_settings.h"
37#include "editor_trackers.h"
38#include "editor_ui.h"
39#include "layer_selector.h"
40#include "map_view.h"
41#include "smooth_value.h"
42
43#include <deque>
44#include <functional>
45#include <map>
46#include <memory>
47#include <string>
48#include <vector>
49
50typedef std::function<void(int *pIndex)> FIndexModifyFunction;
51template<typename T>
52using FDropdownRenderCallback = std::function<void(const T &, char (&aOutput)[128], std::vector<STextColorSplit> &)>;
53
54// CEditor SPECIFIC
55enum
56{
57 MODE_LAYERS = 0,
58 MODE_IMAGES,
59 MODE_SOUNDS,
60 NUM_MODES,
61
62 DIALOG_NONE = 0,
63 DIALOG_FILE,
64 DIALOG_MAPSETTINGS_ERROR
65};
66
67class CEditorImage;
68class CEditorSound;
69
70class CEditorMap
71{
72 void MakeGameGroup(std::shared_ptr<CLayerGroup> pGroup);
73 void MakeGameLayer(const std::shared_ptr<CLayer> &pLayer);
74
75public:
76 CEditor *m_pEditor;
77
78 CEditorMap()
79 {
80 Clean();
81 }
82
83 ~CEditorMap()
84 {
85 Clean();
86 }
87
88 bool m_Modified; // unsaved changes in manual save
89 bool m_ModifiedAuto; // unsaved changes in autosave
90 float m_LastModifiedTime;
91 float m_LastSaveTime;
92 float m_LastAutosaveUpdateTime;
93 void OnModify();
94
95 std::vector<std::shared_ptr<CLayerGroup>> m_vpGroups;
96 std::vector<std::shared_ptr<CEditorImage>> m_vpImages;
97 std::vector<std::shared_ptr<CEnvelope>> m_vpEnvelopes;
98 std::vector<std::shared_ptr<CEditorSound>> m_vpSounds;
99
100 class CMapInfo
101 {
102 public:
103 char m_aAuthor[32];
104 char m_aVersion[16];
105 char m_aCredits[128];
106 char m_aLicense[32];
107
108 void Reset()
109 {
110 m_aAuthor[0] = '\0';
111 m_aVersion[0] = '\0';
112 m_aCredits[0] = '\0';
113 m_aLicense[0] = '\0';
114 }
115
116 void Copy(const CMapInfo &Source)
117 {
118 str_copy(dst&: m_aAuthor, src: Source.m_aAuthor);
119 str_copy(dst&: m_aVersion, src: Source.m_aVersion);
120 str_copy(dst&: m_aCredits, src: Source.m_aCredits);
121 str_copy(dst&: m_aLicense, src: Source.m_aLicense);
122 }
123 };
124 CMapInfo m_MapInfo;
125 CMapInfo m_MapInfoTmp;
126
127 std::vector<CEditorMapSetting> m_vSettings;
128
129 std::shared_ptr<class CLayerGame> m_pGameLayer;
130 std::shared_ptr<CLayerGroup> m_pGameGroup;
131
132 std::shared_ptr<CEnvelope> NewEnvelope(CEnvelope::EType Type)
133 {
134 OnModify();
135 std::shared_ptr<CEnvelope> pEnv = std::make_shared<CEnvelope>(args&: Type);
136 m_vpEnvelopes.push_back(x: pEnv);
137 return pEnv;
138 }
139
140 void DeleteEnvelope(int Index);
141 void SwapEnvelopes(int Index0, int Index1);
142 template<typename F>
143 void VisitEnvelopeReferences(F &&Visitor);
144
145 std::shared_ptr<CLayerGroup> NewGroup()
146 {
147 OnModify();
148 std::shared_ptr<CLayerGroup> pGroup = std::make_shared<CLayerGroup>();
149 pGroup->m_pMap = this;
150 m_vpGroups.push_back(x: pGroup);
151 return pGroup;
152 }
153
154 int SwapGroups(int Index0, int Index1)
155 {
156 if(Index0 < 0 || Index0 >= (int)m_vpGroups.size())
157 return Index0;
158 if(Index1 < 0 || Index1 >= (int)m_vpGroups.size())
159 return Index0;
160 if(Index0 == Index1)
161 return Index0;
162 OnModify();
163 std::swap(a&: m_vpGroups[Index0], b&: m_vpGroups[Index1]);
164 return Index1;
165 }
166
167 void DeleteGroup(int Index)
168 {
169 if(Index < 0 || Index >= (int)m_vpGroups.size())
170 return;
171 OnModify();
172 m_vpGroups.erase(position: m_vpGroups.begin() + Index);
173 }
174
175 void ModifyImageIndex(FIndexModifyFunction pfnFunc)
176 {
177 OnModify();
178 for(auto &pGroup : m_vpGroups)
179 pGroup->ModifyImageIndex(Func: pfnFunc);
180 }
181
182 void ModifyEnvelopeIndex(FIndexModifyFunction pfnFunc)
183 {
184 OnModify();
185 for(auto &pGroup : m_vpGroups)
186 pGroup->ModifyEnvelopeIndex(Func: pfnFunc);
187 }
188
189 void ModifySoundIndex(FIndexModifyFunction pfnFunc)
190 {
191 OnModify();
192 for(auto &pGroup : m_vpGroups)
193 pGroup->ModifySoundIndex(Func: pfnFunc);
194 }
195
196 void Clean();
197 void CreateDefault(IGraphics::CTextureHandle EntitiesTexture);
198
199 // io
200 bool Save(const char *pFilename);
201 bool Load(const char *pFilename, int StorageType, const std::function<void(const char *pErrorMessage)> &ErrorHandler);
202 void PerformSanityChecks(const std::function<void(const char *pErrorMessage)> &ErrorHandler);
203
204 // DDRace
205
206 std::shared_ptr<class CLayerTele> m_pTeleLayer;
207 std::shared_ptr<class CLayerSpeedup> m_pSpeedupLayer;
208 std::shared_ptr<class CLayerFront> m_pFrontLayer;
209 std::shared_ptr<class CLayerSwitch> m_pSwitchLayer;
210 std::shared_ptr<class CLayerTune> m_pTuneLayer;
211 void MakeTeleLayer(const std::shared_ptr<CLayer> &pLayer);
212 void MakeSpeedupLayer(const std::shared_ptr<CLayer> &pLayer);
213 void MakeFrontLayer(const std::shared_ptr<CLayer> &pLayer);
214 void MakeSwitchLayer(const std::shared_ptr<CLayer> &pLayer);
215 void MakeTuneLayer(const std::shared_ptr<CLayer> &pLayer);
216};
217
218struct CProperty
219{
220 const char *m_pName;
221 int m_Value;
222 int m_Type;
223 int m_Min;
224 int m_Max;
225};
226
227enum
228{
229 PROPTYPE_NULL = 0,
230 PROPTYPE_BOOL,
231 PROPTYPE_INT,
232 PROPTYPE_ANGLE_SCROLL,
233 PROPTYPE_COLOR,
234 PROPTYPE_IMAGE,
235 PROPTYPE_ENVELOPE,
236 PROPTYPE_SHIFT,
237 PROPTYPE_SOUND,
238 PROPTYPE_AUTOMAPPER,
239};
240
241class CDataFileWriterFinishJob : public IJob
242{
243 char m_aRealFileName[IO_MAX_PATH_LENGTH];
244 char m_aTempFileName[IO_MAX_PATH_LENGTH];
245 CDataFileWriter m_Writer;
246
247 void Run() override
248 {
249 m_Writer.Finish();
250 }
251
252public:
253 CDataFileWriterFinishJob(const char *pRealFileName, const char *pTempFileName, CDataFileWriter &&Writer) :
254 m_Writer(std::move(Writer))
255 {
256 str_copy(dst&: m_aRealFileName, src: pRealFileName);
257 str_copy(dst&: m_aTempFileName, src: pTempFileName);
258 }
259
260 const char *GetRealFileName() const { return m_aRealFileName; }
261 const char *GetTempFileName() const { return m_aTempFileName; }
262};
263
264class CEditor : public IEditor
265{
266 class IInput *m_pInput = nullptr;
267 class IClient *m_pClient = nullptr;
268 class IConfigManager *m_pConfigManager = nullptr;
269 class CConfig *m_pConfig = nullptr;
270 class IConsole *m_pConsole = nullptr;
271 class IEngine *m_pEngine = nullptr;
272 class IGraphics *m_pGraphics = nullptr;
273 class ITextRender *m_pTextRender = nullptr;
274 class ISound *m_pSound = nullptr;
275 class IStorage *m_pStorage = nullptr;
276 CRenderTools m_RenderTools;
277 CUi m_UI;
278
279 std::vector<std::reference_wrapper<CEditorComponent>> m_vComponents;
280 CMapView m_MapView;
281 CLayerSelector m_LayerSelector;
282
283 bool m_EditorWasUsedBefore = false;
284
285 IGraphics::CTextureHandle m_EntitiesTexture;
286
287 IGraphics::CTextureHandle m_FrontTexture;
288 IGraphics::CTextureHandle m_TeleTexture;
289 IGraphics::CTextureHandle m_SpeedupTexture;
290 IGraphics::CTextureHandle m_SwitchTexture;
291 IGraphics::CTextureHandle m_TuneTexture;
292
293 int GetTextureUsageFlag() const;
294
295 enum EPreviewState
296 {
297 PREVIEW_UNLOADED,
298 PREVIEW_LOADED,
299 PREVIEW_ERROR,
300 };
301
302 std::shared_ptr<CLayerGroup> m_apSavedBrushes[10];
303 static const ColorRGBA ms_DefaultPropColor;
304
305public:
306 class IInput *Input() const { return m_pInput; }
307 class IClient *Client() const { return m_pClient; }
308 class IConfigManager *ConfigManager() const { return m_pConfigManager; }
309 class CConfig *Config() const { return m_pConfig; }
310 class IConsole *Console() const { return m_pConsole; }
311 class IEngine *Engine() const { return m_pEngine; }
312 class IGraphics *Graphics() const { return m_pGraphics; }
313 class ISound *Sound() const { return m_pSound; }
314 class ITextRender *TextRender() const { return m_pTextRender; }
315 class IStorage *Storage() const { return m_pStorage; }
316 CUi *Ui() { return &m_UI; }
317 CRenderTools *RenderTools() { return &m_RenderTools; }
318
319 CMapView *MapView() { return &m_MapView; }
320 const CMapView *MapView() const { return &m_MapView; }
321 CLayerSelector *LayerSelector() { return &m_LayerSelector; }
322
323 CEditor() :
324 m_ZoomEnvelopeX(1.0f, 0.1f, 600.0f),
325 m_ZoomEnvelopeY(640.0f, 0.1f, 32000.0f),
326 m_MapSettingsCommandContext(m_MapSettingsBackend.NewContext(pLineInput: &m_SettingsCommandInput))
327 {
328 m_EntitiesTexture.Invalidate();
329 m_FrontTexture.Invalidate();
330 m_TeleTexture.Invalidate();
331 m_SpeedupTexture.Invalidate();
332 m_SwitchTexture.Invalidate();
333 m_TuneTexture.Invalidate();
334
335 m_Mode = MODE_LAYERS;
336 m_Dialog = 0;
337
338 m_BrushColorEnabled = true;
339
340 m_aFileName[0] = '\0';
341 m_aFileNamePending[0] = '\0';
342 m_aFileSaveName[0] = '\0';
343 m_ValidSaveFilename = false;
344
345 m_PopupEventActivated = false;
346 m_PopupEventWasActivated = false;
347
348 m_FileDialogStorageType = 0;
349 m_FileDialogLastPopulatedStorageType = 0;
350 m_pFileDialogTitle = nullptr;
351 m_pFileDialogButtonText = nullptr;
352 m_pFileDialogUser = nullptr;
353 m_aFileDialogCurrentFolder[0] = '\0';
354 m_aFileDialogCurrentLink[0] = '\0';
355 m_aFilesSelectedName[0] = '\0';
356 m_pFileDialogPath = m_aFileDialogCurrentFolder;
357 m_FileDialogOpening = false;
358 m_FilesSelectedIndex = -1;
359
360 m_FilePreviewImage.Invalidate();
361 m_FilePreviewSound = -1;
362 m_FilePreviewState = PREVIEW_UNLOADED;
363
364 m_ToolbarPreviewSound = -1;
365
366 m_SelectEntitiesImage = "DDNet";
367
368 m_ResetZoomEnvelope = true;
369 m_OffsetEnvelopeX = 0.1f;
370 m_OffsetEnvelopeY = 0.5f;
371
372 m_ShowMousePointer = true;
373
374 m_GuiActive = true;
375 m_PreviewZoom = false;
376
377 m_ShowTileInfo = SHOW_TILE_OFF;
378 m_ShowDetail = true;
379 m_Animate = false;
380 m_AnimateStart = 0;
381 m_AnimateTime = 0;
382 m_AnimateSpeed = 1;
383 m_AnimateUpdatePopup = false;
384
385 m_ShowEnvelopePreview = SHOWENV_NONE;
386 m_SelectedQuadEnvelope = -1;
387
388 m_vSelectedEnvelopePoints = {};
389 m_UpdateEnvPointInfo = false;
390 m_SelectedTangentInPoint = std::pair(-1, -1);
391 m_SelectedTangentOutPoint = std::pair(-1, -1);
392 m_CurrentQuadIndex = -1;
393
394 m_QuadKnifeActive = false;
395 m_QuadKnifeCount = 0;
396 mem_zero(block: m_aQuadKnifePoints, size: sizeof(m_aQuadKnifePoints));
397
398 for(size_t i = 0; i < std::size(m_aSavedColors); ++i)
399 {
400 m_aSavedColors[i] = color_cast<ColorRGBA>(hsl: ColorHSLA(i / (float)std::size(m_aSavedColors), 1.0f, 0.5f));
401 }
402
403 m_CheckerTexture.Invalidate();
404 m_BackgroundTexture.Invalidate();
405 for(int i = 0; i < NUM_CURSORS; i++)
406 m_aCursorTextures[i].Invalidate();
407
408 m_CursorType = CURSOR_NORMAL;
409
410 ms_pUiGotContext = nullptr;
411
412 // DDRace
413
414 m_TeleNumber = 1;
415 m_TeleCheckpointNumber = 1;
416 m_SwitchNum = 1;
417 m_TuningNum = 1;
418 m_SwitchDelay = 0;
419 m_SpeedupForce = 50;
420 m_SpeedupMaxSpeed = 0;
421 m_SpeedupAngle = 0;
422 m_LargeLayerWasWarned = false;
423 m_PreventUnusedTilesWasWarned = false;
424 m_AllowPlaceUnusedTiles = 0;
425 m_BrushDrawDestructive = true;
426 }
427
428 class CHoverTile
429 {
430 public:
431 CHoverTile(int Group, int Layer, int x, int y, const CTile Tile) :
432 m_Group(Group),
433 m_Layer(Layer),
434 m_X(x),
435 m_Y(y),
436 m_Tile(Tile)
437 {
438 }
439
440 int m_Group;
441 int m_Layer;
442 int m_X;
443 int m_Y;
444 const CTile m_Tile;
445 };
446 std::vector<CHoverTile> m_vHoverTiles;
447 const std::vector<CHoverTile> &HoverTiles() const { return m_vHoverTiles; }
448
449 void Init() override;
450 void OnUpdate() override;
451 void OnRender() override;
452 void OnActivate() override;
453 void OnWindowResize() override;
454 void OnClose() override;
455 void OnDialogClose() override;
456 bool HasUnsavedData() const override { return m_Map.m_Modified; }
457 void UpdateMentions() override { m_Mentions++; }
458 void ResetMentions() override { m_Mentions = 0; }
459 void OnIngameMoved() override { m_IngameMoved = true; }
460 void ResetIngameMoved() override { m_IngameMoved = false; }
461
462 void HandleCursorMovement();
463 void OnMouseMove(vec2 MousePos);
464 void HandleAutosave();
465 bool PerformAutosave();
466 void HandleWriterFinishJobs();
467
468 void RefreshFilteredFileList();
469 void FilelistPopulate(int StorageType, bool KeepSelection = false);
470 void InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText,
471 const char *pBasepath, bool FilenameAsDefault,
472 bool (*pfnFunc)(const char *pFilename, int StorageType, void *pUser), void *pUser);
473 struct SStringKeyComparator
474 {
475 bool operator()(const char *pLhs, const char *pRhs) const
476 {
477 return str_comp(a: pLhs, b: pRhs) < 0;
478 }
479 };
480 std::map<const char *, CUi::SMessagePopupContext *, SStringKeyComparator> m_PopupMessageContexts;
481 void ShowFileDialogError(const char *pFormat, ...)
482 GNUC_ATTRIBUTE((format(printf, 2, 3)));
483
484 void Reset(bool CreateDefault = true);
485 bool Save(const char *pFilename) override;
486 bool Load(const char *pFilename, int StorageType) override;
487 bool HandleMapDrop(const char *pFilename, int StorageType) override;
488 bool Append(const char *pFilename, int StorageType, bool IgnoreHistory = false);
489 void LoadCurrentMap();
490 void Render();
491
492 void RenderPressedKeys(CUIRect View);
493 void RenderSavingIndicator(CUIRect View);
494 void FreeDynamicPopupMenus();
495 void UpdateColorPipette();
496 void RenderMousePointer();
497
498 std::vector<CQuad *> GetSelectedQuads();
499 std::shared_ptr<CLayer> GetSelectedLayerType(int Index, int Type) const;
500 std::shared_ptr<CLayer> GetSelectedLayer(int Index) const;
501 std::shared_ptr<CLayerGroup> GetSelectedGroup() const;
502 CSoundSource *GetSelectedSource() const;
503 void SelectLayer(int LayerIndex, int GroupIndex = -1);
504 void AddSelectedLayer(int LayerIndex);
505 void SelectQuad(int Index);
506 void ToggleSelectQuad(int Index);
507 void DeselectQuads();
508 void DeselectQuadPoints();
509 void SelectQuadPoint(int QuadIndex, int Index);
510 void ToggleSelectQuadPoint(int QuadIndex, int Index);
511 void DeleteSelectedQuads();
512 bool IsQuadSelected(int Index) const;
513 bool IsQuadCornerSelected(int Index) const;
514 bool IsQuadPointSelected(int QuadIndex, int Index) const;
515 int FindSelectedQuadIndex(int Index) const;
516
517 int FindEnvPointIndex(int Index, int Channel) const;
518 void SelectEnvPoint(int Index);
519 void SelectEnvPoint(int Index, int Channel);
520 void ToggleEnvPoint(int Index, int Channel);
521 bool IsEnvPointSelected(int Index, int Channel) const;
522 bool IsEnvPointSelected(int Index) const;
523 void DeselectEnvPoints();
524 void SelectTangentOutPoint(int Index, int Channel);
525 bool IsTangentOutPointSelected(int Index, int Channel) const;
526 void SelectTangentInPoint(int Index, int Channel);
527 bool IsTangentInPointSelected(int Index, int Channel) const;
528 bool IsTangentInSelected() const;
529 bool IsTangentOutSelected() const;
530 bool IsTangentSelected() const;
531 std::pair<int, int> EnvGetSelectedTimeAndValue() const;
532
533 template<typename E>
534 SEditResult<E> DoPropertiesWithState(CUIRect *pToolbox, CProperty *pProps, int *pIds, int *pNewVal, const std::vector<ColorRGBA> &vColors = {});
535 int DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIds, int *pNewVal, const std::vector<ColorRGBA> &vColors = {});
536
537 CUi::SColorPickerPopupContext m_ColorPickerPopupContext;
538 const void *m_pColorPickerPopupActiveId = nullptr;
539 void DoColorPickerButton(const void *pId, const CUIRect *pRect, ColorRGBA Color, const std::function<void(ColorRGBA Color)> &SetColor);
540
541 int m_Mode;
542 int m_Dialog;
543 char m_aTooltip[256] = "";
544
545 bool m_BrushColorEnabled;
546
547 char m_aFileName[IO_MAX_PATH_LENGTH];
548 char m_aFileNamePending[IO_MAX_PATH_LENGTH];
549 char m_aFileSaveName[IO_MAX_PATH_LENGTH];
550 bool m_ValidSaveFilename;
551
552 enum
553 {
554 POPEVENT_EXIT = 0,
555 POPEVENT_LOAD,
556 POPEVENT_LOADCURRENT,
557 POPEVENT_LOADDROP,
558 POPEVENT_NEW,
559 POPEVENT_SAVE,
560 POPEVENT_SAVE_COPY,
561 POPEVENT_SAVE_IMG,
562 POPEVENT_SAVE_SOUND,
563 POPEVENT_LARGELAYER,
564 POPEVENT_PREVENTUNUSEDTILES,
565 POPEVENT_IMAGEDIV16,
566 POPEVENT_IMAGE_MAX,
567 POPEVENT_SOUND_MAX,
568 POPEVENT_PLACE_BORDER_TILES,
569 POPEVENT_PIXELART_BIG_IMAGE,
570 POPEVENT_PIXELART_MANY_COLORS,
571 POPEVENT_PIXELART_TOO_MANY_COLORS
572 };
573
574 int m_PopupEventType;
575 int m_PopupEventActivated;
576 int m_PopupEventWasActivated;
577 bool m_LargeLayerWasWarned;
578 bool m_PreventUnusedTilesWasWarned;
579 int m_AllowPlaceUnusedTiles;
580 bool m_BrushDrawDestructive;
581
582 int m_Mentions = 0;
583 bool m_IngameMoved = false;
584
585 enum
586 {
587 FILETYPE_MAP,
588 FILETYPE_IMG,
589 FILETYPE_SOUND,
590 NUM_FILETYPES
591 };
592
593 int m_FileDialogStorageType;
594 int m_FileDialogLastPopulatedStorageType;
595 const char *m_pFileDialogTitle;
596 const char *m_pFileDialogButtonText;
597 bool (*m_pfnFileDialogFunc)(const char *pFileName, int StorageType, void *pUser);
598 void *m_pFileDialogUser;
599 CLineInputBuffered<IO_MAX_PATH_LENGTH> m_FileDialogFileNameInput;
600 char m_aFileDialogCurrentFolder[IO_MAX_PATH_LENGTH];
601 char m_aFileDialogCurrentLink[IO_MAX_PATH_LENGTH];
602 char m_aFilesSelectedName[IO_MAX_PATH_LENGTH];
603 CLineInputBuffered<IO_MAX_PATH_LENGTH> m_FileDialogFilterInput;
604 char *m_pFileDialogPath;
605 int m_FileDialogFileType;
606 bool m_FileDialogMultipleStorages = false;
607 bool m_FileDialogShowingRoot = false;
608 int m_FilesSelectedIndex;
609 CLineInputBuffered<IO_MAX_PATH_LENGTH> m_FileDialogNewFolderNameInput;
610
611 IGraphics::CTextureHandle m_FilePreviewImage;
612 int m_FilePreviewSound;
613 EPreviewState m_FilePreviewState;
614 CImageInfo m_FilePreviewImageInfo;
615 bool m_FileDialogOpening;
616
617 int m_ToolbarPreviewSound;
618
619 struct CFilelistItem
620 {
621 char m_aFilename[IO_MAX_PATH_LENGTH];
622 char m_aName[IO_MAX_PATH_LENGTH];
623 bool m_IsDir;
624 bool m_IsLink;
625 int m_StorageType;
626 time_t m_TimeModified;
627 };
628 std::vector<CFilelistItem> m_vCompleteFileList;
629 std::vector<const CFilelistItem *> m_vpFilteredFileList;
630
631 static bool CompareFilenameAscending(const CFilelistItem *pLhs, const CFilelistItem *pRhs)
632 {
633 if(str_comp(a: pLhs->m_aFilename, b: "..") == 0)
634 return true;
635 if(str_comp(a: pRhs->m_aFilename, b: "..") == 0)
636 return false;
637 if(pLhs->m_IsLink != pRhs->m_IsLink)
638 return pLhs->m_IsLink;
639 if(pLhs->m_IsDir != pRhs->m_IsDir)
640 return pLhs->m_IsDir;
641 return str_comp_filenames(a: pLhs->m_aName, b: pRhs->m_aName) < 0;
642 }
643
644 static bool CompareFilenameDescending(const CFilelistItem *pLhs, const CFilelistItem *pRhs)
645 {
646 if(str_comp(a: pLhs->m_aFilename, b: "..") == 0)
647 return true;
648 if(str_comp(a: pRhs->m_aFilename, b: "..") == 0)
649 return false;
650 if(pLhs->m_IsLink != pRhs->m_IsLink)
651 return pLhs->m_IsLink;
652 if(pLhs->m_IsDir != pRhs->m_IsDir)
653 return pLhs->m_IsDir;
654 return str_comp_filenames(a: pLhs->m_aName, b: pRhs->m_aName) > 0;
655 }
656
657 static bool CompareTimeModifiedAscending(const CFilelistItem *pLhs, const CFilelistItem *pRhs)
658 {
659 if(str_comp(a: pLhs->m_aFilename, b: "..") == 0)
660 return true;
661 if(str_comp(a: pRhs->m_aFilename, b: "..") == 0)
662 return false;
663 if(pLhs->m_IsLink || pRhs->m_IsLink)
664 return pLhs->m_IsLink;
665 if(pLhs->m_IsDir != pRhs->m_IsDir)
666 return pLhs->m_IsDir;
667 return pLhs->m_TimeModified < pRhs->m_TimeModified;
668 }
669
670 static bool CompareTimeModifiedDescending(const CFilelistItem *pLhs, const CFilelistItem *pRhs)
671 {
672 if(str_comp(a: pLhs->m_aFilename, b: "..") == 0)
673 return true;
674 if(str_comp(a: pRhs->m_aFilename, b: "..") == 0)
675 return false;
676 if(pLhs->m_IsLink || pRhs->m_IsLink)
677 return pLhs->m_IsLink;
678 if(pLhs->m_IsDir != pRhs->m_IsDir)
679 return pLhs->m_IsDir;
680 return pLhs->m_TimeModified > pRhs->m_TimeModified;
681 }
682
683 void SortFilteredFileList();
684 int m_SortByFilename = 1;
685 int m_SortByTimeModified = 0;
686
687 std::vector<std::string> m_vSelectEntitiesFiles;
688 std::string m_SelectEntitiesImage;
689
690 // Zooming
691 CSmoothValue m_ZoomEnvelopeX;
692 CSmoothValue m_ZoomEnvelopeY;
693
694 bool m_ResetZoomEnvelope;
695
696 float m_OffsetEnvelopeX;
697 float m_OffsetEnvelopeY;
698
699 bool m_ShowMousePointer;
700 bool m_GuiActive;
701
702 char m_aMenuBackgroundTooltip[256];
703 bool m_PreviewZoom;
704 float m_MouseWorldScale = 1.0f; // Mouse (i.e. UI) scale relative to the World (selected Group)
705 vec2 m_MouseWorldPos = vec2(0.0f, 0.0f);
706 vec2 m_MouseWorldNoParaPos = vec2(0.0f, 0.0f);
707 vec2 m_MouseDeltaWorld = vec2(0.0f, 0.0f);
708 const void *m_pContainerPanned;
709 const void *m_pContainerPannedLast;
710 char m_MapEditorId; // UI element ID for the main map editor
711
712 enum EShowTile
713 {
714 SHOW_TILE_OFF,
715 SHOW_TILE_DECIMAL,
716 SHOW_TILE_HEXADECIMAL
717 };
718 EShowTile m_ShowTileInfo;
719 bool m_ShowDetail;
720
721 bool m_Animate;
722 int64_t m_AnimateStart;
723 float m_AnimateTime;
724 float m_AnimateSpeed;
725 bool m_AnimateUpdatePopup;
726
727 enum EExtraEditor
728 {
729 EXTRAEDITOR_NONE = -1,
730 EXTRAEDITOR_ENVELOPES,
731 EXTRAEDITOR_SERVER_SETTINGS,
732 EXTRAEDITOR_HISTORY,
733 NUM_EXTRAEDITORS,
734 };
735 EExtraEditor m_ActiveExtraEditor = EXTRAEDITOR_NONE;
736 float m_aExtraEditorSplits[NUM_EXTRAEDITORS] = {250.0f, 250.0f, 250.0f};
737 float m_ToolBoxWidth = 100.0f;
738
739 enum EShowEnvelope
740 {
741 SHOWENV_NONE = 0,
742 SHOWENV_SELECTED,
743 SHOWENV_ALL
744 };
745 EShowEnvelope m_ShowEnvelopePreview;
746 bool m_ShowPicker;
747
748 std::vector<int> m_vSelectedLayers;
749 std::vector<int> m_vSelectedQuads;
750 int m_SelectedQuadPoint;
751 int m_SelectedQuadIndex;
752 int m_SelectedGroup;
753 int m_SelectedQuadPoints;
754 int m_SelectedEnvelope;
755 std::vector<std::pair<int, int>> m_vSelectedEnvelopePoints;
756 int m_SelectedQuadEnvelope;
757 int m_CurrentQuadIndex;
758 int m_SelectedImage;
759 int m_SelectedSound;
760 int m_SelectedSource;
761 std::pair<int, int> m_SelectedTangentInPoint;
762 std::pair<int, int> m_SelectedTangentOutPoint;
763 bool m_UpdateEnvPointInfo;
764
765 bool m_QuadKnifeActive;
766 int m_QuadKnifeCount;
767 vec2 m_aQuadKnifePoints[4];
768
769 // Color palette and pipette
770 ColorRGBA m_aSavedColors[8];
771 ColorRGBA m_PipetteColor = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
772 bool m_ColorPipetteActive = false;
773
774 IGraphics::CTextureHandle m_CheckerTexture;
775 IGraphics::CTextureHandle m_BackgroundTexture;
776
777 enum ECursorType
778 {
779 CURSOR_NORMAL,
780 CURSOR_RESIZE_V,
781 CURSOR_RESIZE_H,
782 NUM_CURSORS
783 };
784 IGraphics::CTextureHandle m_aCursorTextures[ECursorType::NUM_CURSORS];
785 ECursorType m_CursorType;
786
787 IGraphics::CTextureHandle GetEntitiesTexture();
788
789 std::shared_ptr<CLayerGroup> m_pBrush;
790 std::shared_ptr<CLayerTiles> m_pTilesetPicker;
791 std::shared_ptr<CLayerQuads> m_pQuadsetPicker;
792
793 static const void *ms_pUiGotContext;
794
795 CEditorMap m_Map;
796 std::deque<std::shared_ptr<CDataFileWriterFinishJob>> m_WriterFinishJobs;
797
798 int m_ShiftBy;
799
800 static void EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Result, size_t Channels, void *pUser);
801
802 CLineInputBuffered<256> m_SettingsCommandInput;
803 CMapSettingsBackend m_MapSettingsBackend;
804 CMapSettingsBackend::CContext m_MapSettingsCommandContext;
805
806 CImageInfo m_TileartImageInfo;
807 char m_aTileartFilename[IO_MAX_PATH_LENGTH];
808 void AddTileart(bool IgnoreHistory = false);
809 void TileartCheckColors();
810
811 void PlaceBorderTiles();
812
813 void UpdateTooltip(const void *pId, const CUIRect *pRect, const char *pToolTip);
814 int DoButton_Editor_Common(const void *pId, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
815 int DoButton_Editor(const void *pId, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
816 int DoButton_Env(const void *pId, const char *pText, int Checked, const CUIRect *pRect, const char *pToolTip, ColorRGBA Color, int Corners);
817
818 int DoButton_Ex(const void *pId, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners, float FontSize = EditorFontSizes::MENU, int Align = TEXTALIGN_MC);
819 int DoButton_FontIcon(const void *pId, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners, float FontSize = 10.0f);
820 int DoButton_MenuItem(const void *pId, const char *pText, int Checked, const CUIRect *pRect, int Flags = 0, const char *pToolTip = nullptr);
821
822 int DoButton_DraggableEx(const void *pId, const char *pText, int Checked, const CUIRect *pRect, bool *pClicked, bool *pAbrupted, int Flags, const char *pToolTip = nullptr, int Corners = IGraphics::CORNER_ALL, float FontSize = 10.0f);
823
824 bool DoEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners = IGraphics::CORNER_ALL, const char *pToolTip = nullptr, const std::vector<STextColorSplit> &vColorSplits = {});
825 bool DoClearableEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners = IGraphics::CORNER_ALL, const char *pToolTip = nullptr, const std::vector<STextColorSplit> &vColorSplits = {});
826
827 void DoMapSettingsEditBox(CMapSettingsBackend::CContext *pContext, const CUIRect *pRect, float FontSize, float DropdownMaxHeight, int Corners = IGraphics::CORNER_ALL, const char *pToolTip = nullptr);
828
829 template<typename T>
830 int DoEditBoxDropdown(SEditBoxDropdownContext *pDropdown, CLineInput *pLineInput, const CUIRect *pEditBoxRect, int x, float MaxHeight, bool AutoWidth, const std::vector<T> &vData, const FDropdownRenderCallback<T> &fnMatchCallback);
831 template<typename T>
832 int RenderEditBoxDropdown(SEditBoxDropdownContext *pDropdown, CUIRect View, CLineInput *pLineInput, int x, float MaxHeight, bool AutoWidth, const std::vector<T> &vData, const FDropdownRenderCallback<T> &fnMatchCallback);
833
834 void RenderBackground(CUIRect View, IGraphics::CTextureHandle Texture, float Size, float Brightness) const;
835
836 SEditResult<int> UiDoValueSelector(void *pId, CUIRect *pRect, const char *pLabel, int Current, int Min, int Max, int Step, float Scale, const char *pToolTip, bool IsDegree = false, bool IsHex = false, int corners = IGraphics::CORNER_ALL, const ColorRGBA *pColor = nullptr, bool ShowValue = true);
837
838 static CUi::EPopupMenuFunctionResult PopupMenuFile(void *pContext, CUIRect View, bool Active);
839 static CUi::EPopupMenuFunctionResult PopupMenuTools(void *pContext, CUIRect View, bool Active);
840 static CUi::EPopupMenuFunctionResult PopupMenuSettings(void *pContext, CUIRect View, bool Active);
841 static CUi::EPopupMenuFunctionResult PopupGroup(void *pContext, CUIRect View, bool Active);
842 struct SLayerPopupContext : public SPopupMenuId
843 {
844 CEditor *m_pEditor;
845 std::vector<std::shared_ptr<CLayerTiles>> m_vpLayers;
846 std::vector<int> m_vLayerIndices;
847 CLayerTiles::SCommonPropState m_CommonPropState;
848 };
849 static CUi::EPopupMenuFunctionResult PopupLayer(void *pContext, CUIRect View, bool Active);
850 static CUi::EPopupMenuFunctionResult PopupQuad(void *pContext, CUIRect View, bool Active);
851 static CUi::EPopupMenuFunctionResult PopupSource(void *pContext, CUIRect View, bool Active);
852 static CUi::EPopupMenuFunctionResult PopupPoint(void *pContext, CUIRect View, bool Active);
853 static CUi::EPopupMenuFunctionResult PopupEnvPoint(void *pContext, CUIRect View, bool Active);
854 static CUi::EPopupMenuFunctionResult PopupEnvPointMulti(void *pContext, CUIRect View, bool Active);
855 static CUi::EPopupMenuFunctionResult PopupEnvPointCurveType(void *pContext, CUIRect View, bool Active);
856 static CUi::EPopupMenuFunctionResult PopupImage(void *pContext, CUIRect View, bool Active);
857 static CUi::EPopupMenuFunctionResult PopupSound(void *pContext, CUIRect View, bool Active);
858 static CUi::EPopupMenuFunctionResult PopupNewFolder(void *pContext, CUIRect View, bool Active);
859 static CUi::EPopupMenuFunctionResult PopupMapInfo(void *pContext, CUIRect View, bool Active);
860 static CUi::EPopupMenuFunctionResult PopupEvent(void *pContext, CUIRect View, bool Active);
861 static CUi::EPopupMenuFunctionResult PopupSelectImage(void *pContext, CUIRect View, bool Active);
862 static CUi::EPopupMenuFunctionResult PopupSelectSound(void *pContext, CUIRect View, bool Active);
863 static CUi::EPopupMenuFunctionResult PopupSelectGametileOp(void *pContext, CUIRect View, bool Active);
864 static CUi::EPopupMenuFunctionResult PopupSelectConfigAutoMap(void *pContext, CUIRect View, bool Active);
865 static CUi::EPopupMenuFunctionResult PopupTele(void *pContext, CUIRect View, bool Active);
866 static CUi::EPopupMenuFunctionResult PopupSpeedup(void *pContext, CUIRect View, bool Active);
867 static CUi::EPopupMenuFunctionResult PopupSwitch(void *pContext, CUIRect View, bool Active);
868 static CUi::EPopupMenuFunctionResult PopupTune(void *pContext, CUIRect View, bool Active);
869 static CUi::EPopupMenuFunctionResult PopupGoto(void *pContext, CUIRect View, bool Active);
870 static CUi::EPopupMenuFunctionResult PopupEntities(void *pContext, CUIRect View, bool Active);
871 static CUi::EPopupMenuFunctionResult PopupProofMode(void *pContext, CUIRect View, bool Active);
872 static CUi::EPopupMenuFunctionResult PopupAnimateSettings(void *pContext, CUIRect View, bool Active);
873
874 static bool CallbackOpenMap(const char *pFileName, int StorageType, void *pUser);
875 static bool CallbackAppendMap(const char *pFileName, int StorageType, void *pUser);
876 static bool CallbackSaveMap(const char *pFileName, int StorageType, void *pUser);
877 static bool CallbackSaveCopyMap(const char *pFileName, int StorageType, void *pUser);
878 static bool CallbackAddTileart(const char *pFilepath, int StorageType, void *pUser);
879 static bool CallbackSaveImage(const char *pFileName, int StorageType, void *pUser);
880 static bool CallbackSaveSound(const char *pFileName, int StorageType, void *pUser);
881
882 void PopupSelectImageInvoke(int Current, float x, float y);
883 int PopupSelectImageResult();
884
885 void PopupSelectGametileOpInvoke(float x, float y);
886 int PopupSelectGameTileOpResult();
887
888 void PopupSelectConfigAutoMapInvoke(int Current, float x, float y);
889 int PopupSelectConfigAutoMapResult();
890
891 void PopupSelectSoundInvoke(int Current, float x, float y);
892 int PopupSelectSoundResult();
893
894 void DoQuadEnvelopes(const std::vector<CQuad> &vQuads, IGraphics::CTextureHandle Texture = IGraphics::CTextureHandle());
895 void DoQuadEnvPoint(const CQuad *pQuad, int QIndex, int pIndex);
896 void DoQuadPoint(int LayerIndex, const std::shared_ptr<CLayerQuads> &pLayer, CQuad *pQuad, int QuadIndex, int v);
897 void SetHotQuadPoint(const std::shared_ptr<CLayerQuads> &pLayer);
898
899 float TriangleArea(vec2 A, vec2 B, vec2 C);
900 bool IsInTriangle(vec2 Point, vec2 A, vec2 B, vec2 C);
901 void DoQuadKnife(int QuadIndex);
902
903 void DoSoundSource(int LayerIndex, CSoundSource *pSource, int Index);
904
905 enum class EAxis
906 {
907 AXIS_NONE = 0,
908 AXIS_X,
909 AXIS_Y
910 };
911 struct SAxisAlignedBoundingBox
912 {
913 enum
914 {
915 POINT_TL = 0,
916 POINT_TR,
917 POINT_BL,
918 POINT_BR,
919 POINT_CENTER,
920 NUM_POINTS
921 };
922 CPoint m_aPoints[NUM_POINTS];
923 };
924 void DoMapEditor(CUIRect View);
925 void DoToolbarLayers(CUIRect Toolbar);
926 void DoToolbarSounds(CUIRect Toolbar);
927 void DoQuad(int LayerIndex, const std::shared_ptr<CLayerQuads> &pLayer, CQuad *pQuad, int Index);
928 void PreparePointDrag(const std::shared_ptr<CLayerQuads> &pLayer, CQuad *pQuad, int QuadIndex, int PointIndex);
929 void DoPointDrag(const std::shared_ptr<CLayerQuads> &pLayer, CQuad *pQuad, int QuadIndex, int PointIndex, int OffsetX, int OffsetY);
930 EAxis GetDragAxis(int OffsetX, int OffsetY) const;
931 void DrawAxis(EAxis Axis, CPoint &OriginalPoint, CPoint &Point) const;
932 void DrawAABB(const SAxisAlignedBoundingBox &AABB, int OffsetX = 0, int OffsetY = 0) const;
933 ColorRGBA GetButtonColor(const void *pId, int Checked);
934
935 // Alignment methods
936 // These methods take `OffsetX` and `OffsetY` because the calculations are made with the original positions
937 // of the quad(s), before we started dragging. This allows us to edit `OffsetX` and `OffsetY` based on the previously
938 // calculated alignments.
939 struct SAlignmentInfo
940 {
941 CPoint m_AlignedPoint; // The "aligned" point, which we want to align/snap to
942 union
943 {
944 // The current changing value when aligned to this point. When aligning to a point on the X axis, then the X value is changing because
945 // we aligned the Y values (X axis aligned => Y values are the same, Y axis aligned => X values are the same).
946 int m_X;
947 int m_Y;
948 };
949 EAxis m_Axis; // The axis we are aligning on
950 int m_PointIndex; // The point index we are aligning
951 int m_Diff; // Store the difference
952 };
953 void ComputePointAlignments(const std::shared_ptr<CLayerQuads> &pLayer, CQuad *pQuad, int QuadIndex, int PointIndex, int OffsetX, int OffsetY, std::vector<SAlignmentInfo> &vAlignments, bool Append = false) const;
954 void ComputePointsAlignments(const std::shared_ptr<CLayerQuads> &pLayer, bool Pivot, int OffsetX, int OffsetY, std::vector<SAlignmentInfo> &vAlignments) const;
955 void ComputeAABBAlignments(const std::shared_ptr<CLayerQuads> &pLayer, const SAxisAlignedBoundingBox &AABB, int OffsetX, int OffsetY, std::vector<SAlignmentInfo> &vAlignments) const;
956 void DrawPointAlignments(const std::vector<SAlignmentInfo> &vAlignments, int OffsetX, int OffsetY) const;
957 void QuadSelectionAABB(const std::shared_ptr<CLayerQuads> &pLayer, SAxisAlignedBoundingBox &OutAABB);
958 void ApplyAlignments(const std::vector<SAlignmentInfo> &vAlignments, int &OffsetX, int &OffsetY);
959 void ApplyAxisAlignment(int &OffsetX, int &OffsetY) const;
960
961 bool ReplaceImage(const char *pFilename, int StorageType, bool CheckDuplicate);
962 static bool ReplaceImageCallback(const char *pFilename, int StorageType, void *pUser);
963 bool ReplaceSound(const char *pFileName, int StorageType, bool CheckDuplicate);
964 static bool ReplaceSoundCallback(const char *pFileName, int StorageType, void *pUser);
965 static bool AddImage(const char *pFilename, int StorageType, void *pUser);
966 static bool AddSound(const char *pFileName, int StorageType, void *pUser);
967
968 bool IsEnvelopeUsed(int EnvelopeIndex) const;
969 void RemoveUnusedEnvelopes();
970
971 static bool IsVanillaImage(const char *pImage);
972
973 void RenderLayers(CUIRect LayersBox);
974 void RenderImagesList(CUIRect Toolbox);
975 void RenderSelectedImage(CUIRect View);
976 void RenderSounds(CUIRect Toolbox);
977 void RenderModebar(CUIRect View);
978 void RenderStatusbar(CUIRect View, CUIRect *pTooltipRect);
979 void RenderTooltip(CUIRect TooltipRect);
980
981 void RenderEnvelopeEditor(CUIRect View);
982
983 void RenderMapSettingsErrorDialog();
984 void RenderServerSettingsEditor(CUIRect View, bool ShowServerSettingsEditorLast);
985 static void MapSettingsDropdownRenderCallback(const SPossibleValueMatch &Match, char (&aOutput)[128], std::vector<STextColorSplit> &vColorSplits);
986
987 void RenderEditorHistory(CUIRect View);
988
989 enum class EDragSide // Which side is the drag bar on
990 {
991 SIDE_BOTTOM,
992 SIDE_LEFT,
993 SIDE_TOP,
994 SIDE_RIGHT
995 };
996 void DoEditorDragBar(CUIRect View, CUIRect *pDragBar, EDragSide Side, float *pValue, float MinValue = 100.0f, float MaxValue = 400.0f);
997
998 void SetHotEnvelopePoint(const CUIRect &View, const std::shared_ptr<CEnvelope> &pEnvelope, int ActiveChannels);
999
1000 void RenderMenubar(CUIRect Menubar);
1001 void RenderFileDialog();
1002
1003 void SelectGameLayer();
1004 std::vector<int> SortImages();
1005
1006 void DoAudioPreview(CUIRect View, const void *pPlayPauseButtonId, const void *pStopButtonId, const void *pSeekBarId, const int SampleId);
1007
1008 // Tile Numbers For Explanations - TODO: Add/Improve tiles and explanations
1009 enum
1010 {
1011 TILE_PUB_AIR,
1012 TILE_PUB_HOOKABLE,
1013 TILE_PUB_DEATH,
1014 TILE_PUB_UNHOOKABLE,
1015
1016 TILE_PUB_CREDITS1 = 140,
1017 TILE_PUB_CREDITS2,
1018 TILE_PUB_CREDITS3,
1019 TILE_PUB_CREDITS4,
1020 TILE_PUB_CREDITS5 = 156,
1021 TILE_PUB_CREDITS6,
1022 TILE_PUB_CREDITS7,
1023 TILE_PUB_CREDITS8,
1024
1025 TILE_PUB_ENTITIES_OFF1 = 190,
1026 TILE_PUB_ENTITIES_OFF2,
1027 };
1028
1029 enum
1030 {
1031 TILE_FNG_SPIKE_GOLD = 7,
1032 TILE_FNG_SPIKE_NORMAL,
1033 TILE_FNG_SPIKE_RED,
1034 TILE_FNG_SPIKE_BLUE,
1035 TILE_FNG_SCORE_RED,
1036 TILE_FNG_SCORE_BLUE,
1037
1038 TILE_FNG_SPIKE_GREEN = 14,
1039 TILE_FNG_SPIKE_PURPLE,
1040
1041 TILE_FNG_SPAWN = 192,
1042 TILE_FNG_SPAWN_RED,
1043 TILE_FNG_SPAWN_BLUE,
1044 TILE_FNG_FLAG_RED,
1045 TILE_FNG_FLAG_BLUE,
1046 TILE_FNG_SHIELD,
1047 TILE_FNG_HEART,
1048 TILE_FNG_SHOTGUN,
1049 TILE_FNG_GRENADE,
1050 TILE_FNG_NINJA,
1051 TILE_FNG_LASER,
1052
1053 TILE_FNG_SPIKE_OLD1 = 208,
1054 TILE_FNG_SPIKE_OLD2,
1055 TILE_FNG_SPIKE_OLD3
1056 };
1057
1058 enum
1059 {
1060 TILE_VANILLA_SPAWN = 192,
1061 TILE_VANILLA_SPAWN_RED,
1062 TILE_VANILLA_SPAWN_BLUE,
1063 TILE_VANILLA_FLAG_RED,
1064 TILE_VANILLA_FLAG_BLUE,
1065 TILE_VANILLA_SHIELD,
1066 TILE_VANILLA_HEART,
1067 TILE_VANILLA_SHOTGUN,
1068 TILE_VANILLA_GRENADE,
1069 TILE_VANILLA_NINJA,
1070 TILE_VANILLA_LASER,
1071 };
1072
1073 // Explanations
1074 enum class EExplanation
1075 {
1076 NONE,
1077 DDNET,
1078 FNG,
1079 RACE,
1080 VANILLA,
1081 BLOCKWORLDS
1082 };
1083 static const char *ExplainDDNet(int Tile, int Layer);
1084 static const char *ExplainFNG(int Tile, int Layer);
1085 static const char *ExplainVanilla(int Tile, int Layer);
1086 static const char *Explain(EExplanation Explanation, int Tile, int Layer);
1087
1088 // Zooming
1089 void ZoomAdaptOffsetX(float ZoomFactor, const CUIRect &View);
1090 void UpdateZoomEnvelopeX(const CUIRect &View);
1091
1092 void ZoomAdaptOffsetY(float ZoomFactor, const CUIRect &View);
1093 void UpdateZoomEnvelopeY(const CUIRect &View);
1094
1095 void ResetZoomEnvelope(const std::shared_ptr<CEnvelope> &pEnvelope, int ActiveChannels);
1096 void RemoveTimeOffsetEnvelope(const std::shared_ptr<CEnvelope> &pEnvelope);
1097 float ScreenToEnvelopeX(const CUIRect &View, float x) const;
1098 float EnvelopeToScreenX(const CUIRect &View, float x) const;
1099 float ScreenToEnvelopeY(const CUIRect &View, float y) const;
1100 float EnvelopeToScreenY(const CUIRect &View, float y) const;
1101 float ScreenToEnvelopeDX(const CUIRect &View, float dx);
1102 float ScreenToEnvelopeDY(const CUIRect &View, float dy);
1103
1104 // DDRace
1105
1106 IGraphics::CTextureHandle GetFrontTexture();
1107 IGraphics::CTextureHandle GetTeleTexture();
1108 IGraphics::CTextureHandle GetSpeedupTexture();
1109 IGraphics::CTextureHandle GetSwitchTexture();
1110 IGraphics::CTextureHandle GetTuneTexture();
1111
1112 unsigned char m_TeleNumber;
1113 unsigned char m_TeleCheckpointNumber;
1114 unsigned char m_ViewTeleNumber;
1115
1116 unsigned char m_TuningNum;
1117
1118 unsigned char m_SpeedupForce;
1119 unsigned char m_SpeedupMaxSpeed;
1120 short m_SpeedupAngle;
1121
1122 unsigned char m_SwitchNum;
1123 unsigned char m_SwitchDelay;
1124 unsigned char m_ViewSwitch;
1125
1126 void AdjustBrushSpecialTiles(bool UseNextFree, int Adjust = 0);
1127 int FindNextFreeSwitchNumber();
1128 int FindNextFreeTeleNumber(bool IsCheckpoint = false);
1129
1130public:
1131 // Undo/Redo
1132 CEditorHistory m_EditorHistory;
1133 CEditorHistory m_ServerSettingsHistory;
1134 CEditorHistory m_EnvelopeEditorHistory;
1135 CQuadEditTracker m_QuadTracker;
1136 CEnvelopeEditorOperationTracker m_EnvOpTracker;
1137
1138private:
1139 void UndoLastAction();
1140 void RedoLastAction();
1141
1142private:
1143 std::map<int, CPoint[5]> m_QuadDragOriginalPoints;
1144};
1145
1146// make sure to inline this function
1147inline class IGraphics *CLayer::Graphics() { return m_pEditor->Graphics(); }
1148inline class ITextRender *CLayer::TextRender() { return m_pEditor->TextRender(); }
1149
1150#endif
1151