1#include "layer_group.h"
2
3#include <engine/graphics.h>
4#include <engine/shared/config.h>
5
6#include <game/editor/editor.h>
7
8#include <algorithm>
9
10CLayerGroup::CLayerGroup(CEditorMap *pMap) :
11 CMapObject(pMap)
12{
13 m_vpLayers.clear();
14 m_aName[0] = 0;
15 m_Visible = true;
16 m_Collapse = false;
17 m_GameGroup = false;
18 m_OffsetX = 0;
19 m_OffsetY = 0;
20 m_ParallaxX = 100;
21 m_ParallaxY = 100;
22
23 m_UseClipping = 0;
24 m_ClipX = 0;
25 m_ClipY = 0;
26 m_ClipW = 0;
27 m_ClipH = 0;
28}
29
30void CLayerGroup::OnAttach(CEditorMap *pMap)
31{
32 CMapObject::OnAttach(pMap);
33 for(const auto &pLayer : m_vpLayers)
34 {
35 pLayer->OnAttach(pMap);
36 }
37}
38
39void CLayerGroup::Convert(CUIRect *pRect) const
40{
41 pRect->x += m_OffsetX;
42 pRect->y += m_OffsetY;
43}
44
45CScreenRect CLayerGroup::Mapping() const
46{
47 float NormalParallaxZoom = std::clamp(val: (float)std::max(a: m_ParallaxX, b: m_ParallaxY), lo: 0.0f, hi: 100.0f);
48 float ParallaxZoom = Map()->m_PreviewZoom ? NormalParallaxZoom : 100.0f;
49
50 CScreenRect ScreenRect = Graphics()->MapScreenToWorld(
51 CenterX: Editor()->MapView()->GetWorldOffset().x, CenterY: Editor()->MapView()->GetWorldOffset().y,
52 ParallaxX: m_ParallaxX, ParallaxY: m_ParallaxY, ParallaxZoom, OffsetX: m_OffsetX, OffsetY: m_OffsetY,
53 Aspect: Graphics()->ScreenAspect(), Zoom: Editor()->MapView()->GetWorldZoom());
54
55 ScreenRect = ScreenRect.Move(Position: Editor()->MapView()->GetEditorOffset());
56 return ScreenRect;
57}
58
59void CLayerGroup::MapScreen()
60{
61 CScreenRect ScreenRect = Mapping();
62 Graphics()->MapScreen(ScreenRect);
63}
64
65void CLayerGroup::Render(const CEditorMap *pRenderMap)
66{
67 MapScreen();
68
69 if(m_UseClipping)
70 {
71 CScreenRect ScreenRect = Map()->m_pGameGroup->Mapping();
72 float ScreenWidth = ScreenRect.Width();
73 float ScreenHeight = ScreenRect.Height();
74 float Left = m_ClipX - ScreenRect.m_TopLeft.x;
75 float Top = m_ClipY - ScreenRect.m_TopLeft.y;
76 float Right = (m_ClipX + m_ClipW) - ScreenRect.m_TopLeft.x;
77 float Bottom = (m_ClipY + m_ClipH) - ScreenRect.m_TopLeft.y;
78
79 int ClipX = (int)std::round(x: Left * Graphics()->ScreenWidth() / ScreenWidth);
80 int ClipY = (int)std::round(x: Top * Graphics()->ScreenHeight() / ScreenHeight);
81
82 Graphics()->ClipEnable(
83 x: ClipX,
84 y: ClipY,
85 w: (int)std::round(x: Right * Graphics()->ScreenWidth() / ScreenWidth) - ClipX,
86 h: (int)std::round(x: Bottom * Graphics()->ScreenHeight() / ScreenHeight) - ClipY);
87 }
88
89 for(auto &pLayer : m_vpLayers)
90 {
91 if(pLayer->m_Visible)
92 {
93 if(pLayer->m_Type == LAYERTYPE_TILES)
94 {
95 std::shared_ptr<CLayerTiles> pTiles = std::static_pointer_cast<CLayerTiles>(r: pLayer);
96
97 if(g_Config.m_EdShowIngameEntities &&
98 (pLayer == Map()->m_pGameLayer || pLayer == Map()->m_pFrontLayer || pLayer == Map()->m_pSwitchLayer))
99 {
100 Editor()->RenderIngameEntities(Group: *this, TilesLayer: *pTiles);
101 }
102
103 if(pTiles->m_HasGame || pTiles->m_HasFront || pTiles->m_HasTele || pTiles->m_HasSpeedup || pTiles->m_HasTune || pTiles->m_HasSwitch)
104 continue;
105 }
106 if(pRenderMap->m_ShowDetail || !(pLayer->m_Flags & LAYERFLAG_DETAIL))
107 pLayer->Render(pRenderMap);
108 }
109 }
110
111 for(auto &pLayer : m_vpLayers)
112 {
113 if(pLayer->m_Visible && pLayer->m_Type == LAYERTYPE_TILES && !pLayer->IsEntitiesLayer())
114 {
115 std::shared_ptr<CLayerTiles> pTiles = std::static_pointer_cast<CLayerTiles>(r: pLayer);
116 if(pTiles->m_HasGame || pTiles->m_HasFront || pTiles->m_HasTele || pTiles->m_HasSpeedup || pTiles->m_HasTune || pTiles->m_HasSwitch)
117 {
118 pLayer->Render(pRenderMap);
119 }
120 }
121 }
122
123 if(m_UseClipping)
124 Graphics()->ClipDisable();
125}
126
127void CLayerGroup::AddLayer(const std::shared_ptr<CLayer> &pLayer)
128{
129 Map()->OnModify();
130 m_vpLayers.push_back(x: pLayer);
131}
132
133void CLayerGroup::DeleteLayer(int Index)
134{
135 if(Index < 0 || Index >= (int)m_vpLayers.size())
136 return;
137 m_vpLayers.erase(position: m_vpLayers.begin() + Index);
138 Map()->OnModify();
139}
140
141void CLayerGroup::DuplicateLayer(int Index)
142{
143 if(Index < 0 || Index >= (int)m_vpLayers.size())
144 return;
145
146 std::shared_ptr<CLayer> pDup = m_vpLayers[Index]->Duplicate();
147 m_vpLayers.insert(position: m_vpLayers.begin() + Index + 1, x: pDup);
148
149 Map()->OnModify();
150}
151
152void CLayerGroup::GetSize(float *pWidth, float *pHeight) const
153{
154 *pWidth = 0.0f;
155 *pHeight = 0.0f;
156 for(const auto &pLayer : m_vpLayers)
157 {
158 float LayerWidth, LayerHeight;
159 pLayer->GetSize(pWidth: &LayerWidth, pHeight: &LayerHeight);
160 *pWidth = std::max(a: *pWidth, b: LayerWidth);
161 *pHeight = std::max(a: *pHeight, b: LayerHeight);
162 }
163}
164
165int CLayerGroup::MoveLayer(int IndexFrom, int IndexTo)
166{
167 if(IndexFrom < 0 || IndexFrom >= (int)m_vpLayers.size())
168 return IndexFrom;
169 if(IndexTo < 0 || IndexTo >= (int)m_vpLayers.size())
170 return IndexFrom;
171 if(IndexFrom == IndexTo)
172 return IndexFrom;
173 Map()->OnModify();
174 auto pMovedLayer = m_vpLayers[IndexFrom];
175 m_vpLayers.erase(position: m_vpLayers.begin() + IndexFrom);
176 m_vpLayers.insert(position: m_vpLayers.begin() + IndexTo, x: pMovedLayer);
177 return IndexTo;
178}
179
180bool CLayerGroup::IsEmpty() const
181{
182 return m_vpLayers.empty();
183}
184
185void CLayerGroup::Clear()
186{
187 m_vpLayers.clear();
188}
189
190void CLayerGroup::ModifyImageIndex(const FIndexModifyFunction &IndexModifyFunction)
191{
192 for(auto &pLayer : m_vpLayers)
193 {
194 pLayer->ModifyImageIndex(IndexModifyFunction);
195 }
196}
197
198void CLayerGroup::ModifyEnvelopeIndex(const FIndexModifyFunction &IndexModifyFunction)
199{
200 for(auto &pLayer : m_vpLayers)
201 {
202 pLayer->ModifyEnvelopeIndex(IndexModifyFunction);
203 }
204}
205
206void CLayerGroup::ModifySoundIndex(const FIndexModifyFunction &IndexModifyFunction)
207{
208 for(auto &pLayer : m_vpLayers)
209 {
210 pLayer->ModifySoundIndex(IndexModifyFunction);
211 }
212}
213