1 /*
2  *  The ManaPlus Client
3  *  Copyright (C) 2004-2009  The Mana World Development Team
4  *  Copyright (C) 2009-2010  The Mana Developers
5  *  Copyright (C) 2011-2019  The ManaPlus Developers
6  *  Copyright (C) 2019-2021  Andrei Karas
7  *
8  *  This file is part of The ManaPlus Client.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "resources/map/maplayer.h"
25 
26 #include "configuration.h"
27 
28 #include "being/localplayer.h"
29 
30 #include "enums/resources/map/blockmask.h"
31 #include "enums/resources/map/mapitemtype.h"
32 
33 #include "gui/userpalette.h"
34 
35 #ifdef USE_OPENGL
36 #include "utils/foreach.h"
37 #endif  // USE_OPENGL
38 
39 #include "render/graphics.h"
40 
41 #include "resources/image/image.h"
42 
43 #include "resources/map/mapitem.h"
44 #include "resources/map/maprowvertexes.h"
45 #include "resources/map/metatile.h"
46 #include "resources/map/speciallayer.h"
47 
48 #include "debug.h"
49 
MapLayer(const std::string & name,const int x,const int y,const int width,const int height,const bool fringeLayer,const int mask,const int tileCondition)50 MapLayer::MapLayer(const std::string &name,
51                    const int x,
52                    const int y,
53                    const int width,
54                    const int height,
55                    const bool fringeLayer,
56                    const int mask,
57                    const int tileCondition) :
58     mX(x),
59     mY(y),
60     mPixelX(mX * mapTileSize),
61     mPixelY(mY * mapTileSize + mapTileSize),
62     mWidth(width),
63     mHeight(height),
64     mTiles(new TileInfo[mWidth * mHeight]),
65     mDrawLayerFlags(MapType::NORMAL),
66     mSpecialLayer(nullptr),
67     mTempLayer(nullptr),
68     mName(name),
69     mTempRows(),
70     mMask(mask),
71     mTileCondition(tileCondition),
72     mActorsFix(0),
73     mIsFringeLayer(fringeLayer),
74     mHighlightAttackRange(config.getBoolValue("highlightAttackRange")),
75     mSpecialFlag(true)
76 {
77 //    std::fill_n(mTiles, mWidth * mHeight, static_cast<Image*>(nullptr));
78 
79     config.addListener("highlightAttackRange", this);
80 }
81 
~MapLayer()82 MapLayer::~MapLayer()
83 {
84     config.removeListener("highlightAttackRange", this);
85     CHECKLISTENERS
86     delete []mTiles;
87     delete_all(mTempRows);
88     mTempRows.clear();
89 }
90 
optionChanged(const std::string & value)91 void MapLayer::optionChanged(const std::string &value) restrict
92 {
93     if (value == "highlightAttackRange")
94     {
95         mHighlightAttackRange =
96             config.getBoolValue("highlightAttackRange");
97     }
98 }
99 
draw(Graphics * const graphics,int startX,int startY,int endX,int endY,const int scrollX,const int scrollY) const100 void MapLayer::draw(Graphics *const graphics,
101                     int startX,
102                     int startY,
103                     int endX,
104                     int endY,
105                     const int scrollX,
106                     const int scrollY) const restrict
107 {
108     BLOCK_START("MapLayer::draw")
109     startX -= mX;
110     startY -= mY;
111     endX -= mX;
112     endY -= mY;
113 
114     if (startX < 0)
115         startX = 0;
116     if (startY < 0)
117         startY = 0;
118     if (endX > mWidth)
119         endX = mWidth;
120     if (endY > mHeight)
121         endY = mHeight;
122 
123     const int dx = mPixelX - scrollX;
124     const int dy = mPixelY - scrollY;
125     for (int y = startY; y < endY; y++)
126     {
127         const int y32 = y * mapTileSize;
128         const int yWidth = y * mWidth;
129 
130         const int py0 = y32 + dy;
131 
132         int x0 = startX;
133         TileInfo *tilePtr = &mTiles[CAST_SIZE(x0 + yWidth)];
134         if (tilePtr->isEnabled == false)
135         {
136             if (x0 + tilePtr->nextTile + 1 >= endX)
137             {
138                 continue;
139             }
140             x0 += tilePtr->nextTile + 1;
141             tilePtr = &mTiles[CAST_SIZE(x0 + yWidth)];
142             if (mTiles[x0 + yWidth].isEnabled == false)
143             {
144                 continue;
145             }
146         }
147         for (int x = x0; x < endX; x++, tilePtr++)
148         {
149             const int x32 = x * mapTileSize;
150 
151             const Image *const img = tilePtr->image;
152             const int px = x32 + dx;
153             const int py = py0 - img->mBounds.h;
154             if (mSpecialFlag ||
155                 img->mBounds.h <= mapTileSize)
156             {
157                 if (tilePtr->count == 0)
158                 {
159                     graphics->drawImage(img, px, py);
160                 }
161                 else
162                 {
163                     graphics->drawPattern(img,
164                         px,
165                         py,
166                         tilePtr->width,
167                         img->mBounds.h);
168                 }
169             }
170 
171             const int nextTile = tilePtr->nextTile;
172             x += nextTile;
173             tilePtr += nextTile;
174         }
175     }
176     BLOCK_END("MapLayer::draw")
177 }
178 
drawSDL(Graphics * const graphics) const179 void MapLayer::drawSDL(Graphics *const graphics) const restrict2
180 {
181     BLOCK_START("MapLayer::drawSDL")
182     MapRows::const_iterator rit = mTempRows.begin();
183     const MapRows::const_iterator rit_end = mTempRows.end();
184     while (rit != rit_end)
185     {
186         MapRowImages *const images = &(*rit)->images;
187         MapRowImages::const_iterator iit = images->begin();
188         const MapRowImages::const_iterator iit_end = images->end();
189         while (iit != iit_end)
190         {
191             graphics->drawTileVertexes(*iit);
192             ++ iit;
193         }
194         ++ rit;
195     }
196     BLOCK_END("MapLayer::drawSDL")
197 }
198 
199 #ifdef USE_OPENGL
updateSDL(const Graphics * const graphics,int startX,int startY,int endX,int endY,const int scrollX,const int scrollY)200 void MapLayer::updateSDL(const Graphics *const graphics,
201                          int startX,
202                          int startY,
203                          int endX,
204                          int endY,
205                          const int scrollX,
206                          const int scrollY) restrict2
207 {
208     BLOCK_START("MapLayer::updateSDL")
209     delete_all(mTempRows);
210     mTempRows.clear();
211 
212     startX -= mX;
213     startY -= mY;
214     endX -= mX;
215     endY -= mY;
216 
217     if (startX < 0)
218         startX = 0;
219     if (startY < 0)
220         startY = 0;
221     if (endX > mWidth)
222         endX = mWidth;
223     if (endY > mHeight)
224         endY = mHeight;
225 
226     const int dx = mPixelX - scrollX;
227     const int dy = mPixelY - scrollY;
228 
229     for (int y = startY; y < endY; y++)
230     {
231         MapRowVertexes *const row = new MapRowVertexes;
232         mTempRows.push_back(row);
233 
234         const Image *lastImage = nullptr;
235         ImageVertexes *imgVert = nullptr;
236 
237         const int yWidth = y * mWidth;
238         const int py0 = y * mapTileSize + dy;
239         TileInfo *tilePtr = &mTiles[CAST_SIZE(startX + yWidth)];
240 
241         for (int x = startX; x < endX; x++, tilePtr++)
242         {
243             if (!tilePtr->isEnabled)
244                 continue;
245             Image *const img = (*tilePtr).image;
246             const int px = x * mapTileSize + dx;
247             const int py = py0 - img->mBounds.h;
248             if (mSpecialFlag ||
249                 img->mBounds.h <= mapTileSize)
250             {
251                 if (lastImage != img)
252                 {
253                     imgVert = new ImageVertexes;
254                     imgVert->image = img;
255                     row->images.push_back(imgVert);
256                     lastImage = img;
257                 }
258                 graphics->calcTileSDL(imgVert, px, py);
259             }
260         }
261     }
262     BLOCK_END("MapLayer::updateSDL")
263 }
264 
updateOGL(Graphics * const graphics,int startX,int startY,int endX,int endY,const int scrollX,const int scrollY)265 void MapLayer::updateOGL(Graphics *const graphics,
266                          int startX,
267                          int startY,
268                          int endX,
269                          int endY,
270                          const int scrollX,
271                          const int scrollY) restrict2
272 {
273     BLOCK_START("MapLayer::updateOGL")
274     delete_all(mTempRows);
275     mTempRows.clear();
276 
277     startX -= mX;
278     startY -= mY;
279     endX -= mX;
280     endY -= mY;
281 
282     if (startX < 0)
283         startX = 0;
284     if (startY < 0)
285         startY = 0;
286     if (endX > mWidth)
287         endX = mWidth;
288     if (endY > mHeight)
289         endY = mHeight;
290 
291     const int dx = mPixelX - scrollX;
292     const int dy = mPixelY - scrollY;
293 
294     MapRowVertexes *const row = new MapRowVertexes;
295     mTempRows.push_back(row);
296     Image *lastImage = nullptr;
297     ImageVertexes *imgVert = nullptr;
298     typedef std::map<int, ImageVertexes*> ImageVertexesMap;
299     ImageVertexesMap imgSet;
300 
301     for (int y = startY; y < endY; y++)
302     {
303         const int yWidth = y * mWidth;
304         const int py0 = y * mapTileSize + dy;
305         TileInfo *tilePtr = &mTiles[CAST_SIZE(startX + yWidth)];
306         for (int x = startX; x < endX; x++, tilePtr++)
307         {
308             if (!tilePtr->isEnabled)
309                 continue;
310             Image *const img = (*tilePtr).image;
311             const int px = x * mapTileSize + dx;
312             const int py = py0 - img->mBounds.h;
313             const GLuint imgGlImage = img->mGLImage;
314             if (mSpecialFlag ||
315                 img->mBounds.h <= mapTileSize)
316             {
317                 if ((lastImage == nullptr) ||
318                     lastImage->mGLImage != imgGlImage)
319                 {
320                     if (img->mBounds.w > mapTileSize)
321                         imgSet.clear();
322 
323                     if (imgSet.find(imgGlImage) != imgSet.end())
324                     {
325                         imgVert = imgSet[imgGlImage];
326                     }
327                     else
328                     {
329                         if (lastImage != nullptr)
330                             imgSet[lastImage->mGLImage] = imgVert;
331                         imgVert = new ImageVertexes;
332                         imgVert->ogl.init();
333                         imgVert->image = img;
334                         row->images.push_back(imgVert);
335                     }
336                 }
337                 lastImage = img;
338                 graphics->calcTileVertexes(imgVert, lastImage, px, py);
339             }
340         }
341     }
342     FOR_EACH (MapRowImages::iterator, it, row->images)
343     {
344         graphics->finalize(*it);
345     }
346     BLOCK_END("MapLayer::updateOGL")
347 }
348 
drawOGL(Graphics * const graphics) const349 void MapLayer::drawOGL(Graphics *const graphics) const restrict2
350 {
351     BLOCK_START("MapLayer::drawOGL")
352     MapRows::const_iterator rit = mTempRows.begin();
353     const MapRows::const_iterator rit_end = mTempRows.end();
354     while (rit != rit_end)
355     {
356         const MapRowImages *const images = &(*rit)->images;
357         MapRowImages::const_iterator iit = images->begin();
358         const MapRowImages::const_iterator iit_end = images->end();
359         while (iit != iit_end)
360         {
361             graphics->drawTileVertexes(*iit);
362             ++ iit;
363         }
364         ++ rit;
365     }
366     BLOCK_END("MapLayer::drawOGL")
367 }
368 #endif  // USE_OPENGL
369 
drawSpecialLayer(Graphics * const graphics,const int y,const int startX,const int endX,const int scrollX,const int scrollY) const370 void MapLayer::drawSpecialLayer(Graphics *const graphics,
371                                 const int y,
372                                 const int startX,
373                                 const int endX,
374                                 const int scrollX,
375                                 const int scrollY) const restrict
376 {
377     const int y32 = y * mapTileSize;
378     const int py1 = y32 - scrollY;
379     int endX1 = endX;
380     int specialWidth = mSpecialLayer->mWidth;
381     int ptr = y * specialWidth;
382     if (endX1 > specialWidth)
383         endX1 = specialWidth;
384     if (endX1 < 0)
385         endX1 = 0;
386     int x0 = startX;
387     const MapItem *item0 = mSpecialLayer->mTiles[ptr + startX];
388     if ((item0 == nullptr) || item0->mType == MapItemType::EMPTY)
389     {
390         x0 += mSpecialLayer->mCache[ptr + startX] + 1;
391     }
392     for (int x = x0; x < endX1; x++)
393     {
394         const int px1 = x * mapTileSize - scrollX;
395         const MapItem *const item = mSpecialLayer->mTiles[ptr + x];
396         if (item != nullptr)
397         {
398             item->draw(graphics, px1, py1,
399                 mapTileSize, mapTileSize);
400         }
401         x += mSpecialLayer->mCache[ptr + x];
402     }
403 
404     x0 = startX;
405     specialWidth = mTempLayer->mWidth;
406     ptr = y * specialWidth;
407     endX1 = endX;
408     if (endX1 > specialWidth)
409         endX1 = specialWidth;
410     item0 = mTempLayer->mTiles[ptr + startX];
411     if ((item0 == nullptr) || item0->mType == MapItemType::EMPTY)
412     {
413         x0 += mTempLayer->mCache[ptr + startX] + 1;
414     }
415     for (int x = x0; x < endX1; x++)
416     {
417         const int px1 = x * mapTileSize - scrollX;
418         const MapItem *const item = mTempLayer->mTiles[ptr + x];
419         item->draw(graphics, px1, py1,
420             mapTileSize, mapTileSize);
421         x += mTempLayer->mCache[ptr + x];
422     }
423 }
424 
drawFringe(Graphics * const graphics,int startX,int startY,int endX,int endY,const int scrollX,const int scrollY,const Actors & actors) const425 void MapLayer::drawFringe(Graphics *const graphics,
426                           int startX,
427                           int startY,
428                           int endX,
429                           int endY,
430                           const int scrollX,
431                           const int scrollY,
432                           const Actors &actors) const restrict
433 {
434     BLOCK_START("MapLayer::drawFringe")
435     if ((localPlayer == nullptr) ||
436         (mSpecialLayer == nullptr) ||
437         (mTempLayer == nullptr))
438     {
439         BLOCK_END("MapLayer::drawFringe")
440         return;
441     }
442 
443     startX -= mX;
444     startY -= mY;
445     endX -= mX;
446     endY -= mY;
447 
448     if (startX < 0)
449         startX = 0;
450     if (startY < 0)
451         startY = 0;
452     if (endX > mWidth)
453         endX = mWidth;
454     if (endY > mHeight)
455         endY = mHeight;
456 
457     ActorsCIter ai = actors.begin();
458     const ActorsCIter ai_end = actors.end();
459 
460     const int dx = mPixelX - scrollX;
461     const int dy = mPixelY - scrollY;
462 
463     const int specialHeight = mSpecialLayer->mHeight;
464 
465     const bool flag = mDrawLayerFlags == MapType::SPECIAL3 ||
466         mDrawLayerFlags == MapType::SPECIAL4 ||
467         mDrawLayerFlags == MapType::BLACKWHITE;
468 
469     const int minEndY = std::min(specialHeight, endY);
470 
471     if (flag)
472     {   // flag
473         for (int y = startY; y < minEndY; y ++)
474         {
475             const int y32s = (y + mActorsFix) * mapTileSize;
476 
477             BLOCK_START("MapLayer::drawFringe drawmobs")
478             // If drawing the fringe layer, make sure all actors above this
479             // row of tiles have been drawn
480             while (ai != ai_end && (*ai)->getSortPixelY() <= y32s)
481             {
482                 (*ai)->draw(graphics, -scrollX, -scrollY);
483                 ++ ai;
484             }
485             BLOCK_END("MapLayer::drawFringe drawmobs")
486 
487             // remove this condition, because it always true
488             if (y < specialHeight)
489             {
490                 drawSpecialLayer(graphics,
491                     y,
492                     startX,
493                     endX,
494                     scrollX,
495                     scrollY);
496             }
497         }
498 
499         for (int y = minEndY; y < endY; y++)
500         {
501             const int y32s = (y + mActorsFix) * mapTileSize;
502 
503             BLOCK_START("MapLayer::drawFringe drawmobs")
504             // If drawing the fringe layer, make sure all actors above this
505             // row of tiles have been drawn
506             while (ai != ai_end && (*ai)->getSortPixelY() <= y32s)
507             {
508                 (*ai)->draw(graphics, -scrollX, -scrollY);
509                 ++ ai;
510             }
511             BLOCK_END("MapLayer::drawFringe drawmobs")
512         }
513     }
514     else
515     {   // !flag
516         for (int y = startY; y < minEndY; y ++)
517         {
518             const int y32 = y * mapTileSize;
519             const int y32s = (y + mActorsFix) * mapTileSize;
520             const int yWidth = y * mWidth;
521 
522             BLOCK_START("MapLayer::drawFringe drawmobs")
523             // If drawing the fringe layer, make sure all actors above this
524             // row of tiles have been drawn
525             while (ai != ai_end &&
526                    (*ai)->getSortPixelY() <= y32s)
527             {
528                 (*ai)->draw(graphics, -scrollX, -scrollY);
529                 ++ ai;
530             }
531             BLOCK_END("MapLayer::drawFringe drawmobs")
532 
533             const int py0 = y32 + dy;
534 
535             int x0 = startX;
536             TileInfo *tilePtr = &mTiles[CAST_SIZE(x0 + yWidth)];
537             if (tilePtr->isEnabled == false)
538             {
539                 drawSpecialLayer(graphics,
540                     y,
541                     0,
542                     std::min(x0 + tilePtr->nextTile + 1, endX),
543                     scrollX,
544                     scrollY);
545                 if (x0 + tilePtr->nextTile + 1 >= endX)
546                 {
547                     continue;
548                 }
549                 x0 += tilePtr->nextTile + 1;
550                 tilePtr = &mTiles[CAST_SIZE(x0 + yWidth)];
551                 if (mTiles[x0 + yWidth].isEnabled == false)
552                     continue;
553             }
554             for (int x = x0; x < endX; x++, tilePtr++)
555             {
556                 const int x32 = x * mapTileSize;
557                 const Image *const img = tilePtr->image;
558                 if (mSpecialFlag ||
559                     img->mBounds.h <= mapTileSize)
560                 {
561                     const int px = x32 + dx;
562                     const int py = py0 - img->mBounds.h;
563 
564                     if (tilePtr->count == 0)
565                     {
566                         graphics->drawImage(img, px, py);
567                     }
568                     else
569                     {
570                         graphics->drawPattern(img,
571                             px,
572                             py,
573                             tilePtr->width,
574                             img->mBounds.h);
575                     }
576                 }
577 
578                 const int nextTile = tilePtr->nextTile;
579                 // remove this condition, because it always true
580                 if (y < specialHeight)
581                 {
582                     drawSpecialLayer(graphics,
583                         y,
584                         x,
585                         std::min(x + nextTile + 1, endX),
586                         scrollX,
587                         scrollY);
588                 }
589                 x += nextTile;
590                 tilePtr += nextTile;
591             }
592         }
593 
594         for (int y = minEndY; y < endY; y++)
595         {
596             const int y32 = y * mapTileSize;
597             const int y32s = (y + mActorsFix) * mapTileSize;
598             const int yWidth = y * mWidth;
599 
600             BLOCK_START("MapLayer::drawFringe drawmobs")
601             // If drawing the fringe layer, make sure all actors above this
602             // row of tiles have been drawn
603             while (ai != ai_end && (*ai)->getSortPixelY() <= y32s)
604             {
605                 (*ai)->draw(graphics, -scrollX, -scrollY);
606                 ++ ai;
607             }
608             BLOCK_END("MapLayer::drawFringe drawmobs")
609 
610             const int py0 = y32 + dy;
611 
612             int x0 = startX;
613             TileInfo *tilePtr = &mTiles[CAST_SIZE(x0 + yWidth)];
614             if (tilePtr->isEnabled == false)
615             {
616                 if (x0 + tilePtr->nextTile + 1 >= endX)
617                     continue;
618                 x0 += tilePtr->nextTile + 1;
619                 tilePtr = &mTiles[CAST_SIZE(x0 + yWidth)];
620                 if (mTiles[x0 + yWidth].isEnabled == false)
621                     continue;
622             }
623             for (int x = x0; x < endX; x++, tilePtr++)
624             {
625                 const int x32 = x * mapTileSize;
626                 const Image *const img = tilePtr->image;
627                 const int px = x32 + dx;
628                 const int py = py0 - img->mBounds.h;
629                 if (mSpecialFlag ||
630                     img->mBounds.h <= mapTileSize)
631                 {
632                     const int c = tilePtr->count;
633 
634                     if (c == 0)
635                     {
636                         graphics->drawImage(img, px, py);
637                     }
638                     else
639                     {
640                         graphics->drawPattern(img,
641                             px,
642                             py,
643                             tilePtr->width,
644                             img->mBounds.h);
645                     }
646                 }
647                 const int nextTile = tilePtr->nextTile;
648                 x += nextTile;
649                 tilePtr += nextTile;
650             }
651         }
652     }  // !flag
653 
654     // Draw any remaining actors
655     if (mDrawLayerFlags != MapType::SPECIAL3 &&
656         mDrawLayerFlags != MapType::SPECIAL4)
657     {
658         BLOCK_START("MapLayer::drawFringe drawmobs")
659         while (ai != ai_end)
660         {
661             (*ai)->draw(graphics, -scrollX, -scrollY);
662             ++ai;
663         }
664         BLOCK_END("MapLayer::drawFringe drawmobs")
665         if (mHighlightAttackRange)
666         {
667             const int px = localPlayer->getPixelX()
668                 - scrollX - mapTileSize / 2;
669             const int py = localPlayer->getPixelY() - scrollY - mapTileSize;
670             const int attackRange = localPlayer->getAttackRange()
671                 * mapTileSize;
672 
673             int x = px - attackRange;
674             int y = py - attackRange;
675             int w = 2 * attackRange + mapTileSize;
676             int h = w;
677             if (attackRange <= mapTileSize)
678             {
679                 x -= mapTileSize / 2;
680                 y -= mapTileSize / 2;
681                 w += mapTileSize;
682                 h += mapTileSize;
683             }
684 
685             if (userPalette != nullptr)
686             {
687                 graphics->setColor(userPalette->getColorWithAlpha(
688                     UserColorId::ATTACK_RANGE));
689                 graphics->fillRectangle(Rect(x, y, w, h));
690                 graphics->setColor(userPalette->getColorWithAlpha(
691                     UserColorId::ATTACK_RANGE_BORDER));
692                 graphics->drawRectangle(Rect(x, y, w, h));
693             }
694         }
695     }
696     BLOCK_END("MapLayer::drawFringe")
697 }
698 
getTileDrawWidth(const TileInfo * restrict tilePtr,const int endX,int & restrict width,int & restrict nextTile)699 int MapLayer::getTileDrawWidth(const TileInfo *restrict tilePtr,
700                                const int endX,
701                                int &restrict width,
702                                int &restrict nextTile)
703 {
704     BLOCK_START("MapLayer::getTileDrawWidth")
705     const Image *const img1 = tilePtr->image;
706     int c = 0;
707     width = img1->mBounds.w;
708     for (int x = 1; x < endX; x++)
709     {
710         tilePtr ++;
711         const Image *const img = tilePtr->image;
712         if (img == nullptr ||
713             tilePtr->isEnabled == false)
714         {
715             break;
716         }
717         if (img != img1)
718         {
719             nextTile = c;
720             BLOCK_END("MapLayer::getTileDrawWidth")
721             return c;
722         }
723         c ++;
724         width += img->mBounds.w;
725     }
726     int c2 = c;
727     for (int x2 = c2 + 1; x2 < endX; x2++)
728     {
729         if (tilePtr->image != nullptr &&
730             tilePtr->isEnabled == true)
731         {
732             break;
733         }
734         c2 ++;
735         tilePtr ++;
736     }
737     nextTile = c2;
738     BLOCK_END("MapLayer::getTileDrawWidth")
739     return c;
740 }
741 
getEmptyTileDrawWidth(const TileInfo * restrict tilePtr,const int endX,int & restrict nextTile)742 int MapLayer::getEmptyTileDrawWidth(const TileInfo *restrict tilePtr,
743                                     const int endX,
744                                     int &restrict nextTile)
745 {
746     BLOCK_START("MapLayer::getEmptyTileDrawWidth")
747     int c = 0;
748     for (int x = 1; x < endX; x++)
749     {
750         tilePtr ++;
751         const Image *const img = tilePtr->image;
752         if (img != nullptr && tilePtr->isEnabled == true)
753             break;
754         c ++;
755     }
756     BLOCK_END("MapLayer::getEmptyTileDrawWidth")
757 
758     nextTile = c;
759     return c;
760 }
761 
updateConditionTiles(const MetaTile * const metaTiles,const int width,const int height)762 void MapLayer::updateConditionTiles(const MetaTile *const metaTiles,
763                                     const int width,
764                                     const int height) restrict
765 {
766     const int width1 = width < mWidth ? width : mWidth;
767     const int height1 = height < mHeight ? height : mHeight;
768 
769     for (int y = mY; y < height1; y ++)
770     {
771         const MetaTile *metaPtr = metaTiles + (y - mY) * width;
772         TileInfo *tilePtr = mTiles + y * mWidth;
773         for (int x = mX; x < width1; x ++, metaPtr ++, tilePtr ++)
774         {
775             if (tilePtr->image != nullptr &&
776                 (((metaPtr->blockmask & mTileCondition) != 0) ||
777                 (metaPtr->blockmask == 0 &&
778                 mTileCondition == BlockMask::GROUND)))
779             {
780                 tilePtr->isEnabled = true;
781             }
782             else
783             {
784                 tilePtr->isEnabled = false;
785             }
786         }
787     }
788 }
789 
updateCache(const int width,const int height)790 void MapLayer::updateCache(const int width,
791                            const int height) restrict
792 {
793     const int width1 = width < mWidth ? width : mWidth;
794     const int height1 = height < mHeight ? height : mHeight;
795 
796     for (int y = mY; y < height1; y ++)
797     {
798         for (int x = mX; x < width1; x ++)
799         {
800             TileInfo *tilePtr = mTiles + y * mWidth + x;
801             int nextTile = 0;
802             if (tilePtr->image == nullptr || tilePtr->isEnabled == false)
803             {
804                 tilePtr->isEnabled = false;
805                 tilePtr->count = getEmptyTileDrawWidth(tilePtr,
806                     width1 - x,
807                     nextTile);
808                 tilePtr->width = 0;
809             }
810             else
811             {
812                 int tileWidth = 0;
813                 tilePtr->count = getTileDrawWidth(tilePtr,
814                     width1 - x,
815                     tileWidth,
816                     nextTile);
817                 tilePtr->width = tileWidth;
818             }
819             tilePtr->nextTile = nextTile;
820         }
821     }
822 }
823 
calcMemoryLocal() const824 int MapLayer::calcMemoryLocal() const
825 {
826     return static_cast<int>(sizeof(MapLayer) +
827         sizeof(TileInfo) * mWidth * mHeight +
828         sizeof(MapRowVertexes) * mTempRows.capacity());
829 }
830 
calcMemoryChilds(const int level) const831 int MapLayer::calcMemoryChilds(const int level) const
832 {
833     int sz = 0;
834     if (mSpecialLayer != nullptr)
835         sz += mSpecialLayer->calcMemory(level + 1);
836     if (mTempLayer != nullptr)
837         sz += mTempLayer->calcMemory(level + 1);
838     return sz;
839 }
840