1#include "map_renderer.h"
2
3#include <base/dbg.h>
4#include <base/log.h>
5
6#include <engine/graphics.h>
7
8#include <game/map/envelope_manager.h>
9
10const int LAYER_DEFAULT_TILESET = -1;
11
12void CMapRenderer::Clear()
13{
14 for(auto &pLayer : m_vpRenderLayers)
15 pLayer->Unload();
16 m_vpRenderLayers.clear();
17}
18
19void CMapRenderer::Load(ERenderType Type, CLayers *pLayers, IMapImages *pMapImages, const IEnvelopeEval *pEnvelopeEval, std::optional<FRenderUploadCallback> RenderCallbackOptional)
20{
21 Clear();
22
23 std::shared_ptr<CEnvelopeManager> pEnvelopeManager = std::make_shared<CEnvelopeManager>(args&: pEnvelopeEval, args: pLayers->Map());
24 bool PassedGameLayer = false;
25
26 for(int GroupId = 0; GroupId < pLayers->NumGroups(); GroupId++)
27 {
28 CMapItemGroup *pGroup = pLayers->GetGroup(Index: GroupId);
29 std::unique_ptr<CRenderLayer> pRenderLayerGroup = std::make_unique<CRenderLayerGroup>(args&: GroupId, args&: pGroup);
30 pRenderLayerGroup->OnInit(pGraphics: Graphics(), pTextRender: TextRender(), pRenderMap: RenderMap(), pEnvelopeManager, pMap: pLayers->Map(), pMapImages, FRenderUploadCallbackOptional&: RenderCallbackOptional);
31 if(!pRenderLayerGroup->IsValid())
32 {
33 log_error("map_renderer", "error group was null, group number = %d, total groups = %d", GroupId, pLayers->NumGroups());
34 log_error("map_renderer", "this is here to prevent a crash but the source of this is unknown, please report this for it to get fixed");
35 log_error("map_renderer", "we need mapname and crc and the map that caused this if possible, and anymore info you think is relevant");
36 continue;
37 }
38
39 for(int LayerId = 0; LayerId < pGroup->m_NumLayers; LayerId++)
40 {
41 CMapItemLayer *pLayer = pLayers->GetLayer(Index: pGroup->m_StartLayer + LayerId);
42 int LayerType = GetLayerType(pLayer);
43 PassedGameLayer |= LayerType == LAYER_GAME;
44
45 if(Type == ERenderType::RENDERTYPE_BACKGROUND_FORCE || Type == ERenderType::RENDERTYPE_BACKGROUND)
46 {
47 if(PassedGameLayer)
48 return;
49 }
50 else if(Type == ERenderType::RENDERTYPE_FOREGROUND)
51 {
52 if(!PassedGameLayer)
53 continue;
54 }
55
56 if(pRenderLayerGroup)
57 m_vpRenderLayers.push_back(x: std::move(pRenderLayerGroup));
58
59 std::unique_ptr<CRenderLayer> pRenderLayer;
60
61 if(pLayer->m_Type == LAYERTYPE_TILES)
62 {
63 CMapItemLayerTilemap *pTileLayer = (CMapItemLayerTilemap *)pLayer;
64
65 switch(LayerType)
66 {
67 case LAYER_DEFAULT_TILESET:
68 pRenderLayer = std::make_unique<CRenderLayerTile>(
69 args&: GroupId,
70 args&: LayerId,
71 args&: pLayer->m_Flags,
72 args&: pTileLayer);
73 break;
74 case LAYER_GAME:
75 pRenderLayer = std::make_unique<CRenderLayerEntityGame>(
76 args&: GroupId,
77 args&: LayerId,
78 args&: pLayer->m_Flags,
79 args&: pTileLayer);
80 break;
81 case LAYER_FRONT:
82 pRenderLayer = std::make_unique<CRenderLayerEntityFront>(
83 args&: GroupId,
84 args&: LayerId,
85 args&: pLayer->m_Flags,
86 args&: pTileLayer);
87 break;
88 case LAYER_TELE:
89 pRenderLayer = std::make_unique<CRenderLayerEntityTele>(
90 args&: GroupId,
91 args&: LayerId,
92 args&: pLayer->m_Flags,
93 args&: pTileLayer);
94 break;
95 case LAYER_SPEEDUP:
96 pRenderLayer = std::make_unique<CRenderLayerEntitySpeedup>(
97 args&: GroupId,
98 args&: LayerId,
99 args&: pLayer->m_Flags,
100 args&: pTileLayer);
101 break;
102 case LAYER_SWITCH:
103 pRenderLayer = std::make_unique<CRenderLayerEntitySwitch>(
104 args&: GroupId,
105 args&: LayerId,
106 args&: pLayer->m_Flags,
107 args&: pTileLayer);
108 break;
109 case LAYER_TUNE:
110 pRenderLayer = std::make_unique<CRenderLayerEntityTune>(
111 args&: GroupId,
112 args&: LayerId,
113 args&: pLayer->m_Flags,
114 args&: pTileLayer);
115 break;
116 default:
117 dbg_assert_failed("Unknown LayerType %d", LayerType);
118 }
119 }
120 else if(pLayer->m_Type == LAYERTYPE_QUADS)
121 {
122 CMapItemLayerQuads *pQLayer = (CMapItemLayerQuads *)pLayer;
123
124 pRenderLayer = std::make_unique<CRenderLayerQuads>(
125 args&: GroupId,
126 args&: LayerId,
127 args&: pLayer->m_Flags,
128 args&: pQLayer);
129 }
130
131 // just ignore invalid layers from rendering
132 if(pRenderLayer)
133 {
134 pRenderLayer->OnInit(pGraphics: Graphics(), pTextRender: TextRender(), pRenderMap: RenderMap(), pEnvelopeManager, pMap: pLayers->Map(), pMapImages, FRenderUploadCallbackOptional&: RenderCallbackOptional);
135 if(pRenderLayer->IsValid())
136 {
137 pRenderLayer->Init();
138 m_vpRenderLayers.push_back(x: std::move(pRenderLayer));
139 }
140 }
141 }
142 }
143}
144
145void CMapRenderer::Render(const CRenderLayerParams &Params)
146{
147 CScreenRect ScreenRect = Graphics()->GetScreen();
148
149 bool DoRenderGroup = true;
150 for(auto &pRenderLayer : m_vpRenderLayers)
151 {
152 if(pRenderLayer->IsGroup())
153 DoRenderGroup = pRenderLayer->DoRender(Params);
154
155 if(!DoRenderGroup)
156 continue;
157
158 if(pRenderLayer->DoRender(Params))
159 pRenderLayer->Render(Params);
160 }
161
162 // Reset clip from last group
163 Graphics()->ClipDisable();
164
165 // don't reset screen on background
166 if(Params.m_RenderType != ERenderType::RENDERTYPE_BACKGROUND && Params.m_RenderType != ERenderType::RENDERTYPE_BACKGROUND_FORCE)
167 {
168 // reset the screen like it was before
169 Graphics()->MapScreen(ScreenRect);
170 }
171 else
172 {
173 // reset the screen to the default interface
174 Graphics()->MapScreenToInterface(CenterX: Params.m_Center.x, CenterY: Params.m_Center.y, Zoom: Params.m_Zoom);
175 }
176}
177
178int CMapRenderer::GetLayerType(const CMapItemLayer *pLayer) const
179{
180 if(pLayer->m_Type != LAYERTYPE_TILES)
181 return LAYER_DEFAULT_TILESET;
182
183 // Physics layers must be determined by their flags instead of by comparing them with the
184 // layers of CLayers, which only knows the last physics layer of each type, as design tiles
185 // layers use the data index which is neither used nor validated for physics layers.
186 const int Flags = reinterpret_cast<const CMapItemLayerTilemap *>(pLayer)->m_Flags;
187 if(Flags & TILESLAYERFLAG_GAME)
188 return LAYER_GAME;
189 else if(Flags & TILESLAYERFLAG_FRONT)
190 return LAYER_FRONT;
191 else if(Flags & TILESLAYERFLAG_SWITCH)
192 return LAYER_SWITCH;
193 else if(Flags & TILESLAYERFLAG_TELE)
194 return LAYER_TELE;
195 else if(Flags & TILESLAYERFLAG_SPEEDUP)
196 return LAYER_SPEEDUP;
197 else if(Flags & TILESLAYERFLAG_TUNE)
198 return LAYER_TUNE;
199 return LAYER_DEFAULT_TILESET;
200}
201