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 | #include <engine/demo.h> |
4 | #include <engine/graphics.h> |
5 | #include <engine/keys.h> |
6 | #include <engine/serverbrowser.h> |
7 | #include <engine/shared/config.h> |
8 | #include <engine/storage.h> |
9 | |
10 | #include <game/client/gameclient.h> |
11 | #include <game/client/render.h> |
12 | |
13 | #include <game/layers.h> |
14 | #include <game/mapitems.h> |
15 | #include <game/mapitems_ex.h> |
16 | |
17 | #include <game/client/components/camera.h> |
18 | #include <game/client/components/mapimages.h> |
19 | #include <game/localization.h> |
20 | |
21 | #include "maplayers.h" |
22 | |
23 | #include <chrono> |
24 | |
25 | using namespace std::chrono_literals; |
26 | |
27 | CMapLayers::CMapLayers(int t, bool OnlineOnly) |
28 | { |
29 | m_Type = t; |
30 | m_pLayers = 0; |
31 | m_CurrentLocalTick = 0; |
32 | m_LastLocalTick = 0; |
33 | m_EnvelopeUpdate = false; |
34 | m_OnlineOnly = OnlineOnly; |
35 | } |
36 | |
37 | void CMapLayers::OnInit() |
38 | { |
39 | m_pLayers = Layers(); |
40 | m_pImages = &m_pClient->m_MapImages; |
41 | } |
42 | |
43 | CCamera *CMapLayers::GetCurCamera() |
44 | { |
45 | return &m_pClient->m_Camera; |
46 | } |
47 | |
48 | void CMapLayers::EnvelopeUpdate() |
49 | { |
50 | if(Client()->State() == IClient::STATE_DEMOPLAYBACK) |
51 | { |
52 | const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); |
53 | m_CurrentLocalTick = pInfo->m_CurrentTick; |
54 | m_LastLocalTick = pInfo->m_CurrentTick; |
55 | m_EnvelopeUpdate = true; |
56 | } |
57 | } |
58 | |
59 | void CMapLayers::EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Result, size_t Channels, void *pUser) |
60 | { |
61 | CMapLayers *pThis = (CMapLayers *)pUser; |
62 | |
63 | int EnvStart, EnvNum; |
64 | pThis->m_pLayers->Map()->GetType(Type: MAPITEMTYPE_ENVELOPE, pStart: &EnvStart, pNum: &EnvNum); |
65 | if(Env < 0 || Env >= EnvNum) |
66 | return; |
67 | |
68 | const CMapItemEnvelope *pItem = (CMapItemEnvelope *)pThis->m_pLayers->Map()->GetItem(Index: EnvStart + Env); |
69 | if(pItem->m_Channels <= 0) |
70 | return; |
71 | Channels = minimum<size_t>(a: Channels, b: pItem->m_Channels, c: CEnvPoint::MAX_CHANNELS); |
72 | |
73 | CMapBasedEnvelopePointAccess EnvelopePoints(pThis->m_pLayers->Map()); |
74 | EnvelopePoints.SetPointsRange(StartPoint: pItem->m_StartPoint, NumPoints: pItem->m_NumPoints); |
75 | if(EnvelopePoints.NumPoints() == 0) |
76 | return; |
77 | |
78 | const auto TickToNanoSeconds = std::chrono::nanoseconds(1s) / (int64_t)pThis->Client()->GameTickSpeed(); |
79 | |
80 | static std::chrono::nanoseconds s_Time{0}; |
81 | static auto s_LastLocalTime = time_get_nanoseconds(); |
82 | if(pThis->Client()->State() == IClient::STATE_DEMOPLAYBACK) |
83 | { |
84 | const IDemoPlayer::CInfo *pInfo = pThis->DemoPlayer()->BaseInfo(); |
85 | |
86 | if(!pInfo->m_Paused || pThis->m_EnvelopeUpdate) |
87 | { |
88 | if(pThis->m_CurrentLocalTick != pInfo->m_CurrentTick) |
89 | { |
90 | pThis->m_LastLocalTick = pThis->m_CurrentLocalTick; |
91 | pThis->m_CurrentLocalTick = pInfo->m_CurrentTick; |
92 | } |
93 | if(pItem->m_Version < 2 || pItem->m_Synchronized) |
94 | { |
95 | if(pThis->m_pClient->m_Snap.m_pGameInfoObj) |
96 | { |
97 | // get the lerp of the current tick and prev |
98 | int MinTick = pThis->Client()->PrevGameTick(Conn: g_Config.m_ClDummy) - pThis->m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick; |
99 | int CurTick = pThis->Client()->GameTick(Conn: g_Config.m_ClDummy) - pThis->m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick; |
100 | s_Time = std::chrono::nanoseconds((int64_t)(mix<double>( |
101 | a: 0, |
102 | b: (CurTick - MinTick), |
103 | amount: (double)pThis->Client()->IntraGameTick(Conn: g_Config.m_ClDummy)) * |
104 | TickToNanoSeconds.count())) + |
105 | MinTick * TickToNanoSeconds; |
106 | } |
107 | } |
108 | else |
109 | { |
110 | int MinTick = pThis->m_LastLocalTick; |
111 | s_Time = std::chrono::nanoseconds((int64_t)(mix<double>(a: 0, |
112 | b: pThis->m_CurrentLocalTick - MinTick, |
113 | amount: (double)pThis->Client()->IntraGameTick(Conn: g_Config.m_ClDummy)) * |
114 | TickToNanoSeconds.count())) + |
115 | MinTick * TickToNanoSeconds; |
116 | } |
117 | } |
118 | CRenderTools::RenderEvalEnvelope(pPoints: &EnvelopePoints, TimeNanos: s_Time + (int64_t)TimeOffsetMillis * std::chrono::nanoseconds(1ms), Result, Channels); |
119 | } |
120 | else |
121 | { |
122 | if(pThis->m_OnlineOnly && (pItem->m_Version < 2 || pItem->m_Synchronized)) |
123 | { |
124 | if(pThis->m_pClient->m_Snap.m_pGameInfoObj) // && !(pThis->m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED)) |
125 | { |
126 | // get the lerp of the current tick and prev |
127 | int MinTick = pThis->Client()->PrevGameTick(Conn: g_Config.m_ClDummy) - pThis->m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick; |
128 | int CurTick = pThis->Client()->GameTick(Conn: g_Config.m_ClDummy) - pThis->m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick; |
129 | s_Time = std::chrono::nanoseconds((int64_t)(mix<double>( |
130 | a: 0, |
131 | b: (CurTick - MinTick), |
132 | amount: (double)pThis->Client()->IntraGameTick(Conn: g_Config.m_ClDummy)) * |
133 | TickToNanoSeconds.count())) + |
134 | MinTick * TickToNanoSeconds; |
135 | } |
136 | } |
137 | else |
138 | { |
139 | auto CurTime = time_get_nanoseconds(); |
140 | s_Time += CurTime - s_LastLocalTime; |
141 | s_LastLocalTime = CurTime; |
142 | } |
143 | CRenderTools::RenderEvalEnvelope(pPoints: &EnvelopePoints, TimeNanos: s_Time + std::chrono::nanoseconds(std::chrono::milliseconds(TimeOffsetMillis)), Result, Channels); |
144 | } |
145 | } |
146 | |
147 | void FillTmpTile(SGraphicTile *pTmpTile, SGraphicTileTexureCoords *pTmpTex, unsigned char Flags, unsigned char Index, int x, int y, const ivec2 &Offset, int Scale, CMapItemGroup *pGroup) |
148 | { |
149 | if(pTmpTex) |
150 | { |
151 | unsigned char x0 = 0; |
152 | unsigned char y0 = 0; |
153 | unsigned char x1 = x0 + 1; |
154 | unsigned char y1 = y0; |
155 | unsigned char x2 = x0 + 1; |
156 | unsigned char y2 = y0 + 1; |
157 | unsigned char x3 = x0; |
158 | unsigned char y3 = y0 + 1; |
159 | |
160 | if(Flags & TILEFLAG_XFLIP) |
161 | { |
162 | x0 = x2; |
163 | x1 = x3; |
164 | x2 = x3; |
165 | x3 = x0; |
166 | } |
167 | |
168 | if(Flags & TILEFLAG_YFLIP) |
169 | { |
170 | y0 = y3; |
171 | y2 = y1; |
172 | y3 = y1; |
173 | y1 = y0; |
174 | } |
175 | |
176 | if(Flags & TILEFLAG_ROTATE) |
177 | { |
178 | unsigned char Tmp = x0; |
179 | x0 = x3; |
180 | x3 = x2; |
181 | x2 = x1; |
182 | x1 = Tmp; |
183 | Tmp = y0; |
184 | y0 = y3; |
185 | y3 = y2; |
186 | y2 = y1; |
187 | y1 = Tmp; |
188 | } |
189 | |
190 | pTmpTex->m_TexCoordTopLeft.x = x0; |
191 | pTmpTex->m_TexCoordTopLeft.y = y0; |
192 | pTmpTex->m_TexCoordBottomLeft.x = x3; |
193 | pTmpTex->m_TexCoordBottomLeft.y = y3; |
194 | pTmpTex->m_TexCoordTopRight.x = x1; |
195 | pTmpTex->m_TexCoordTopRight.y = y1; |
196 | pTmpTex->m_TexCoordBottomRight.x = x2; |
197 | pTmpTex->m_TexCoordBottomRight.y = y2; |
198 | |
199 | pTmpTex->m_TexCoordTopLeft.z = Index; |
200 | pTmpTex->m_TexCoordBottomLeft.z = Index; |
201 | pTmpTex->m_TexCoordTopRight.z = Index; |
202 | pTmpTex->m_TexCoordBottomRight.z = Index; |
203 | |
204 | bool HasRotation = (Flags & TILEFLAG_ROTATE) != 0; |
205 | pTmpTex->m_TexCoordTopLeft.w = HasRotation; |
206 | pTmpTex->m_TexCoordBottomLeft.w = HasRotation; |
207 | pTmpTex->m_TexCoordTopRight.w = HasRotation; |
208 | pTmpTex->m_TexCoordBottomRight.w = HasRotation; |
209 | } |
210 | |
211 | pTmpTile->m_TopLeft.x = x * Scale + Offset.x; |
212 | pTmpTile->m_TopLeft.y = y * Scale + Offset.y; |
213 | pTmpTile->m_BottomLeft.x = x * Scale + Offset.x; |
214 | pTmpTile->m_BottomLeft.y = y * Scale + Scale + Offset.y; |
215 | pTmpTile->m_TopRight.x = x * Scale + Scale + Offset.x; |
216 | pTmpTile->m_TopRight.y = y * Scale + Offset.y; |
217 | pTmpTile->m_BottomRight.x = x * Scale + Scale + Offset.x; |
218 | pTmpTile->m_BottomRight.y = y * Scale + Scale + Offset.y; |
219 | } |
220 | |
221 | void FillTmpTileSpeedup(SGraphicTile *pTmpTile, SGraphicTileTexureCoords *pTmpTex, unsigned char Flags, unsigned char Index, int x, int y, const ivec2 &Offset, int Scale, CMapItemGroup *pGroup, short AngleRotate) |
222 | { |
223 | int Angle = AngleRotate % 360; |
224 | FillTmpTile(pTmpTile, pTmpTex, Flags: Angle >= 270 ? ROTATION_270 : (Angle >= 180 ? ROTATION_180 : (Angle >= 90 ? ROTATION_90 : 0)), Index: AngleRotate % 90, x, y, Offset, Scale, pGroup); |
225 | } |
226 | |
227 | bool CMapLayers::STileLayerVisuals::Init(unsigned int Width, unsigned int Height) |
228 | { |
229 | m_Width = Width; |
230 | m_Height = Height; |
231 | if(Width == 0 || Height == 0) |
232 | return false; |
233 | if constexpr(sizeof(unsigned int) >= sizeof(ptrdiff_t)) |
234 | if(Width >= std::numeric_limits<std::ptrdiff_t>::max() || Height >= std::numeric_limits<std::ptrdiff_t>::max()) |
235 | return false; |
236 | |
237 | m_pTilesOfLayer = new CMapLayers::STileLayerVisuals::STileVisual[Height * Width]; |
238 | |
239 | m_vBorderTop.resize(new_size: Width); |
240 | m_vBorderBottom.resize(new_size: Width); |
241 | |
242 | m_vBorderLeft.resize(new_size: Height); |
243 | m_vBorderRight.resize(new_size: Height); |
244 | return true; |
245 | } |
246 | |
247 | CMapLayers::STileLayerVisuals::~STileLayerVisuals() |
248 | { |
249 | delete[] m_pTilesOfLayer; |
250 | |
251 | m_pTilesOfLayer = NULL; |
252 | } |
253 | |
254 | bool AddTile(std::vector<SGraphicTile> &vTmpTiles, std::vector<SGraphicTileTexureCoords> &vTmpTileTexCoords, unsigned char Index, unsigned char Flags, int x, int y, CMapItemGroup *pGroup, bool DoTextureCoords, bool FillSpeedup = false, int AngleRotate = -1, const ivec2 &Offset = ivec2{0, 0}, int Scale = 32) |
255 | { |
256 | if(Index) |
257 | { |
258 | vTmpTiles.emplace_back(); |
259 | SGraphicTile &Tile = vTmpTiles.back(); |
260 | SGraphicTileTexureCoords *pTileTex = NULL; |
261 | if(DoTextureCoords) |
262 | { |
263 | vTmpTileTexCoords.emplace_back(); |
264 | SGraphicTileTexureCoords &TileTex = vTmpTileTexCoords.back(); |
265 | pTileTex = &TileTex; |
266 | } |
267 | if(FillSpeedup) |
268 | FillTmpTileSpeedup(pTmpTile: &Tile, pTmpTex: pTileTex, Flags, Index: 0, x, y, Offset, Scale, pGroup, AngleRotate); |
269 | else |
270 | FillTmpTile(pTmpTile: &Tile, pTmpTex: pTileTex, Flags, Index, x, y, Offset, Scale, pGroup); |
271 | |
272 | return true; |
273 | } |
274 | return false; |
275 | } |
276 | |
277 | struct STmpQuadVertexTextured |
278 | { |
279 | float m_X, m_Y, m_CenterX, m_CenterY; |
280 | unsigned char m_R, m_G, m_B, m_A; |
281 | float m_U, m_V; |
282 | }; |
283 | |
284 | struct STmpQuadVertex |
285 | { |
286 | float m_X, m_Y, m_CenterX, m_CenterY; |
287 | unsigned char m_R, m_G, m_B, m_A; |
288 | }; |
289 | |
290 | struct STmpQuad |
291 | { |
292 | STmpQuadVertex m_aVertices[4]; |
293 | }; |
294 | |
295 | struct STmpQuadTextured |
296 | { |
297 | STmpQuadVertexTextured m_aVertices[4]; |
298 | }; |
299 | |
300 | void mem_copy_special(void *pDest, void *pSource, size_t Size, size_t Count, size_t Steps) |
301 | { |
302 | size_t CurStep = 0; |
303 | for(size_t i = 0; i < Count; ++i) |
304 | { |
305 | mem_copy(dest: ((char *)pDest) + CurStep + i * Size, source: ((char *)pSource) + i * Size, size: Size); |
306 | CurStep += Steps; |
307 | } |
308 | } |
309 | |
310 | CMapLayers::~CMapLayers() |
311 | { |
312 | //clear everything and destroy all buffers |
313 | if(!m_vpTileLayerVisuals.empty()) |
314 | { |
315 | int s = m_vpTileLayerVisuals.size(); |
316 | for(int i = 0; i < s; ++i) |
317 | { |
318 | delete m_vpTileLayerVisuals[i]; |
319 | } |
320 | } |
321 | if(!m_vpQuadLayerVisuals.empty()) |
322 | { |
323 | int s = m_vpQuadLayerVisuals.size(); |
324 | for(int i = 0; i < s; ++i) |
325 | { |
326 | delete m_vpQuadLayerVisuals[i]; |
327 | } |
328 | } |
329 | } |
330 | |
331 | void CMapLayers::OnMapLoad() |
332 | { |
333 | if(!Graphics()->IsTileBufferingEnabled() && !Graphics()->IsQuadBufferingEnabled()) |
334 | return; |
335 | |
336 | const char *pConnectCaption = GameClient()->DemoPlayer()->IsPlaying() ? Localize(pStr: "Preparing demo playback" ) : Localize(pStr: "Connected" ); |
337 | const char *pLoadMapContent = Localize(pStr: "Uploading map data to GPU" ); |
338 | |
339 | auto CurTime = time_get_nanoseconds(); |
340 | auto &&RenderLoading = [&]() { |
341 | if(CanRenderMenuBackground()) |
342 | GameClient()->m_Menus.RenderLoading(pCaption: pConnectCaption, pContent: pLoadMapContent, IncreaseCounter: 0, RenderLoadingBar: false); |
343 | else if(time_get_nanoseconds() - CurTime > 500ms) |
344 | GameClient()->m_Menus.RenderLoading(pCaption: pConnectCaption, pContent: pLoadMapContent, IncreaseCounter: 0, RenderLoadingBar: false, RenderMenuBackgroundMap: false); |
345 | }; |
346 | |
347 | //clear everything and destroy all buffers |
348 | if(!m_vpTileLayerVisuals.empty()) |
349 | { |
350 | int s = m_vpTileLayerVisuals.size(); |
351 | for(int i = 0; i < s; ++i) |
352 | { |
353 | Graphics()->DeleteBufferContainer(ContainerIndex&: m_vpTileLayerVisuals[i]->m_BufferContainerIndex, DestroyAllBO: true); |
354 | delete m_vpTileLayerVisuals[i]; |
355 | } |
356 | m_vpTileLayerVisuals.clear(); |
357 | } |
358 | if(!m_vpQuadLayerVisuals.empty()) |
359 | { |
360 | int s = m_vpQuadLayerVisuals.size(); |
361 | for(int i = 0; i < s; ++i) |
362 | { |
363 | Graphics()->DeleteBufferContainer(ContainerIndex&: m_vpQuadLayerVisuals[i]->m_BufferContainerIndex, DestroyAllBO: true); |
364 | delete m_vpQuadLayerVisuals[i]; |
365 | } |
366 | m_vpQuadLayerVisuals.clear(); |
367 | |
368 | RenderLoading(); |
369 | } |
370 | |
371 | bool PassedGameLayer = false; |
372 | //prepare all visuals for all tile layers |
373 | std::vector<SGraphicTile> vtmpTiles; |
374 | std::vector<SGraphicTileTexureCoords> vtmpTileTexCoords; |
375 | std::vector<SGraphicTile> vtmpBorderTopTiles; |
376 | std::vector<SGraphicTileTexureCoords> vtmpBorderTopTilesTexCoords; |
377 | std::vector<SGraphicTile> vtmpBorderLeftTiles; |
378 | std::vector<SGraphicTileTexureCoords> vtmpBorderLeftTilesTexCoords; |
379 | std::vector<SGraphicTile> vtmpBorderRightTiles; |
380 | std::vector<SGraphicTileTexureCoords> vtmpBorderRightTilesTexCoords; |
381 | std::vector<SGraphicTile> vtmpBorderBottomTiles; |
382 | std::vector<SGraphicTileTexureCoords> vtmpBorderBottomTilesTexCoords; |
383 | std::vector<SGraphicTile> vtmpBorderCorners; |
384 | std::vector<SGraphicTileTexureCoords> vtmpBorderCornersTexCoords; |
385 | |
386 | std::vector<STmpQuad> vtmpQuads; |
387 | std::vector<STmpQuadTextured> vtmpQuadsTextured; |
388 | |
389 | for(int g = 0; g < m_pLayers->NumGroups(); g++) |
390 | { |
391 | CMapItemGroup *pGroup = m_pLayers->GetGroup(Index: g); |
392 | if(!pGroup) |
393 | { |
394 | dbg_msg(sys: "maplayers" , fmt: "error group was null, group number = %d, total groups = %d" , g, m_pLayers->NumGroups()); |
395 | dbg_msg(sys: "maplayers" , fmt: "this is here to prevent a crash but the source of this is unknown, please report this for it to get fixed" ); |
396 | dbg_msg(sys: "maplayers" , fmt: "we need mapname and crc and the map that caused this if possible, and anymore info you think is relevant" ); |
397 | continue; |
398 | } |
399 | |
400 | for(int l = 0; l < pGroup->m_NumLayers; l++) |
401 | { |
402 | CMapItemLayer *pLayer = m_pLayers->GetLayer(Index: pGroup->m_StartLayer + l); |
403 | bool IsFrontLayer = false; |
404 | bool IsSwitchLayer = false; |
405 | bool IsTeleLayer = false; |
406 | bool IsSpeedupLayer = false; |
407 | bool IsTuneLayer = false; |
408 | bool IsGameLayer = false; |
409 | bool IsEntityLayer = false; |
410 | |
411 | if(pLayer == (CMapItemLayer *)m_pLayers->GameLayer()) |
412 | { |
413 | IsGameLayer = true; |
414 | IsEntityLayer = true; |
415 | PassedGameLayer = true; |
416 | } |
417 | |
418 | if(pLayer == (CMapItemLayer *)m_pLayers->FrontLayer()) |
419 | IsEntityLayer = IsFrontLayer = true; |
420 | |
421 | if(pLayer == (CMapItemLayer *)m_pLayers->SwitchLayer()) |
422 | IsEntityLayer = IsSwitchLayer = true; |
423 | |
424 | if(pLayer == (CMapItemLayer *)m_pLayers->TeleLayer()) |
425 | IsEntityLayer = IsTeleLayer = true; |
426 | |
427 | if(pLayer == (CMapItemLayer *)m_pLayers->SpeedupLayer()) |
428 | IsEntityLayer = IsSpeedupLayer = true; |
429 | |
430 | if(pLayer == (CMapItemLayer *)m_pLayers->TuneLayer()) |
431 | IsEntityLayer = IsTuneLayer = true; |
432 | |
433 | if(m_Type <= TYPE_BACKGROUND_FORCE) |
434 | { |
435 | if(PassedGameLayer) |
436 | return; |
437 | } |
438 | else if(m_Type == TYPE_FOREGROUND) |
439 | { |
440 | if(!PassedGameLayer) |
441 | continue; |
442 | } |
443 | |
444 | if(pLayer->m_Type == LAYERTYPE_TILES && Graphics()->IsTileBufferingEnabled()) |
445 | { |
446 | bool DoTextureCoords = false; |
447 | CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; |
448 | if(pTMap->m_Image == -1) |
449 | { |
450 | if(IsEntityLayer) |
451 | DoTextureCoords = true; |
452 | } |
453 | else |
454 | DoTextureCoords = true; |
455 | |
456 | int DataIndex = 0; |
457 | unsigned int TileSize = 0; |
458 | int OverlayCount = 0; |
459 | if(IsFrontLayer) |
460 | { |
461 | DataIndex = pTMap->m_Front; |
462 | TileSize = sizeof(CTile); |
463 | } |
464 | else if(IsSwitchLayer) |
465 | { |
466 | DataIndex = pTMap->m_Switch; |
467 | TileSize = sizeof(CSwitchTile); |
468 | OverlayCount = 2; |
469 | } |
470 | else if(IsTeleLayer) |
471 | { |
472 | DataIndex = pTMap->m_Tele; |
473 | TileSize = sizeof(CTeleTile); |
474 | OverlayCount = 1; |
475 | } |
476 | else if(IsSpeedupLayer) |
477 | { |
478 | DataIndex = pTMap->m_Speedup; |
479 | TileSize = sizeof(CSpeedupTile); |
480 | OverlayCount = 2; |
481 | } |
482 | else if(IsTuneLayer) |
483 | { |
484 | DataIndex = pTMap->m_Tune; |
485 | TileSize = sizeof(CTuneTile); |
486 | } |
487 | else |
488 | { |
489 | DataIndex = pTMap->m_Data; |
490 | TileSize = sizeof(CTile); |
491 | } |
492 | unsigned int Size = m_pLayers->Map()->GetDataSize(Index: DataIndex); |
493 | void *pTiles = m_pLayers->Map()->GetData(Index: DataIndex); |
494 | |
495 | if(Size >= pTMap->m_Width * pTMap->m_Height * TileSize) |
496 | { |
497 | int CurOverlay = 0; |
498 | while(CurOverlay < OverlayCount + 1) |
499 | { |
500 | // We can later just count the tile layers to get the idx in the vector |
501 | m_vpTileLayerVisuals.push_back(x: new STileLayerVisuals()); |
502 | STileLayerVisuals &Visuals = *m_vpTileLayerVisuals.back(); |
503 | if(!Visuals.Init(Width: pTMap->m_Width, Height: pTMap->m_Height)) |
504 | { |
505 | ++CurOverlay; |
506 | continue; |
507 | } |
508 | Visuals.m_IsTextured = DoTextureCoords; |
509 | |
510 | vtmpTiles.clear(); |
511 | vtmpTileTexCoords.clear(); |
512 | |
513 | vtmpBorderTopTiles.clear(); |
514 | vtmpBorderLeftTiles.clear(); |
515 | vtmpBorderRightTiles.clear(); |
516 | vtmpBorderBottomTiles.clear(); |
517 | vtmpBorderCorners.clear(); |
518 | vtmpBorderTopTilesTexCoords.clear(); |
519 | vtmpBorderLeftTilesTexCoords.clear(); |
520 | vtmpBorderRightTilesTexCoords.clear(); |
521 | vtmpBorderBottomTilesTexCoords.clear(); |
522 | vtmpBorderCornersTexCoords.clear(); |
523 | |
524 | if(!DoTextureCoords) |
525 | { |
526 | vtmpTiles.reserve(n: (size_t)pTMap->m_Width * pTMap->m_Height); |
527 | vtmpBorderTopTiles.reserve(n: (size_t)pTMap->m_Width); |
528 | vtmpBorderBottomTiles.reserve(n: (size_t)pTMap->m_Width); |
529 | vtmpBorderLeftTiles.reserve(n: (size_t)pTMap->m_Height); |
530 | vtmpBorderRightTiles.reserve(n: (size_t)pTMap->m_Height); |
531 | vtmpBorderCorners.reserve(n: (size_t)4); |
532 | } |
533 | else |
534 | { |
535 | vtmpTileTexCoords.reserve(n: (size_t)pTMap->m_Width * pTMap->m_Height); |
536 | vtmpBorderTopTilesTexCoords.reserve(n: (size_t)pTMap->m_Width); |
537 | vtmpBorderBottomTilesTexCoords.reserve(n: (size_t)pTMap->m_Width); |
538 | vtmpBorderLeftTilesTexCoords.reserve(n: (size_t)pTMap->m_Height); |
539 | vtmpBorderRightTilesTexCoords.reserve(n: (size_t)pTMap->m_Height); |
540 | vtmpBorderCornersTexCoords.reserve(n: (size_t)4); |
541 | } |
542 | |
543 | int x = 0; |
544 | int y = 0; |
545 | for(y = 0; y < pTMap->m_Height; ++y) |
546 | { |
547 | for(x = 0; x < pTMap->m_Width; ++x) |
548 | { |
549 | unsigned char Index = 0; |
550 | unsigned char Flags = 0; |
551 | int AngleRotate = -1; |
552 | if(IsEntityLayer) |
553 | { |
554 | if(IsGameLayer) |
555 | { |
556 | Index = ((CTile *)pTiles)[y * pTMap->m_Width + x].m_Index; |
557 | Flags = ((CTile *)pTiles)[y * pTMap->m_Width + x].m_Flags; |
558 | } |
559 | if(IsFrontLayer) |
560 | { |
561 | Index = ((CTile *)pTiles)[y * pTMap->m_Width + x].m_Index; |
562 | Flags = ((CTile *)pTiles)[y * pTMap->m_Width + x].m_Flags; |
563 | } |
564 | if(IsSwitchLayer) |
565 | { |
566 | Flags = 0; |
567 | Index = ((CSwitchTile *)pTiles)[y * pTMap->m_Width + x].m_Type; |
568 | if(CurOverlay == 0) |
569 | { |
570 | Flags = ((CSwitchTile *)pTiles)[y * pTMap->m_Width + x].m_Flags; |
571 | if(Index == TILE_SWITCHTIMEDOPEN) |
572 | Index = 8; |
573 | } |
574 | else if(CurOverlay == 1) |
575 | Index = ((CSwitchTile *)pTiles)[y * pTMap->m_Width + x].m_Number; |
576 | else if(CurOverlay == 2) |
577 | Index = ((CSwitchTile *)pTiles)[y * pTMap->m_Width + x].m_Delay; |
578 | } |
579 | if(IsTeleLayer) |
580 | { |
581 | Index = ((CTeleTile *)pTiles)[y * pTMap->m_Width + x].m_Type; |
582 | Flags = 0; |
583 | if(CurOverlay == 1) |
584 | { |
585 | if(IsTeleTileNumberUsedAny(Index)) |
586 | Index = ((CTeleTile *)pTiles)[y * pTMap->m_Width + x].m_Number; |
587 | else |
588 | Index = 0; |
589 | } |
590 | } |
591 | if(IsSpeedupLayer) |
592 | { |
593 | Index = ((CSpeedupTile *)pTiles)[y * pTMap->m_Width + x].m_Type; |
594 | Flags = 0; |
595 | AngleRotate = ((CSpeedupTile *)pTiles)[y * pTMap->m_Width + x].m_Angle; |
596 | if(((CSpeedupTile *)pTiles)[y * pTMap->m_Width + x].m_Force == 0) |
597 | Index = 0; |
598 | else if(CurOverlay == 1) |
599 | Index = ((CSpeedupTile *)pTiles)[y * pTMap->m_Width + x].m_Force; |
600 | else if(CurOverlay == 2) |
601 | Index = ((CSpeedupTile *)pTiles)[y * pTMap->m_Width + x].m_MaxSpeed; |
602 | } |
603 | if(IsTuneLayer) |
604 | { |
605 | Index = ((CTuneTile *)pTiles)[y * pTMap->m_Width + x].m_Type; |
606 | Flags = 0; |
607 | } |
608 | } |
609 | else |
610 | { |
611 | Index = ((CTile *)pTiles)[y * pTMap->m_Width + x].m_Index; |
612 | Flags = ((CTile *)pTiles)[y * pTMap->m_Width + x].m_Flags; |
613 | } |
614 | |
615 | //the amount of tiles handled before this tile |
616 | int TilesHandledCount = vtmpTiles.size(); |
617 | Visuals.m_pTilesOfLayer[y * pTMap->m_Width + x].SetIndexBufferByteOffset((offset_ptr32)(TilesHandledCount)); |
618 | |
619 | bool AddAsSpeedup = false; |
620 | if(IsSpeedupLayer && CurOverlay == 0) |
621 | AddAsSpeedup = true; |
622 | |
623 | if(AddTile(vTmpTiles&: vtmpTiles, vTmpTileTexCoords&: vtmpTileTexCoords, Index, Flags, x, y, pGroup, DoTextureCoords, FillSpeedup: AddAsSpeedup, AngleRotate)) |
624 | Visuals.m_pTilesOfLayer[y * pTMap->m_Width + x].Draw(SetDraw: true); |
625 | |
626 | //do the border tiles |
627 | if(x == 0) |
628 | { |
629 | if(y == 0) |
630 | { |
631 | Visuals.m_BorderTopLeft.SetIndexBufferByteOffset((offset_ptr32)(vtmpBorderCorners.size())); |
632 | if(AddTile(vTmpTiles&: vtmpBorderCorners, vTmpTileTexCoords&: vtmpBorderCornersTexCoords, Index, Flags, x: 0, y: 0, pGroup, DoTextureCoords, FillSpeedup: AddAsSpeedup, AngleRotate, Offset: ivec2{-32, -32})) |
633 | Visuals.m_BorderTopLeft.Draw(SetDraw: true); |
634 | } |
635 | else if(y == pTMap->m_Height - 1) |
636 | { |
637 | Visuals.m_BorderBottomLeft.SetIndexBufferByteOffset((offset_ptr32)(vtmpBorderCorners.size())); |
638 | if(AddTile(vTmpTiles&: vtmpBorderCorners, vTmpTileTexCoords&: vtmpBorderCornersTexCoords, Index, Flags, x: 0, y: 0, pGroup, DoTextureCoords, FillSpeedup: AddAsSpeedup, AngleRotate, Offset: ivec2{-32, 0})) |
639 | Visuals.m_BorderBottomLeft.Draw(SetDraw: true); |
640 | } |
641 | Visuals.m_vBorderLeft[y].SetIndexBufferByteOffset((offset_ptr32)(vtmpBorderLeftTiles.size())); |
642 | if(AddTile(vTmpTiles&: vtmpBorderLeftTiles, vTmpTileTexCoords&: vtmpBorderLeftTilesTexCoords, Index, Flags, x: 0, y, pGroup, DoTextureCoords, FillSpeedup: AddAsSpeedup, AngleRotate, Offset: ivec2{-32, 0})) |
643 | Visuals.m_vBorderLeft[y].Draw(SetDraw: true); |
644 | } |
645 | else if(x == pTMap->m_Width - 1) |
646 | { |
647 | if(y == 0) |
648 | { |
649 | Visuals.m_BorderTopRight.SetIndexBufferByteOffset((offset_ptr32)(vtmpBorderCorners.size())); |
650 | if(AddTile(vTmpTiles&: vtmpBorderCorners, vTmpTileTexCoords&: vtmpBorderCornersTexCoords, Index, Flags, x: 0, y: 0, pGroup, DoTextureCoords, FillSpeedup: AddAsSpeedup, AngleRotate, Offset: ivec2{0, -32})) |
651 | Visuals.m_BorderTopRight.Draw(SetDraw: true); |
652 | } |
653 | else if(y == pTMap->m_Height - 1) |
654 | { |
655 | Visuals.m_BorderBottomRight.SetIndexBufferByteOffset((offset_ptr32)(vtmpBorderCorners.size())); |
656 | if(AddTile(vTmpTiles&: vtmpBorderCorners, vTmpTileTexCoords&: vtmpBorderCornersTexCoords, Index, Flags, x: 0, y: 0, pGroup, DoTextureCoords, FillSpeedup: AddAsSpeedup, AngleRotate, Offset: ivec2{0, 0})) |
657 | Visuals.m_BorderBottomRight.Draw(SetDraw: true); |
658 | } |
659 | Visuals.m_vBorderRight[y].SetIndexBufferByteOffset((offset_ptr32)(vtmpBorderRightTiles.size())); |
660 | if(AddTile(vTmpTiles&: vtmpBorderRightTiles, vTmpTileTexCoords&: vtmpBorderRightTilesTexCoords, Index, Flags, x: 0, y, pGroup, DoTextureCoords, FillSpeedup: AddAsSpeedup, AngleRotate, Offset: ivec2{0, 0})) |
661 | Visuals.m_vBorderRight[y].Draw(SetDraw: true); |
662 | } |
663 | if(y == 0) |
664 | { |
665 | Visuals.m_vBorderTop[x].SetIndexBufferByteOffset((offset_ptr32)(vtmpBorderTopTiles.size())); |
666 | if(AddTile(vTmpTiles&: vtmpBorderTopTiles, vTmpTileTexCoords&: vtmpBorderTopTilesTexCoords, Index, Flags, x, y: 0, pGroup, DoTextureCoords, FillSpeedup: AddAsSpeedup, AngleRotate, Offset: ivec2{0, -32})) |
667 | Visuals.m_vBorderTop[x].Draw(SetDraw: true); |
668 | } |
669 | else if(y == pTMap->m_Height - 1) |
670 | { |
671 | Visuals.m_vBorderBottom[x].SetIndexBufferByteOffset((offset_ptr32)(vtmpBorderBottomTiles.size())); |
672 | if(AddTile(vTmpTiles&: vtmpBorderBottomTiles, vTmpTileTexCoords&: vtmpBorderBottomTilesTexCoords, Index, Flags, x, y: 0, pGroup, DoTextureCoords, FillSpeedup: AddAsSpeedup, AngleRotate, Offset: ivec2{0, 0})) |
673 | Visuals.m_vBorderBottom[x].Draw(SetDraw: true); |
674 | } |
675 | } |
676 | } |
677 | |
678 | //append one kill tile to the gamelayer |
679 | if(IsGameLayer) |
680 | { |
681 | Visuals.m_BorderKillTile.SetIndexBufferByteOffset((offset_ptr32)(vtmpTiles.size())); |
682 | if(AddTile(vTmpTiles&: vtmpTiles, vTmpTileTexCoords&: vtmpTileTexCoords, Index: TILE_DEATH, Flags: 0, x: 0, y: 0, pGroup, DoTextureCoords)) |
683 | Visuals.m_BorderKillTile.Draw(SetDraw: true); |
684 | } |
685 | |
686 | //add the border corners, then the borders and fix their byte offsets |
687 | int TilesHandledCount = vtmpTiles.size(); |
688 | Visuals.m_BorderTopLeft.AddIndexBufferByteOffset(IndexBufferByteOff: TilesHandledCount); |
689 | Visuals.m_BorderTopRight.AddIndexBufferByteOffset(IndexBufferByteOff: TilesHandledCount); |
690 | Visuals.m_BorderBottomLeft.AddIndexBufferByteOffset(IndexBufferByteOff: TilesHandledCount); |
691 | Visuals.m_BorderBottomRight.AddIndexBufferByteOffset(IndexBufferByteOff: TilesHandledCount); |
692 | //add the Corners to the tiles |
693 | vtmpTiles.insert(position: vtmpTiles.end(), first: vtmpBorderCorners.begin(), last: vtmpBorderCorners.end()); |
694 | vtmpTileTexCoords.insert(position: vtmpTileTexCoords.end(), first: vtmpBorderCornersTexCoords.begin(), last: vtmpBorderCornersTexCoords.end()); |
695 | |
696 | //now the borders |
697 | TilesHandledCount = vtmpTiles.size(); |
698 | if(pTMap->m_Width > 0) |
699 | { |
700 | for(int i = 0; i < pTMap->m_Width; ++i) |
701 | { |
702 | Visuals.m_vBorderTop[i].AddIndexBufferByteOffset(IndexBufferByteOff: TilesHandledCount); |
703 | } |
704 | } |
705 | vtmpTiles.insert(position: vtmpTiles.end(), first: vtmpBorderTopTiles.begin(), last: vtmpBorderTopTiles.end()); |
706 | vtmpTileTexCoords.insert(position: vtmpTileTexCoords.end(), first: vtmpBorderTopTilesTexCoords.begin(), last: vtmpBorderTopTilesTexCoords.end()); |
707 | |
708 | TilesHandledCount = vtmpTiles.size(); |
709 | if(pTMap->m_Width > 0) |
710 | { |
711 | for(int i = 0; i < pTMap->m_Width; ++i) |
712 | { |
713 | Visuals.m_vBorderBottom[i].AddIndexBufferByteOffset(IndexBufferByteOff: TilesHandledCount); |
714 | } |
715 | } |
716 | vtmpTiles.insert(position: vtmpTiles.end(), first: vtmpBorderBottomTiles.begin(), last: vtmpBorderBottomTiles.end()); |
717 | vtmpTileTexCoords.insert(position: vtmpTileTexCoords.end(), first: vtmpBorderBottomTilesTexCoords.begin(), last: vtmpBorderBottomTilesTexCoords.end()); |
718 | |
719 | TilesHandledCount = vtmpTiles.size(); |
720 | if(pTMap->m_Height > 0) |
721 | { |
722 | for(int i = 0; i < pTMap->m_Height; ++i) |
723 | { |
724 | Visuals.m_vBorderLeft[i].AddIndexBufferByteOffset(IndexBufferByteOff: TilesHandledCount); |
725 | } |
726 | } |
727 | vtmpTiles.insert(position: vtmpTiles.end(), first: vtmpBorderLeftTiles.begin(), last: vtmpBorderLeftTiles.end()); |
728 | vtmpTileTexCoords.insert(position: vtmpTileTexCoords.end(), first: vtmpBorderLeftTilesTexCoords.begin(), last: vtmpBorderLeftTilesTexCoords.end()); |
729 | |
730 | TilesHandledCount = vtmpTiles.size(); |
731 | if(pTMap->m_Height > 0) |
732 | { |
733 | for(int i = 0; i < pTMap->m_Height; ++i) |
734 | { |
735 | Visuals.m_vBorderRight[i].AddIndexBufferByteOffset(IndexBufferByteOff: TilesHandledCount); |
736 | } |
737 | } |
738 | vtmpTiles.insert(position: vtmpTiles.end(), first: vtmpBorderRightTiles.begin(), last: vtmpBorderRightTiles.end()); |
739 | vtmpTileTexCoords.insert(position: vtmpTileTexCoords.end(), first: vtmpBorderRightTilesTexCoords.begin(), last: vtmpBorderRightTilesTexCoords.end()); |
740 | |
741 | //setup params |
742 | float *pTmpTiles = vtmpTiles.empty() ? NULL : (float *)vtmpTiles.data(); |
743 | unsigned char *pTmpTileTexCoords = vtmpTileTexCoords.empty() ? NULL : (unsigned char *)vtmpTileTexCoords.data(); |
744 | |
745 | Visuals.m_BufferContainerIndex = -1; |
746 | size_t UploadDataSize = vtmpTileTexCoords.size() * sizeof(SGraphicTileTexureCoords) + vtmpTiles.size() * sizeof(SGraphicTile); |
747 | if(UploadDataSize > 0) |
748 | { |
749 | char *pUploadData = (char *)malloc(size: sizeof(char) * UploadDataSize); |
750 | |
751 | mem_copy_special(pDest: pUploadData, pSource: pTmpTiles, Size: sizeof(vec2), Count: vtmpTiles.size() * 4, Steps: (DoTextureCoords ? sizeof(ubvec4) : 0)); |
752 | if(DoTextureCoords) |
753 | { |
754 | mem_copy_special(pDest: pUploadData + sizeof(vec2), pSource: pTmpTileTexCoords, Size: sizeof(ubvec4), Count: vtmpTiles.size() * 4, Steps: sizeof(vec2)); |
755 | } |
756 | |
757 | // first create the buffer object |
758 | int BufferObjectIndex = Graphics()->CreateBufferObject(UploadDataSize, pUploadData, CreateFlags: 0, IsMovedPointer: true); |
759 | |
760 | // then create the buffer container |
761 | SBufferContainerInfo ContainerInfo; |
762 | ContainerInfo.m_Stride = (DoTextureCoords ? (sizeof(float) * 2 + sizeof(ubvec4)) : 0); |
763 | ContainerInfo.m_VertBufferBindingIndex = BufferObjectIndex; |
764 | ContainerInfo.m_vAttributes.emplace_back(); |
765 | SBufferContainerInfo::SAttribute *pAttr = &ContainerInfo.m_vAttributes.back(); |
766 | pAttr->m_DataTypeCount = 2; |
767 | pAttr->m_Type = GRAPHICS_TYPE_FLOAT; |
768 | pAttr->m_Normalized = false; |
769 | pAttr->m_pOffset = 0; |
770 | pAttr->m_FuncType = 0; |
771 | if(DoTextureCoords) |
772 | { |
773 | ContainerInfo.m_vAttributes.emplace_back(); |
774 | pAttr = &ContainerInfo.m_vAttributes.back(); |
775 | pAttr->m_DataTypeCount = 4; |
776 | pAttr->m_Type = GRAPHICS_TYPE_UNSIGNED_BYTE; |
777 | pAttr->m_Normalized = false; |
778 | pAttr->m_pOffset = (void *)(sizeof(vec2)); |
779 | pAttr->m_FuncType = 1; |
780 | } |
781 | |
782 | Visuals.m_BufferContainerIndex = Graphics()->CreateBufferContainer(pContainerInfo: &ContainerInfo); |
783 | // and finally inform the backend how many indices are required |
784 | Graphics()->IndicesNumRequiredNotify(RequiredIndicesCount: vtmpTiles.size() * 6); |
785 | |
786 | RenderLoading(); |
787 | } |
788 | |
789 | ++CurOverlay; |
790 | } |
791 | } |
792 | } |
793 | else if(pLayer->m_Type == LAYERTYPE_QUADS && Graphics()->IsQuadBufferingEnabled()) |
794 | { |
795 | CMapItemLayerQuads *pQLayer = (CMapItemLayerQuads *)pLayer; |
796 | |
797 | m_vpQuadLayerVisuals.push_back(x: new SQuadLayerVisuals()); |
798 | SQuadLayerVisuals *pQLayerVisuals = m_vpQuadLayerVisuals.back(); |
799 | |
800 | bool Textured = (pQLayer->m_Image != -1); |
801 | |
802 | vtmpQuads.clear(); |
803 | vtmpQuadsTextured.clear(); |
804 | |
805 | if(Textured) |
806 | vtmpQuadsTextured.resize(new_size: pQLayer->m_NumQuads); |
807 | else |
808 | vtmpQuads.resize(new_size: pQLayer->m_NumQuads); |
809 | |
810 | CQuad *pQuads = (CQuad *)m_pLayers->Map()->GetDataSwapped(Index: pQLayer->m_Data); |
811 | for(int i = 0; i < pQLayer->m_NumQuads; ++i) |
812 | { |
813 | CQuad *pQuad = &pQuads[i]; |
814 | for(int j = 0; j < 4; ++j) |
815 | { |
816 | int QuadIdX = j; |
817 | if(j == 2) |
818 | QuadIdX = 3; |
819 | else if(j == 3) |
820 | QuadIdX = 2; |
821 | if(!Textured) |
822 | { |
823 | // ignore the conversion for the position coordinates |
824 | vtmpQuads[i].m_aVertices[j].m_X = (pQuad->m_aPoints[QuadIdX].x); |
825 | vtmpQuads[i].m_aVertices[j].m_Y = (pQuad->m_aPoints[QuadIdX].y); |
826 | vtmpQuads[i].m_aVertices[j].m_CenterX = (pQuad->m_aPoints[4].x); |
827 | vtmpQuads[i].m_aVertices[j].m_CenterY = (pQuad->m_aPoints[4].y); |
828 | vtmpQuads[i].m_aVertices[j].m_R = (unsigned char)pQuad->m_aColors[QuadIdX].r; |
829 | vtmpQuads[i].m_aVertices[j].m_G = (unsigned char)pQuad->m_aColors[QuadIdX].g; |
830 | vtmpQuads[i].m_aVertices[j].m_B = (unsigned char)pQuad->m_aColors[QuadIdX].b; |
831 | vtmpQuads[i].m_aVertices[j].m_A = (unsigned char)pQuad->m_aColors[QuadIdX].a; |
832 | } |
833 | else |
834 | { |
835 | // ignore the conversion for the position coordinates |
836 | vtmpQuadsTextured[i].m_aVertices[j].m_X = (pQuad->m_aPoints[QuadIdX].x); |
837 | vtmpQuadsTextured[i].m_aVertices[j].m_Y = (pQuad->m_aPoints[QuadIdX].y); |
838 | vtmpQuadsTextured[i].m_aVertices[j].m_CenterX = (pQuad->m_aPoints[4].x); |
839 | vtmpQuadsTextured[i].m_aVertices[j].m_CenterY = (pQuad->m_aPoints[4].y); |
840 | vtmpQuadsTextured[i].m_aVertices[j].m_U = fx2f(v: pQuad->m_aTexcoords[QuadIdX].x); |
841 | vtmpQuadsTextured[i].m_aVertices[j].m_V = fx2f(v: pQuad->m_aTexcoords[QuadIdX].y); |
842 | vtmpQuadsTextured[i].m_aVertices[j].m_R = (unsigned char)pQuad->m_aColors[QuadIdX].r; |
843 | vtmpQuadsTextured[i].m_aVertices[j].m_G = (unsigned char)pQuad->m_aColors[QuadIdX].g; |
844 | vtmpQuadsTextured[i].m_aVertices[j].m_B = (unsigned char)pQuad->m_aColors[QuadIdX].b; |
845 | vtmpQuadsTextured[i].m_aVertices[j].m_A = (unsigned char)pQuad->m_aColors[QuadIdX].a; |
846 | } |
847 | } |
848 | } |
849 | |
850 | size_t UploadDataSize = 0; |
851 | if(Textured) |
852 | UploadDataSize = vtmpQuadsTextured.size() * sizeof(STmpQuadTextured); |
853 | else |
854 | UploadDataSize = vtmpQuads.size() * sizeof(STmpQuad); |
855 | |
856 | if(UploadDataSize > 0) |
857 | { |
858 | void *pUploadData = NULL; |
859 | if(Textured) |
860 | pUploadData = vtmpQuadsTextured.data(); |
861 | else |
862 | pUploadData = vtmpQuads.data(); |
863 | // create the buffer object |
864 | int BufferObjectIndex = Graphics()->CreateBufferObject(UploadDataSize, pUploadData, CreateFlags: 0); |
865 | // then create the buffer container |
866 | SBufferContainerInfo ContainerInfo; |
867 | ContainerInfo.m_Stride = (Textured ? (sizeof(STmpQuadTextured) / 4) : (sizeof(STmpQuad) / 4)); |
868 | ContainerInfo.m_VertBufferBindingIndex = BufferObjectIndex; |
869 | ContainerInfo.m_vAttributes.emplace_back(); |
870 | SBufferContainerInfo::SAttribute *pAttr = &ContainerInfo.m_vAttributes.back(); |
871 | pAttr->m_DataTypeCount = 4; |
872 | pAttr->m_Type = GRAPHICS_TYPE_FLOAT; |
873 | pAttr->m_Normalized = false; |
874 | pAttr->m_pOffset = 0; |
875 | pAttr->m_FuncType = 0; |
876 | ContainerInfo.m_vAttributes.emplace_back(); |
877 | pAttr = &ContainerInfo.m_vAttributes.back(); |
878 | pAttr->m_DataTypeCount = 4; |
879 | pAttr->m_Type = GRAPHICS_TYPE_UNSIGNED_BYTE; |
880 | pAttr->m_Normalized = true; |
881 | pAttr->m_pOffset = (void *)(sizeof(float) * 4); |
882 | pAttr->m_FuncType = 0; |
883 | if(Textured) |
884 | { |
885 | ContainerInfo.m_vAttributes.emplace_back(); |
886 | pAttr = &ContainerInfo.m_vAttributes.back(); |
887 | pAttr->m_DataTypeCount = 2; |
888 | pAttr->m_Type = GRAPHICS_TYPE_FLOAT; |
889 | pAttr->m_Normalized = false; |
890 | pAttr->m_pOffset = (void *)(sizeof(float) * 4 + sizeof(unsigned char) * 4); |
891 | pAttr->m_FuncType = 0; |
892 | } |
893 | |
894 | pQLayerVisuals->m_BufferContainerIndex = Graphics()->CreateBufferContainer(pContainerInfo: &ContainerInfo); |
895 | // and finally inform the backend how many indices are required |
896 | Graphics()->IndicesNumRequiredNotify(RequiredIndicesCount: pQLayer->m_NumQuads * 6); |
897 | |
898 | RenderLoading(); |
899 | } |
900 | } |
901 | } |
902 | } |
903 | } |
904 | |
905 | void CMapLayers::RenderTileLayer(int LayerIndex, const ColorRGBA &Color, CMapItemLayerTilemap *pTileLayer, CMapItemGroup *pGroup) |
906 | { |
907 | STileLayerVisuals &Visuals = *m_vpTileLayerVisuals[LayerIndex]; |
908 | if(Visuals.m_BufferContainerIndex == -1) |
909 | return; //no visuals were created |
910 | |
911 | float ScreenX0, ScreenY0, ScreenX1, ScreenY1; |
912 | Graphics()->GetScreen(pTopLeftX: &ScreenX0, pTopLeftY: &ScreenY0, pBottomRightX: &ScreenX1, pBottomRightY: &ScreenY1); |
913 | |
914 | int BorderX0, BorderY0, BorderX1, BorderY1; |
915 | bool DrawBorder = false; |
916 | |
917 | int Y0 = BorderY0 = std::floor(x: ScreenY0 / 32); |
918 | int X0 = BorderX0 = std::floor(x: ScreenX0 / 32); |
919 | int Y1 = BorderY1 = std::ceil(x: ScreenY1 / 32); |
920 | int X1 = BorderX1 = std::ceil(x: ScreenX1 / 32); |
921 | |
922 | if(X0 < 0) |
923 | { |
924 | X0 = 0; |
925 | DrawBorder = true; |
926 | } |
927 | if(Y0 < 0) |
928 | { |
929 | Y0 = 0; |
930 | DrawBorder = true; |
931 | } |
932 | if(X1 > pTileLayer->m_Width) |
933 | { |
934 | X1 = pTileLayer->m_Width; |
935 | DrawBorder = true; |
936 | } |
937 | if(Y1 > pTileLayer->m_Height) |
938 | { |
939 | Y1 = pTileLayer->m_Height; |
940 | DrawBorder = true; |
941 | } |
942 | |
943 | bool DrawLayer = true; |
944 | if(X1 <= 0) |
945 | DrawLayer = false; |
946 | if(Y1 <= 0) |
947 | DrawLayer = false; |
948 | if(X0 >= pTileLayer->m_Width) |
949 | DrawLayer = false; |
950 | if(Y0 >= pTileLayer->m_Height) |
951 | DrawLayer = false; |
952 | |
953 | if(DrawLayer) |
954 | { |
955 | //create the indice buffers we want to draw -- reuse them |
956 | static std::vector<char *> s_vpIndexOffsets; |
957 | static std::vector<unsigned int> s_vDrawCounts; |
958 | |
959 | s_vpIndexOffsets.clear(); |
960 | s_vDrawCounts.clear(); |
961 | |
962 | unsigned long long Reserve = absolute(a: Y1 - Y0) + 1; |
963 | s_vpIndexOffsets.reserve(n: Reserve); |
964 | s_vDrawCounts.reserve(n: Reserve); |
965 | |
966 | for(int y = Y0; y < Y1; ++y) |
967 | { |
968 | if(X0 > X1) |
969 | continue; |
970 | int XR = X1 - 1; |
971 | |
972 | dbg_assert(Visuals.m_pTilesOfLayer[y * pTileLayer->m_Width + XR].IndexBufferByteOffset() >= Visuals.m_pTilesOfLayer[y * pTileLayer->m_Width + X0].IndexBufferByteOffset(), "Tile count wrong." ); |
973 | |
974 | unsigned int NumVertices = ((Visuals.m_pTilesOfLayer[y * pTileLayer->m_Width + XR].IndexBufferByteOffset() - Visuals.m_pTilesOfLayer[y * pTileLayer->m_Width + X0].IndexBufferByteOffset()) / sizeof(unsigned int)) + (Visuals.m_pTilesOfLayer[y * pTileLayer->m_Width + XR].DoDraw() ? 6lu : 0lu); |
975 | |
976 | if(NumVertices) |
977 | { |
978 | s_vpIndexOffsets.push_back(x: (offset_ptr_size)Visuals.m_pTilesOfLayer[y * pTileLayer->m_Width + X0].IndexBufferByteOffset()); |
979 | s_vDrawCounts.push_back(x: NumVertices); |
980 | } |
981 | } |
982 | |
983 | int DrawCount = s_vpIndexOffsets.size(); |
984 | if(DrawCount != 0) |
985 | { |
986 | Graphics()->RenderTileLayer(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pOffsets: s_vpIndexOffsets.data(), pIndicedVertexDrawNum: s_vDrawCounts.data(), NumIndicesOffset: DrawCount); |
987 | } |
988 | } |
989 | |
990 | if(DrawBorder) |
991 | RenderTileBorder(LayerIndex, Color, pTileLayer, pGroup, BorderX0, BorderY0, BorderX1, BorderY1); |
992 | } |
993 | |
994 | void CMapLayers::RenderTileBorder(int LayerIndex, const ColorRGBA &Color, CMapItemLayerTilemap *pTileLayer, CMapItemGroup *pGroup, int BorderX0, int BorderY0, int BorderX1, int BorderY1) |
995 | { |
996 | STileLayerVisuals &Visuals = *m_vpTileLayerVisuals[LayerIndex]; |
997 | |
998 | int Y0 = BorderY0; |
999 | int X0 = BorderX0; |
1000 | int Y1 = BorderY1; |
1001 | int X1 = BorderX1; |
1002 | |
1003 | if(X0 < 0) |
1004 | X0 = 0; |
1005 | if(Y0 < 0) |
1006 | Y0 = 0; |
1007 | if(X1 > pTileLayer->m_Width) |
1008 | X1 = pTileLayer->m_Width; |
1009 | if(Y1 > pTileLayer->m_Height) |
1010 | Y1 = pTileLayer->m_Height; |
1011 | |
1012 | // corners |
1013 | if(BorderX0 < 0) |
1014 | { |
1015 | // Draw corners on left side |
1016 | if(BorderY0 < 0) |
1017 | { |
1018 | if(Visuals.m_BorderTopLeft.DoDraw()) |
1019 | { |
1020 | vec2 Offset; |
1021 | Offset.x = 0; |
1022 | Offset.y = 0; |
1023 | vec2 Scale; |
1024 | Scale.x = absolute(a: BorderX0); |
1025 | Scale.y = absolute(a: BorderY0); |
1026 | |
1027 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: (offset_ptr_size)Visuals.m_BorderTopLeft.IndexBufferByteOffset(), Offset, Scale, DrawNum: 1); |
1028 | } |
1029 | } |
1030 | if(BorderY1 > pTileLayer->m_Height) |
1031 | { |
1032 | if(Visuals.m_BorderBottomLeft.DoDraw()) |
1033 | { |
1034 | vec2 Offset; |
1035 | Offset.x = 0; |
1036 | Offset.y = pTileLayer->m_Height * 32.0f; |
1037 | vec2 Scale; |
1038 | Scale.x = absolute(a: BorderX0); |
1039 | Scale.y = BorderY1 - pTileLayer->m_Height; |
1040 | |
1041 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: (offset_ptr_size)Visuals.m_BorderBottomLeft.IndexBufferByteOffset(), Offset, Scale, DrawNum: 1); |
1042 | } |
1043 | } |
1044 | } |
1045 | if(BorderX1 > pTileLayer->m_Width) |
1046 | { |
1047 | // Draw corners on right side |
1048 | if(BorderY0 < 0) |
1049 | { |
1050 | if(Visuals.m_BorderTopRight.DoDraw()) |
1051 | { |
1052 | vec2 Offset; |
1053 | Offset.x = pTileLayer->m_Width * 32.0f; |
1054 | Offset.y = 0; |
1055 | vec2 Scale; |
1056 | Scale.x = BorderX1 - pTileLayer->m_Width; |
1057 | Scale.y = absolute(a: BorderY0); |
1058 | |
1059 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: (offset_ptr_size)Visuals.m_BorderTopRight.IndexBufferByteOffset(), Offset, Scale, DrawNum: 1); |
1060 | } |
1061 | } |
1062 | if(BorderY1 > pTileLayer->m_Height) |
1063 | { |
1064 | if(Visuals.m_BorderBottomRight.DoDraw()) |
1065 | { |
1066 | vec2 Offset; |
1067 | Offset.x = pTileLayer->m_Width * 32.0f; |
1068 | Offset.y = pTileLayer->m_Height * 32.0f; |
1069 | vec2 Scale; |
1070 | Scale.x = BorderX1 - pTileLayer->m_Width; |
1071 | Scale.y = BorderY1 - pTileLayer->m_Height; |
1072 | |
1073 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: (offset_ptr_size)Visuals.m_BorderBottomRight.IndexBufferByteOffset(), Offset, Scale, DrawNum: 1); |
1074 | } |
1075 | } |
1076 | } |
1077 | |
1078 | if(BorderX1 > pTileLayer->m_Width) |
1079 | { |
1080 | // Draw right border |
1081 | if(Y0 < pTileLayer->m_Height && Y1 > 0) |
1082 | { |
1083 | int YB = Y1 - 1; |
1084 | unsigned int DrawNum = ((Visuals.m_vBorderRight[YB].IndexBufferByteOffset() - Visuals.m_vBorderRight[Y0].IndexBufferByteOffset()) / (sizeof(unsigned int) * 6)) + (Visuals.m_vBorderRight[YB].DoDraw() ? 1lu : 0lu); |
1085 | offset_ptr_size pOffset = (offset_ptr_size)Visuals.m_vBorderRight[Y0].IndexBufferByteOffset(); |
1086 | vec2 Offset; |
1087 | Offset.x = 32.f * pTileLayer->m_Width; |
1088 | Offset.y = 0.f; |
1089 | vec2 Scale; |
1090 | Scale.x = BorderX1 - pTileLayer->m_Width; |
1091 | Scale.y = 1.f; |
1092 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: pOffset, Offset, Scale, DrawNum); |
1093 | } |
1094 | } |
1095 | if(BorderX0 < 0) |
1096 | { |
1097 | // Draw left border |
1098 | if(Y0 < pTileLayer->m_Height && Y1 > 0) |
1099 | { |
1100 | int YB = Y1 - 1; |
1101 | unsigned int DrawNum = ((Visuals.m_vBorderLeft[YB].IndexBufferByteOffset() - Visuals.m_vBorderLeft[Y0].IndexBufferByteOffset()) / (sizeof(unsigned int) * 6)) + (Visuals.m_vBorderLeft[YB].DoDraw() ? 1lu : 0lu); |
1102 | offset_ptr_size pOffset = (offset_ptr_size)Visuals.m_vBorderLeft[Y0].IndexBufferByteOffset(); |
1103 | vec2 Offset; |
1104 | Offset.x = 0; |
1105 | Offset.y = 0; |
1106 | vec2 Scale; |
1107 | Scale.x = absolute(a: BorderX0); |
1108 | Scale.y = 1; |
1109 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: pOffset, Offset, Scale, DrawNum); |
1110 | } |
1111 | } |
1112 | if(BorderY0 < 0) |
1113 | { |
1114 | // Draw top border |
1115 | if(X0 < pTileLayer->m_Width && X1 > 0) |
1116 | { |
1117 | int XR = X1 - 1; |
1118 | unsigned int DrawNum = ((Visuals.m_vBorderTop[XR].IndexBufferByteOffset() - Visuals.m_vBorderTop[X0].IndexBufferByteOffset()) / (sizeof(unsigned int) * 6)) + (Visuals.m_vBorderTop[XR].DoDraw() ? 1lu : 0lu); |
1119 | offset_ptr_size pOffset = (offset_ptr_size)Visuals.m_vBorderTop[X0].IndexBufferByteOffset(); |
1120 | vec2 Offset; |
1121 | Offset.x = 0.f; |
1122 | Offset.y = 0; |
1123 | vec2 Scale; |
1124 | Scale.x = 1; |
1125 | Scale.y = absolute(a: BorderY0); |
1126 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: pOffset, Offset, Scale, DrawNum); |
1127 | } |
1128 | } |
1129 | if(BorderY1 > pTileLayer->m_Height) |
1130 | { |
1131 | // Draw bottom border |
1132 | if(X0 < pTileLayer->m_Width && X1 > 0) |
1133 | { |
1134 | int XR = X1 - 1; |
1135 | unsigned int DrawNum = ((Visuals.m_vBorderBottom[XR].IndexBufferByteOffset() - Visuals.m_vBorderBottom[X0].IndexBufferByteOffset()) / (sizeof(unsigned int) * 6)) + (Visuals.m_vBorderBottom[XR].DoDraw() ? 1lu : 0lu); |
1136 | offset_ptr_size pOffset = (offset_ptr_size)Visuals.m_vBorderBottom[X0].IndexBufferByteOffset(); |
1137 | vec2 Offset; |
1138 | Offset.x = 0.f; |
1139 | Offset.y = 32.f * pTileLayer->m_Height; |
1140 | vec2 Scale; |
1141 | Scale.x = 1; |
1142 | Scale.y = BorderY1 - pTileLayer->m_Height; |
1143 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: pOffset, Offset, Scale, DrawNum); |
1144 | } |
1145 | } |
1146 | } |
1147 | |
1148 | void CMapLayers::RenderKillTileBorder(int LayerIndex, const ColorRGBA &Color, CMapItemLayerTilemap *pTileLayer, CMapItemGroup *pGroup) |
1149 | { |
1150 | STileLayerVisuals &Visuals = *m_vpTileLayerVisuals[LayerIndex]; |
1151 | if(Visuals.m_BufferContainerIndex == -1) |
1152 | return; //no visuals were created |
1153 | |
1154 | float ScreenX0, ScreenY0, ScreenX1, ScreenY1; |
1155 | Graphics()->GetScreen(pTopLeftX: &ScreenX0, pTopLeftY: &ScreenY0, pBottomRightX: &ScreenX1, pBottomRightY: &ScreenY1); |
1156 | |
1157 | bool DrawBorder = false; |
1158 | |
1159 | int BorderY0 = std::floor(x: ScreenY0 / 32); |
1160 | int BorderX0 = std::floor(x: ScreenX0 / 32); |
1161 | int BorderY1 = std::ceil(x: ScreenY1 / 32); |
1162 | int BorderX1 = std::ceil(x: ScreenX1 / 32); |
1163 | |
1164 | if(BorderX0 < -201) |
1165 | DrawBorder = true; |
1166 | if(BorderY0 < -201) |
1167 | DrawBorder = true; |
1168 | if(BorderX1 > pTileLayer->m_Width + 201) |
1169 | DrawBorder = true; |
1170 | if(BorderY1 > pTileLayer->m_Height + 201) |
1171 | DrawBorder = true; |
1172 | |
1173 | if(!DrawBorder) |
1174 | return; |
1175 | if(!Visuals.m_BorderKillTile.DoDraw()) |
1176 | return; |
1177 | |
1178 | if(BorderX0 < -300) |
1179 | BorderX0 = -300; |
1180 | if(BorderY0 < -300) |
1181 | BorderY0 = -300; |
1182 | if(BorderX1 >= pTileLayer->m_Width + 300) |
1183 | BorderX1 = pTileLayer->m_Width + 299; |
1184 | if(BorderY1 >= pTileLayer->m_Height + 300) |
1185 | BorderY1 = pTileLayer->m_Height + 299; |
1186 | |
1187 | if(BorderX1 < -300) |
1188 | BorderX1 = -300; |
1189 | if(BorderY1 < -300) |
1190 | BorderY1 = -300; |
1191 | if(BorderX0 >= pTileLayer->m_Width + 300) |
1192 | BorderX0 = pTileLayer->m_Width + 299; |
1193 | if(BorderY0 >= pTileLayer->m_Height + 300) |
1194 | BorderY0 = pTileLayer->m_Height + 299; |
1195 | |
1196 | // Draw left kill tile border |
1197 | if(BorderX0 < -201) |
1198 | { |
1199 | unsigned int DrawNum = 1; |
1200 | offset_ptr_size pOffset = (offset_ptr_size)Visuals.m_BorderKillTile.IndexBufferByteOffset(); |
1201 | vec2 Offset; |
1202 | Offset.x = 32.f * BorderX0; |
1203 | Offset.y = 32.f * BorderY0; |
1204 | vec2 Scale; |
1205 | Scale.x = -201 - BorderX0; |
1206 | Scale.y = BorderY1 - BorderY0; |
1207 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: pOffset, Offset, Scale, DrawNum); |
1208 | } |
1209 | // Draw top kill tile border |
1210 | if(BorderY0 < -201) |
1211 | { |
1212 | unsigned int DrawNum = 1; |
1213 | offset_ptr_size pOffset = (offset_ptr_size)Visuals.m_BorderKillTile.IndexBufferByteOffset(); |
1214 | vec2 Offset; |
1215 | Offset.x = maximum(a: BorderX0, b: -201) * 32.0f; |
1216 | Offset.y = 32.f * BorderY0; |
1217 | vec2 Scale; |
1218 | Scale.x = minimum(a: BorderX1, b: pTileLayer->m_Width + 201) - maximum(a: BorderX0, b: -201); |
1219 | Scale.y = -201 - BorderY0; |
1220 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: pOffset, Offset, Scale, DrawNum); |
1221 | } |
1222 | // Draw right kill tile border |
1223 | if(BorderX1 > pTileLayer->m_Width + 201) |
1224 | { |
1225 | unsigned int DrawNum = 1; |
1226 | offset_ptr_size pOffset = (offset_ptr_size)Visuals.m_BorderKillTile.IndexBufferByteOffset(); |
1227 | vec2 Offset; |
1228 | Offset.x = 32.0f * (pTileLayer->m_Width + 201); |
1229 | Offset.y = 32.0f * BorderY0; |
1230 | vec2 Scale; |
1231 | Scale.x = BorderX1 - (pTileLayer->m_Width + 201); |
1232 | Scale.y = BorderY1 - BorderY0; |
1233 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: pOffset, Offset, Scale, DrawNum); |
1234 | } |
1235 | // Draw bottom kill tile border |
1236 | if(BorderY1 > pTileLayer->m_Height + 201) |
1237 | { |
1238 | unsigned int DrawNum = 1; |
1239 | offset_ptr_size pOffset = (offset_ptr_size)Visuals.m_BorderKillTile.IndexBufferByteOffset(); |
1240 | vec2 Offset; |
1241 | Offset.x = maximum(a: BorderX0, b: -201) * 32.0f; |
1242 | Offset.y = 32.0f * (pTileLayer->m_Height + 201); |
1243 | vec2 Scale; |
1244 | Scale.x = minimum(a: BorderX1, b: pTileLayer->m_Width + 201) - maximum(a: BorderX0, b: -201); |
1245 | Scale.y = BorderY1 - (pTileLayer->m_Height + 201); |
1246 | Graphics()->RenderBorderTiles(BufferContainerIndex: Visuals.m_BufferContainerIndex, Color, pIndexBufferOffset: pOffset, Offset, Scale, DrawNum); |
1247 | } |
1248 | } |
1249 | |
1250 | void CMapLayers::RenderQuadLayer(int LayerIndex, CMapItemLayerQuads *pQuadLayer, CMapItemGroup *pGroup, bool Force) |
1251 | { |
1252 | SQuadLayerVisuals &Visuals = *m_vpQuadLayerVisuals[LayerIndex]; |
1253 | if(Visuals.m_BufferContainerIndex == -1) |
1254 | return; //no visuals were created |
1255 | |
1256 | if(!Force && (!g_Config.m_ClShowQuads || g_Config.m_ClOverlayEntities == 100)) |
1257 | return; |
1258 | |
1259 | CQuad *pQuads = (CQuad *)m_pLayers->Map()->GetDataSwapped(Index: pQuadLayer->m_Data); |
1260 | |
1261 | static std::vector<SQuadRenderInfo> s_vQuadRenderInfo; |
1262 | |
1263 | s_vQuadRenderInfo.resize(new_size: pQuadLayer->m_NumQuads); |
1264 | size_t QuadsRenderCount = 0; |
1265 | size_t CurQuadOffset = 0; |
1266 | for(int i = 0; i < pQuadLayer->m_NumQuads; ++i) |
1267 | { |
1268 | CQuad *pQuad = &pQuads[i]; |
1269 | |
1270 | ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f); |
1271 | EnvelopeEval(TimeOffsetMillis: pQuad->m_ColorEnvOffset, Env: pQuad->m_ColorEnv, Result&: Color, Channels: 4, pUser: this); |
1272 | |
1273 | const bool IsFullyTransparent = Color.a <= 0.0f; |
1274 | const bool NeedsFlush = QuadsRenderCount == gs_GraphicsMaxQuadsRenderCount || IsFullyTransparent; |
1275 | |
1276 | if(NeedsFlush) |
1277 | { |
1278 | // render quads of the current offset directly(cancel batching) |
1279 | Graphics()->RenderQuadLayer(BufferContainerIndex: Visuals.m_BufferContainerIndex, pQuadInfo: s_vQuadRenderInfo.data(), QuadNum: QuadsRenderCount, QuadOffset: CurQuadOffset); |
1280 | QuadsRenderCount = 0; |
1281 | CurQuadOffset = i; |
1282 | if(IsFullyTransparent) |
1283 | { |
1284 | // since this quad is ignored, the offset is the next quad |
1285 | ++CurQuadOffset; |
1286 | } |
1287 | } |
1288 | |
1289 | if(!IsFullyTransparent) |
1290 | { |
1291 | ColorRGBA Position = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f); |
1292 | EnvelopeEval(TimeOffsetMillis: pQuad->m_PosEnvOffset, Env: pQuad->m_PosEnv, Result&: Position, Channels: 3, pUser: this); |
1293 | |
1294 | SQuadRenderInfo &QInfo = s_vQuadRenderInfo[QuadsRenderCount++]; |
1295 | QInfo.m_Color = Color; |
1296 | QInfo.m_Offsets.x = Position.r; |
1297 | QInfo.m_Offsets.y = Position.g; |
1298 | QInfo.m_Rotation = Position.b / 180.0f * pi; |
1299 | } |
1300 | } |
1301 | Graphics()->RenderQuadLayer(BufferContainerIndex: Visuals.m_BufferContainerIndex, pQuadInfo: s_vQuadRenderInfo.data(), QuadNum: QuadsRenderCount, QuadOffset: CurQuadOffset); |
1302 | } |
1303 | |
1304 | void CMapLayers::LayersOfGroupCount(CMapItemGroup *pGroup, int &TileLayerCount, int &QuadLayerCount, bool &PassedGameLayer) |
1305 | { |
1306 | int TileLayerCounter = 0; |
1307 | int QuadLayerCounter = 0; |
1308 | for(int l = 0; l < pGroup->m_NumLayers; l++) |
1309 | { |
1310 | CMapItemLayer *pLayer = m_pLayers->GetLayer(Index: pGroup->m_StartLayer + l); |
1311 | bool IsFrontLayer = false; |
1312 | bool IsSwitchLayer = false; |
1313 | bool IsTeleLayer = false; |
1314 | bool IsSpeedupLayer = false; |
1315 | bool IsTuneLayer = false; |
1316 | |
1317 | if(pLayer == (CMapItemLayer *)m_pLayers->GameLayer()) |
1318 | { |
1319 | PassedGameLayer = true; |
1320 | } |
1321 | |
1322 | if(pLayer == (CMapItemLayer *)m_pLayers->FrontLayer()) |
1323 | IsFrontLayer = true; |
1324 | |
1325 | if(pLayer == (CMapItemLayer *)m_pLayers->SwitchLayer()) |
1326 | IsSwitchLayer = true; |
1327 | |
1328 | if(pLayer == (CMapItemLayer *)m_pLayers->TeleLayer()) |
1329 | IsTeleLayer = true; |
1330 | |
1331 | if(pLayer == (CMapItemLayer *)m_pLayers->SpeedupLayer()) |
1332 | IsSpeedupLayer = true; |
1333 | |
1334 | if(pLayer == (CMapItemLayer *)m_pLayers->TuneLayer()) |
1335 | IsTuneLayer = true; |
1336 | |
1337 | if(m_Type <= TYPE_BACKGROUND_FORCE) |
1338 | { |
1339 | if(PassedGameLayer) |
1340 | break; |
1341 | } |
1342 | else if(m_Type == TYPE_FOREGROUND) |
1343 | { |
1344 | if(!PassedGameLayer) |
1345 | continue; |
1346 | } |
1347 | |
1348 | if(pLayer->m_Type == LAYERTYPE_TILES) |
1349 | { |
1350 | CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; |
1351 | int DataIndex = 0; |
1352 | unsigned int TileSize = 0; |
1353 | int TileLayerAndOverlayCount = 0; |
1354 | if(IsFrontLayer) |
1355 | { |
1356 | DataIndex = pTMap->m_Front; |
1357 | TileSize = sizeof(CTile); |
1358 | TileLayerAndOverlayCount = 1; |
1359 | } |
1360 | else if(IsSwitchLayer) |
1361 | { |
1362 | DataIndex = pTMap->m_Switch; |
1363 | TileSize = sizeof(CSwitchTile); |
1364 | TileLayerAndOverlayCount = 3; |
1365 | } |
1366 | else if(IsTeleLayer) |
1367 | { |
1368 | DataIndex = pTMap->m_Tele; |
1369 | TileSize = sizeof(CTeleTile); |
1370 | TileLayerAndOverlayCount = 2; |
1371 | } |
1372 | else if(IsSpeedupLayer) |
1373 | { |
1374 | DataIndex = pTMap->m_Speedup; |
1375 | TileSize = sizeof(CSpeedupTile); |
1376 | TileLayerAndOverlayCount = 3; |
1377 | } |
1378 | else if(IsTuneLayer) |
1379 | { |
1380 | DataIndex = pTMap->m_Tune; |
1381 | TileSize = sizeof(CTuneTile); |
1382 | TileLayerAndOverlayCount = 1; |
1383 | } |
1384 | else |
1385 | { |
1386 | DataIndex = pTMap->m_Data; |
1387 | TileSize = sizeof(CTile); |
1388 | TileLayerAndOverlayCount = 1; |
1389 | } |
1390 | |
1391 | unsigned int Size = m_pLayers->Map()->GetDataSize(Index: DataIndex); |
1392 | if(Size >= pTMap->m_Width * pTMap->m_Height * TileSize) |
1393 | { |
1394 | TileLayerCounter += TileLayerAndOverlayCount; |
1395 | } |
1396 | } |
1397 | else if(pLayer->m_Type == LAYERTYPE_QUADS) |
1398 | { |
1399 | ++QuadLayerCounter; |
1400 | } |
1401 | } |
1402 | |
1403 | TileLayerCount += TileLayerCounter; |
1404 | QuadLayerCount += QuadLayerCounter; |
1405 | } |
1406 | |
1407 | void CMapLayers::OnRender() |
1408 | { |
1409 | if(m_OnlineOnly && Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK) |
1410 | return; |
1411 | |
1412 | CUIRect Screen; |
1413 | Graphics()->GetScreen(pTopLeftX: &Screen.x, pTopLeftY: &Screen.y, pBottomRightX: &Screen.w, pBottomRightY: &Screen.h); |
1414 | |
1415 | vec2 Center = GetCurCamera()->m_Center; |
1416 | |
1417 | bool PassedGameLayer = false; |
1418 | int TileLayerCounter = 0; |
1419 | int QuadLayerCounter = 0; |
1420 | |
1421 | for(int g = 0; g < m_pLayers->NumGroups(); g++) |
1422 | { |
1423 | CMapItemGroup *pGroup = m_pLayers->GetGroup(Index: g); |
1424 | |
1425 | if(!pGroup) |
1426 | { |
1427 | dbg_msg(sys: "maplayers" , fmt: "error group was null, group number = %d, total groups = %d" , g, m_pLayers->NumGroups()); |
1428 | dbg_msg(sys: "maplayers" , fmt: "this is here to prevent a crash but the source of this is unknown, please report this for it to get fixed" ); |
1429 | dbg_msg(sys: "maplayers" , fmt: "we need mapname and crc and the map that caused this if possible, and anymore info you think is relevant" ); |
1430 | continue; |
1431 | } |
1432 | |
1433 | if((!g_Config.m_GfxNoclip || m_Type == TYPE_FULL_DESIGN) && pGroup->m_Version >= 2 && pGroup->m_UseClipping) |
1434 | { |
1435 | // set clipping |
1436 | float aPoints[4]; |
1437 | RenderTools()->MapScreenToGroup(CenterX: Center.x, CenterY: Center.y, pGroup: m_pLayers->GameGroup(), Zoom: GetCurCamera()->m_Zoom); |
1438 | Graphics()->GetScreen(pTopLeftX: &aPoints[0], pTopLeftY: &aPoints[1], pBottomRightX: &aPoints[2], pBottomRightY: &aPoints[3]); |
1439 | float x0 = (pGroup->m_ClipX - aPoints[0]) / (aPoints[2] - aPoints[0]); |
1440 | float y0 = (pGroup->m_ClipY - aPoints[1]) / (aPoints[3] - aPoints[1]); |
1441 | float x1 = ((pGroup->m_ClipX + pGroup->m_ClipW) - aPoints[0]) / (aPoints[2] - aPoints[0]); |
1442 | float y1 = ((pGroup->m_ClipY + pGroup->m_ClipH) - aPoints[1]) / (aPoints[3] - aPoints[1]); |
1443 | |
1444 | if(x1 < 0.0f || x0 > 1.0f || y1 < 0.0f || y0 > 1.0f) |
1445 | { |
1446 | //check tile layer count of this group |
1447 | LayersOfGroupCount(pGroup, TileLayerCount&: TileLayerCounter, QuadLayerCount&: QuadLayerCounter, PassedGameLayer); |
1448 | continue; |
1449 | } |
1450 | |
1451 | Graphics()->ClipEnable(x: (int)(x0 * Graphics()->ScreenWidth()), y: (int)(y0 * Graphics()->ScreenHeight()), |
1452 | w: (int)((x1 - x0) * Graphics()->ScreenWidth()), h: (int)((y1 - y0) * Graphics()->ScreenHeight())); |
1453 | } |
1454 | |
1455 | RenderTools()->MapScreenToGroup(CenterX: Center.x, CenterY: Center.y, pGroup, Zoom: GetCurCamera()->m_Zoom); |
1456 | |
1457 | for(int l = 0; l < pGroup->m_NumLayers; l++) |
1458 | { |
1459 | CMapItemLayer *pLayer = m_pLayers->GetLayer(Index: pGroup->m_StartLayer + l); |
1460 | bool Render = false; |
1461 | bool IsGameLayer = false; |
1462 | bool IsFrontLayer = false; |
1463 | bool IsSwitchLayer = false; |
1464 | bool IsTeleLayer = false; |
1465 | bool IsSpeedupLayer = false; |
1466 | bool IsTuneLayer = false; |
1467 | bool IsEntityLayer = false; |
1468 | |
1469 | if(pLayer == (CMapItemLayer *)m_pLayers->GameLayer()) |
1470 | { |
1471 | IsEntityLayer = IsGameLayer = true; |
1472 | PassedGameLayer = true; |
1473 | } |
1474 | |
1475 | if(pLayer == (CMapItemLayer *)m_pLayers->FrontLayer()) |
1476 | IsEntityLayer = IsFrontLayer = true; |
1477 | |
1478 | if(pLayer == (CMapItemLayer *)m_pLayers->SwitchLayer()) |
1479 | IsEntityLayer = IsSwitchLayer = true; |
1480 | |
1481 | if(pLayer == (CMapItemLayer *)m_pLayers->TeleLayer()) |
1482 | IsEntityLayer = IsTeleLayer = true; |
1483 | |
1484 | if(pLayer == (CMapItemLayer *)m_pLayers->SpeedupLayer()) |
1485 | IsEntityLayer = IsSpeedupLayer = true; |
1486 | |
1487 | if(pLayer == (CMapItemLayer *)m_pLayers->TuneLayer()) |
1488 | IsEntityLayer = IsTuneLayer = true; |
1489 | |
1490 | if(m_Type == -1) |
1491 | Render = true; |
1492 | else if(m_Type <= TYPE_BACKGROUND_FORCE) |
1493 | { |
1494 | if(PassedGameLayer) |
1495 | return; |
1496 | Render = true; |
1497 | |
1498 | if(m_Type == TYPE_BACKGROUND_FORCE) |
1499 | { |
1500 | if(pLayer->m_Type == LAYERTYPE_TILES && !g_Config.m_ClBackgroundShowTilesLayers) |
1501 | continue; |
1502 | } |
1503 | } |
1504 | else if(m_Type == TYPE_FOREGROUND) |
1505 | { |
1506 | if(PassedGameLayer && !IsGameLayer) |
1507 | Render = true; |
1508 | } |
1509 | else if(m_Type == TYPE_FULL_DESIGN) |
1510 | { |
1511 | if(!IsGameLayer) |
1512 | Render = true; |
1513 | } |
1514 | |
1515 | if(Render && pLayer->m_Type == LAYERTYPE_TILES && Input()->ModifierIsPressed() && Input()->ShiftIsPressed() && Input()->KeyPress(Key: KEY_KP_0)) |
1516 | { |
1517 | CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; |
1518 | CTile *pTiles = (CTile *)m_pLayers->Map()->GetData(Index: pTMap->m_Data); |
1519 | CServerInfo CurrentServerInfo; |
1520 | Client()->GetServerInfo(pServerInfo: &CurrentServerInfo); |
1521 | char aFilename[IO_MAX_PATH_LENGTH]; |
1522 | str_format(buffer: aFilename, buffer_size: sizeof(aFilename), format: "dumps/tilelayer_dump_%s-%d-%d-%dx%d.txt" , CurrentServerInfo.m_aMap, g, l, pTMap->m_Width, pTMap->m_Height); |
1523 | IOHANDLE File = Storage()->OpenFile(pFilename: aFilename, Flags: IOFLAG_WRITE, Type: IStorage::TYPE_SAVE); |
1524 | if(File) |
1525 | { |
1526 | for(int y = 0; y < pTMap->m_Height; y++) |
1527 | { |
1528 | for(int x = 0; x < pTMap->m_Width; x++) |
1529 | io_write(io: File, buffer: &(pTiles[y * pTMap->m_Width + x].m_Index), size: sizeof(pTiles[y * pTMap->m_Width + x].m_Index)); |
1530 | io_write_newline(io: File); |
1531 | } |
1532 | io_close(io: File); |
1533 | } |
1534 | } |
1535 | |
1536 | if((Render || IsGameLayer) && pLayer->m_Type == LAYERTYPE_TILES) |
1537 | { |
1538 | CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; |
1539 | int DataIndex = 0; |
1540 | unsigned int TileSize = 0; |
1541 | int TileLayerAndOverlayCount = 0; |
1542 | if(IsFrontLayer) |
1543 | { |
1544 | DataIndex = pTMap->m_Front; |
1545 | TileSize = sizeof(CTile); |
1546 | TileLayerAndOverlayCount = 1; |
1547 | } |
1548 | else if(IsSwitchLayer) |
1549 | { |
1550 | DataIndex = pTMap->m_Switch; |
1551 | TileSize = sizeof(CSwitchTile); |
1552 | TileLayerAndOverlayCount = 3; |
1553 | } |
1554 | else if(IsTeleLayer) |
1555 | { |
1556 | DataIndex = pTMap->m_Tele; |
1557 | TileSize = sizeof(CTeleTile); |
1558 | TileLayerAndOverlayCount = 2; |
1559 | } |
1560 | else if(IsSpeedupLayer) |
1561 | { |
1562 | DataIndex = pTMap->m_Speedup; |
1563 | TileSize = sizeof(CSpeedupTile); |
1564 | TileLayerAndOverlayCount = 3; |
1565 | } |
1566 | else if(IsTuneLayer) |
1567 | { |
1568 | DataIndex = pTMap->m_Tune; |
1569 | TileSize = sizeof(CTuneTile); |
1570 | TileLayerAndOverlayCount = 1; |
1571 | } |
1572 | else |
1573 | { |
1574 | DataIndex = pTMap->m_Data; |
1575 | TileSize = sizeof(CTile); |
1576 | TileLayerAndOverlayCount = 1; |
1577 | } |
1578 | |
1579 | unsigned int Size = m_pLayers->Map()->GetDataSize(Index: DataIndex); |
1580 | if(Size >= pTMap->m_Width * pTMap->m_Height * TileSize) |
1581 | { |
1582 | TileLayerCounter += TileLayerAndOverlayCount; |
1583 | } |
1584 | } |
1585 | else if(Render && pLayer->m_Type == LAYERTYPE_QUADS) |
1586 | { |
1587 | ++QuadLayerCounter; |
1588 | } |
1589 | |
1590 | // skip rendering if detail layers if not wanted, or is entity layer and we are a background map |
1591 | if((pLayer->m_Flags & LAYERFLAG_DETAIL && (!g_Config.m_GfxHighDetail && !(m_Type == TYPE_FULL_DESIGN)) && !IsGameLayer) || (m_Type == TYPE_BACKGROUND_FORCE && IsEntityLayer) || (m_Type == TYPE_FULL_DESIGN && IsEntityLayer)) |
1592 | continue; |
1593 | |
1594 | int EntityOverlayVal = g_Config.m_ClOverlayEntities; |
1595 | if(m_Type == TYPE_FULL_DESIGN) |
1596 | EntityOverlayVal = 0; |
1597 | |
1598 | if((Render && EntityOverlayVal < 100 && !IsGameLayer && !IsFrontLayer && !IsSwitchLayer && !IsTeleLayer && !IsSpeedupLayer && !IsTuneLayer) || (EntityOverlayVal && IsGameLayer) || (m_Type == TYPE_BACKGROUND_FORCE)) |
1599 | { |
1600 | if(pLayer->m_Type == LAYERTYPE_TILES) |
1601 | { |
1602 | CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; |
1603 | if(pTMap->m_Image < 0 || pTMap->m_Image >= m_pImages->Num()) |
1604 | { |
1605 | if(!IsGameLayer) |
1606 | Graphics()->TextureClear(); |
1607 | else |
1608 | Graphics()->TextureSet(Texture: m_pImages->GetEntities(EntityLayerType: MAP_IMAGE_ENTITY_LAYER_TYPE_ALL_EXCEPT_SWITCH)); |
1609 | } |
1610 | else |
1611 | Graphics()->TextureSet(Texture: m_pImages->Get(Index: pTMap->m_Image)); |
1612 | |
1613 | CTile *pTiles = (CTile *)m_pLayers->Map()->GetData(Index: pTMap->m_Data); |
1614 | unsigned int Size = m_pLayers->Map()->GetDataSize(Index: pTMap->m_Data); |
1615 | |
1616 | if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTile)) |
1617 | { |
1618 | ColorRGBA Color = IsGameLayer ? ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f) : ColorRGBA(pTMap->m_Color.r / 255.0f, pTMap->m_Color.g / 255.0f, pTMap->m_Color.b / 255.0f, pTMap->m_Color.a / 255.0f); |
1619 | if(IsGameLayer && EntityOverlayVal) |
1620 | Color.a *= EntityOverlayVal / 100.0f; |
1621 | else if(!IsGameLayer && EntityOverlayVal && m_Type != TYPE_BACKGROUND_FORCE) |
1622 | Color.a *= (100 - EntityOverlayVal) / 100.0f; |
1623 | |
1624 | if(!IsGameLayer) |
1625 | { |
1626 | ColorRGBA ColorEnv = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f); |
1627 | EnvelopeEval(TimeOffsetMillis: pTMap->m_ColorEnvOffset, Env: pTMap->m_ColorEnv, Result&: ColorEnv, Channels: 4, pUser: this); |
1628 | Color = Color.Multiply(Other: ColorEnv); |
1629 | } |
1630 | |
1631 | if(!Graphics()->IsTileBufferingEnabled()) |
1632 | { |
1633 | Graphics()->BlendNone(); |
1634 | RenderTools()->RenderTilemap(pTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_OPAQUE); |
1635 | Graphics()->BlendNormal(); |
1636 | |
1637 | // draw kill tiles outside the entity clipping rectangle |
1638 | if(IsGameLayer) |
1639 | { |
1640 | // slow blinking to hint that it's not a part of the map |
1641 | double Seconds = time_get() / (double)time_freq(); |
1642 | ColorRGBA ColorHint = ColorRGBA(1.0f, 1.0f, 1.0f, 0.3 + 0.7 * (1 + std::sin(x: 2 * (double)pi * Seconds / 3)) / 2); |
1643 | RenderTools()->RenderTileRectangle(RectX: -201, RectY: -201, RectW: pTMap->m_Width + 402, RectH: pTMap->m_Height + 402, |
1644 | IndexIn: 0, IndexOut: TILE_DEATH, // display air inside, death outside |
1645 | Scale: 32.0f, Color: Color.Multiply(Other: ColorHint), RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT); |
1646 | } |
1647 | |
1648 | RenderTools()->RenderTilemap(pTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT); |
1649 | } |
1650 | else |
1651 | { |
1652 | Graphics()->BlendNormal(); |
1653 | // draw kill tiles outside the entity clipping rectangle |
1654 | if(IsGameLayer) |
1655 | { |
1656 | // slow blinking to hint that it's not a part of the map |
1657 | double Seconds = time_get() / (double)time_freq(); |
1658 | ColorRGBA ColorHint = ColorRGBA(1.0f, 1.0f, 1.0f, 0.3 + 0.7 * (1.0 + std::sin(x: 2 * (double)pi * Seconds / 3)) / 2); |
1659 | RenderKillTileBorder(LayerIndex: TileLayerCounter - 1, Color: Color.Multiply(Other: ColorHint), pTileLayer: pTMap, pGroup); |
1660 | } |
1661 | RenderTileLayer(LayerIndex: TileLayerCounter - 1, Color, pTileLayer: pTMap, pGroup); |
1662 | } |
1663 | } |
1664 | } |
1665 | else if(pLayer->m_Type == LAYERTYPE_QUADS) |
1666 | { |
1667 | CMapItemLayerQuads *pQLayer = (CMapItemLayerQuads *)pLayer; |
1668 | if(pQLayer->m_Image < 0 || pQLayer->m_Image >= m_pImages->Num()) |
1669 | Graphics()->TextureClear(); |
1670 | else |
1671 | Graphics()->TextureSet(Texture: m_pImages->Get(Index: pQLayer->m_Image)); |
1672 | |
1673 | CQuad *pQuads = (CQuad *)m_pLayers->Map()->GetDataSwapped(Index: pQLayer->m_Data); |
1674 | if(m_Type == TYPE_BACKGROUND_FORCE || m_Type == TYPE_FULL_DESIGN) |
1675 | { |
1676 | if(g_Config.m_ClShowQuads || m_Type == TYPE_FULL_DESIGN) |
1677 | { |
1678 | if(!Graphics()->IsQuadBufferingEnabled()) |
1679 | { |
1680 | Graphics()->BlendNormal(); |
1681 | RenderTools()->ForceRenderQuads(pQuads, NumQuads: pQLayer->m_NumQuads, Flags: LAYERRENDERFLAG_TRANSPARENT, pfnEval: EnvelopeEval, pUser: this, Alpha: 1.f); |
1682 | } |
1683 | else |
1684 | { |
1685 | RenderQuadLayer(LayerIndex: QuadLayerCounter - 1, pQuadLayer: pQLayer, pGroup, Force: true); |
1686 | } |
1687 | } |
1688 | } |
1689 | else |
1690 | { |
1691 | if(!Graphics()->IsQuadBufferingEnabled()) |
1692 | { |
1693 | Graphics()->BlendNormal(); |
1694 | RenderTools()->RenderQuads(pQuads, NumQuads: pQLayer->m_NumQuads, Flags: LAYERRENDERFLAG_TRANSPARENT, pfnEval: EnvelopeEval, pUser: this); |
1695 | } |
1696 | else |
1697 | { |
1698 | RenderQuadLayer(LayerIndex: QuadLayerCounter - 1, pQuadLayer: pQLayer, pGroup, Force: false); |
1699 | } |
1700 | } |
1701 | } |
1702 | } |
1703 | else if(Render && EntityOverlayVal && IsFrontLayer) |
1704 | { |
1705 | CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; |
1706 | Graphics()->TextureSet(Texture: m_pImages->GetEntities(EntityLayerType: MAP_IMAGE_ENTITY_LAYER_TYPE_ALL_EXCEPT_SWITCH)); |
1707 | |
1708 | CTile *pFrontTiles = (CTile *)m_pLayers->Map()->GetData(Index: pTMap->m_Front); |
1709 | unsigned int Size = m_pLayers->Map()->GetDataSize(Index: pTMap->m_Front); |
1710 | |
1711 | if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTile)) |
1712 | { |
1713 | const ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, EntityOverlayVal / 100.0f); |
1714 | if(!Graphics()->IsTileBufferingEnabled()) |
1715 | { |
1716 | Graphics()->BlendNone(); |
1717 | RenderTools()->RenderTilemap(pTiles: pFrontTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_OPAQUE); |
1718 | Graphics()->BlendNormal(); |
1719 | RenderTools()->RenderTilemap(pTiles: pFrontTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT); |
1720 | } |
1721 | else |
1722 | { |
1723 | Graphics()->BlendNormal(); |
1724 | RenderTileLayer(LayerIndex: TileLayerCounter - 1, Color, pTileLayer: pTMap, pGroup); |
1725 | } |
1726 | } |
1727 | } |
1728 | else if(Render && EntityOverlayVal && IsSwitchLayer) |
1729 | { |
1730 | CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; |
1731 | Graphics()->TextureSet(Texture: m_pImages->GetEntities(EntityLayerType: MAP_IMAGE_ENTITY_LAYER_TYPE_SWITCH)); |
1732 | |
1733 | CSwitchTile *pSwitchTiles = (CSwitchTile *)m_pLayers->Map()->GetData(Index: pTMap->m_Switch); |
1734 | unsigned int Size = m_pLayers->Map()->GetDataSize(Index: pTMap->m_Switch); |
1735 | |
1736 | if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CSwitchTile)) |
1737 | { |
1738 | const ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, EntityOverlayVal / 100.0f); |
1739 | if(!Graphics()->IsTileBufferingEnabled()) |
1740 | { |
1741 | Graphics()->BlendNone(); |
1742 | RenderTools()->RenderSwitchmap(pSwitch: pSwitchTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_OPAQUE); |
1743 | Graphics()->BlendNormal(); |
1744 | RenderTools()->RenderSwitchmap(pSwitch: pSwitchTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT); |
1745 | RenderTools()->RenderSwitchOverlay(pSwitch: pSwitchTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Alpha: EntityOverlayVal / 100.0f); |
1746 | } |
1747 | else |
1748 | { |
1749 | Graphics()->BlendNormal(); |
1750 | RenderTileLayer(LayerIndex: TileLayerCounter - 3, Color, pTileLayer: pTMap, pGroup); |
1751 | if(g_Config.m_ClTextEntities) |
1752 | { |
1753 | Graphics()->TextureSet(Texture: m_pImages->GetOverlayBottom()); |
1754 | RenderTileLayer(LayerIndex: TileLayerCounter - 2, Color, pTileLayer: pTMap, pGroup); |
1755 | Graphics()->TextureSet(Texture: m_pImages->GetOverlayTop()); |
1756 | RenderTileLayer(LayerIndex: TileLayerCounter - 1, Color, pTileLayer: pTMap, pGroup); |
1757 | } |
1758 | } |
1759 | } |
1760 | } |
1761 | else if(Render && EntityOverlayVal && IsTeleLayer) |
1762 | { |
1763 | CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; |
1764 | Graphics()->TextureSet(Texture: m_pImages->GetEntities(EntityLayerType: MAP_IMAGE_ENTITY_LAYER_TYPE_ALL_EXCEPT_SWITCH)); |
1765 | |
1766 | CTeleTile *pTeleTiles = (CTeleTile *)m_pLayers->Map()->GetData(Index: pTMap->m_Tele); |
1767 | unsigned int Size = m_pLayers->Map()->GetDataSize(Index: pTMap->m_Tele); |
1768 | |
1769 | if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTeleTile)) |
1770 | { |
1771 | const ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, EntityOverlayVal / 100.0f); |
1772 | if(!Graphics()->IsTileBufferingEnabled()) |
1773 | { |
1774 | Graphics()->BlendNone(); |
1775 | RenderTools()->RenderTelemap(pTele: pTeleTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_OPAQUE); |
1776 | Graphics()->BlendNormal(); |
1777 | RenderTools()->RenderTelemap(pTele: pTeleTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT); |
1778 | RenderTools()->RenderTeleOverlay(pTele: pTeleTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Alpha: EntityOverlayVal / 100.0f); |
1779 | } |
1780 | else |
1781 | { |
1782 | Graphics()->BlendNormal(); |
1783 | RenderTileLayer(LayerIndex: TileLayerCounter - 2, Color, pTileLayer: pTMap, pGroup); |
1784 | if(g_Config.m_ClTextEntities) |
1785 | { |
1786 | Graphics()->TextureSet(Texture: m_pImages->GetOverlayCenter()); |
1787 | RenderTileLayer(LayerIndex: TileLayerCounter - 1, Color, pTileLayer: pTMap, pGroup); |
1788 | } |
1789 | } |
1790 | } |
1791 | } |
1792 | else if(Render && EntityOverlayVal && IsSpeedupLayer) |
1793 | { |
1794 | CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; |
1795 | Graphics()->TextureSet(Texture: m_pImages->GetEntities(EntityLayerType: MAP_IMAGE_ENTITY_LAYER_TYPE_ALL_EXCEPT_SWITCH)); |
1796 | |
1797 | CSpeedupTile *pSpeedupTiles = (CSpeedupTile *)m_pLayers->Map()->GetData(Index: pTMap->m_Speedup); |
1798 | unsigned int Size = m_pLayers->Map()->GetDataSize(Index: pTMap->m_Speedup); |
1799 | |
1800 | if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CSpeedupTile)) |
1801 | { |
1802 | const ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, EntityOverlayVal / 100.0f); |
1803 | if(!Graphics()->IsTileBufferingEnabled()) |
1804 | { |
1805 | Graphics()->BlendNone(); |
1806 | RenderTools()->RenderSpeedupmap(pSpeedup: pSpeedupTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_OPAQUE); |
1807 | Graphics()->BlendNormal(); |
1808 | RenderTools()->RenderSpeedupmap(pSpeedup: pSpeedupTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT); |
1809 | RenderTools()->RenderSpeedupOverlay(pSpeedup: pSpeedupTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Alpha: EntityOverlayVal / 100.0f); |
1810 | } |
1811 | else |
1812 | { |
1813 | Graphics()->BlendNormal(); |
1814 | |
1815 | // draw arrow -- clamp to the edge of the arrow image |
1816 | Graphics()->WrapClamp(); |
1817 | Graphics()->TextureSet(Texture: m_pImages->GetSpeedupArrow()); |
1818 | RenderTileLayer(LayerIndex: TileLayerCounter - 3, Color, pTileLayer: pTMap, pGroup); |
1819 | Graphics()->WrapNormal(); |
1820 | |
1821 | if(g_Config.m_ClTextEntities) |
1822 | { |
1823 | Graphics()->TextureSet(Texture: m_pImages->GetOverlayBottom()); |
1824 | RenderTileLayer(LayerIndex: TileLayerCounter - 2, Color, pTileLayer: pTMap, pGroup); |
1825 | Graphics()->TextureSet(Texture: m_pImages->GetOverlayTop()); |
1826 | RenderTileLayer(LayerIndex: TileLayerCounter - 1, Color, pTileLayer: pTMap, pGroup); |
1827 | } |
1828 | } |
1829 | } |
1830 | } |
1831 | else if(Render && EntityOverlayVal && IsTuneLayer) |
1832 | { |
1833 | CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; |
1834 | Graphics()->TextureSet(Texture: m_pImages->GetEntities(EntityLayerType: MAP_IMAGE_ENTITY_LAYER_TYPE_ALL_EXCEPT_SWITCH)); |
1835 | |
1836 | CTuneTile *pTuneTiles = (CTuneTile *)m_pLayers->Map()->GetData(Index: pTMap->m_Tune); |
1837 | unsigned int Size = m_pLayers->Map()->GetDataSize(Index: pTMap->m_Tune); |
1838 | |
1839 | if(Size >= (size_t)pTMap->m_Width * pTMap->m_Height * sizeof(CTuneTile)) |
1840 | { |
1841 | const ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, EntityOverlayVal / 100.0f); |
1842 | if(!Graphics()->IsTileBufferingEnabled()) |
1843 | { |
1844 | Graphics()->BlendNone(); |
1845 | RenderTools()->RenderTunemap(pTune: pTuneTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_OPAQUE); |
1846 | Graphics()->BlendNormal(); |
1847 | RenderTools()->RenderTunemap(pTune: pTuneTiles, w: pTMap->m_Width, h: pTMap->m_Height, Scale: 32.0f, Color, RenderFlags: TILERENDERFLAG_EXTEND | LAYERRENDERFLAG_TRANSPARENT); |
1848 | } |
1849 | else |
1850 | { |
1851 | Graphics()->BlendNormal(); |
1852 | RenderTileLayer(LayerIndex: TileLayerCounter - 1, Color, pTileLayer: pTMap, pGroup); |
1853 | } |
1854 | } |
1855 | } |
1856 | } |
1857 | if(!g_Config.m_GfxNoclip || m_Type == TYPE_FULL_DESIGN) |
1858 | Graphics()->ClipDisable(); |
1859 | } |
1860 | |
1861 | if(!g_Config.m_GfxNoclip || m_Type == TYPE_FULL_DESIGN) |
1862 | Graphics()->ClipDisable(); |
1863 | |
1864 | // reset the screen like it was before |
1865 | Graphics()->MapScreen(TopLeftX: Screen.x, TopLeftY: Screen.y, BottomRightX: Screen.w, BottomRightY: Screen.h); |
1866 | } |
1867 | |