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