1 /*!
2  *  Copyright (C) 2011-2016  OpenDungeons Team
3  *
4  *  This program is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "gamemap/MiniMapDrawnFull.h"
19 
20 #include "entities/GameEntityType.h"
21 #include "entities/Tile.h"
22 #include "game/Player.h"
23 #include "game/Seat.h"
24 #include "gamemap/GameMap.h"
25 #include "render/ODFrameListener.h"
26 
27 #include <OgrePrerequisites.h>
28 #include <OgreSceneNode.h>
29 #include <OgreTextureManager.h>
30 
31 #include <CEGUI/BasicImage.h>
32 #include <CEGUI/Image.h>
33 #include <CEGUI/ImageManager.h>
34 #include <CEGUI/PropertyHelper.h>
35 #include <CEGUI/RendererModules/Ogre/Renderer.h>
36 #include <CEGUI/Size.h>
37 #include <CEGUI/System.h>
38 #include <CEGUI/Texture.h>
39 #include <CEGUI/Window.h>
40 #include <CEGUI/WindowManager.h>
41 
42 class MiniMapDrawnFullTileStateListener : public TileStateListener
43 {
44 public:
MiniMapDrawnFullTileStateListener(MiniMapDrawnFull & minimap,uint32_t minimapXMin,uint32_t minimapXMax,uint32_t minimapYMin,uint32_t minimapYMax,uint32_t tileXMin,uint32_t tileXMax,uint32_t tileYMin,uint32_t tileYMax)45     MiniMapDrawnFullTileStateListener(MiniMapDrawnFull& minimap,
46             uint32_t minimapXMin, uint32_t minimapXMax, uint32_t minimapYMin,
47             uint32_t minimapYMax, uint32_t tileXMin, uint32_t tileXMax,
48             uint32_t tileYMin, uint32_t tileYMax) :
49         mMinimapXMin(minimapXMin),
50         mMinimapXMax(minimapXMax),
51         mMinimapYMin(minimapYMin),
52         mMinimapYMax(minimapYMax),
53         mTileXMin(tileXMin),
54         mTileXMax(tileXMax),
55         mTileYMin(tileYMin),
56         mTileYMax(tileYMax),
57         mMinimap(minimap)
58     {}
59 
~MiniMapDrawnFullTileStateListener()60     virtual ~MiniMapDrawnFullTileStateListener()
61     {}
62 
tileStateChanged(Tile & tile)63     void tileStateChanged(Tile& tile) override
64     {
65         fireTileStateChanged();
66     }
67 
fireTileStateChanged()68     void fireTileStateChanged()
69     {
70         mMinimap.updateTileState(mMinimapXMin, mMinimapXMax, mMinimapYMin,
71             mMinimapYMax, mTileXMin, mTileXMax, mTileYMin, mTileYMax);
72     }
73 
74     const uint32_t mMinimapXMin;
75     const uint32_t mMinimapXMax;
76     const uint32_t mMinimapYMin;
77     const uint32_t mMinimapYMax;
78     const uint32_t mTileXMin;
79     const uint32_t mTileXMax;
80     const uint32_t mTileYMin;
81     const uint32_t mTileYMax;
82 
83 private:
84     MiniMapDrawnFull& mMinimap;
85 };
86 
87 //! \brief This enum represents the possible values a pixel can have in the minimap.
88 //! If a pixel corresponds to several game tiles, the highest value will be used
89 //! to display the pixel
90 enum class MiniMapDrawnFullPixel
91 {
92     dirtFull,
93     dirtGround,
94     rockFull,
95     rockGround,
96     claimedFull,
97     claimedGround,
98     lava,
99     water,
100     goldFull,
101     goldGround,
102     gemFull,
103     gemGround,
104     pickupEntity,
105     alliedCreature,
106     enemyCreature
107 };
108 
109 namespace
110 {
getPixelValueFromTile(Seat & playerSeat,Tile & tile)111 MiniMapDrawnFullPixel getPixelValueFromTile(Seat& playerSeat, Tile& tile)
112 {
113     MiniMapDrawnFullPixel value = MiniMapDrawnFullPixel::dirtFull;
114     const std::vector<GameEntity*>& entities = tile.getEntitiesInTile();
115     for(GameEntity* entity : entities)
116     {
117         if(entity->getObjectType() == GameEntityType::creature)
118         {
119             if(!entity->getSeat()->isAlliedSeat(&playerSeat))
120             {
121                 if(value < MiniMapDrawnFullPixel::enemyCreature)
122                     value = MiniMapDrawnFullPixel::enemyCreature;
123             }
124             else
125             {
126                 if(value < MiniMapDrawnFullPixel::alliedCreature)
127                     value = MiniMapDrawnFullPixel::alliedCreature;
128             }
129         }
130         else if(entity->tryPickup(&playerSeat))
131         {
132             if(value < MiniMapDrawnFullPixel::pickupEntity)
133                 value = MiniMapDrawnFullPixel::pickupEntity;
134         }
135     }
136 
137     // If something interesting is on the tile, we return the computed value
138     if(value != MiniMapDrawnFullPixel::dirtFull)
139         return value;
140 
141     // Otherwise, we compute a value according to its type
142     switch(tile.getTileVisual())
143     {
144         case TileVisual::lavaGround:
145             value = MiniMapDrawnFullPixel::lava;
146             break;
147         case TileVisual::waterGround:
148             value = MiniMapDrawnFullPixel::water;
149             break;
150         case TileVisual::goldFull:
151             value = MiniMapDrawnFullPixel::goldFull;
152             break;
153         case TileVisual::goldGround:
154             value = MiniMapDrawnFullPixel::goldGround;
155             break;
156         case TileVisual::gemFull:
157             value = MiniMapDrawnFullPixel::gemFull;
158             break;
159         case TileVisual::gemGround:
160             value = MiniMapDrawnFullPixel::gemGround;
161             break;
162         case TileVisual::rockFull:
163             value = MiniMapDrawnFullPixel::rockFull;
164             break;
165         case TileVisual::rockGround:
166             value = MiniMapDrawnFullPixel::rockGround;
167             break;
168         case TileVisual::claimedGround:
169             value = MiniMapDrawnFullPixel::claimedGround;
170             break;
171         case TileVisual::claimedFull:
172             value = MiniMapDrawnFullPixel::claimedFull;
173             break;
174         case TileVisual::dirtGround:
175             value = MiniMapDrawnFullPixel::dirtGround;
176             break;
177         case TileVisual::dirtFull:
178             value = MiniMapDrawnFullPixel::dirtFull;
179             break;
180         default:
181             break;
182     }
183 
184     return value;
185 }
186 
colourFromPixelValue(MiniMapDrawnFullPixel pixelValue,Seat * seatIfClaimed,Ogre::HardwarePixelBufferSharedPtr pixelBuffer,Ogre::PixelBox pixelBox,uint32_t minimapWidth,uint32_t minimapHeight,uint32_t minimapXMin,uint32_t minimapXMax,uint32_t minimapYMin,uint32_t minimapYMax)187 void colourFromPixelValue(MiniMapDrawnFullPixel pixelValue, Seat* seatIfClaimed,
188         Ogre::HardwarePixelBufferSharedPtr pixelBuffer, Ogre::PixelBox pixelBox,
189         uint32_t minimapWidth, uint32_t minimapHeight, uint32_t minimapXMin,
190         uint32_t minimapXMax, uint32_t minimapYMin, uint32_t minimapYMax)
191 {
192     Ogre::uint8 RR = 0x00;
193     Ogre::uint8 GG = 0x00;
194     Ogre::uint8 BB = 0x00;
195     switch(pixelValue)
196     {
197         case MiniMapDrawnFullPixel::enemyCreature:
198         {
199             RR = 0xFF;
200             GG = 0x00;
201             BB = 0x00;
202             break;
203         }
204         case MiniMapDrawnFullPixel::claimedFull:
205         {
206             if(seatIfClaimed == nullptr)
207             {
208                 RR = 0x86;
209                 GG = 0x50;
210                 BB = 0x28;
211             }
212             else
213             {
214                 const Ogre::ColourValue& color = seatIfClaimed->getColorValue();
215                 RR = color.r * 255.0;
216                 GG = color.g * 255.0;
217                 BB = color.b * 255.0;
218             }
219             break;
220         }
221         case MiniMapDrawnFullPixel::claimedGround:
222         {
223             if(seatIfClaimed == nullptr)
224             {
225                 RR = 0x5C;
226                 GG = 0x37;
227                 BB = 0x1B;
228             }
229             else
230             {
231                 const Ogre::ColourValue& color = seatIfClaimed->getColorValue();
232                 RR = color.r * 200.0;
233                 GG = color.g * 200.0;
234                 BB = color.b * 200.0;
235             }
236             break;
237         }
238         case MiniMapDrawnFullPixel::goldFull:
239         {
240             RR = 0xB5;
241             GG = 0xB3;
242             BB = 0x2F;
243             break;
244         }
245         case MiniMapDrawnFullPixel::goldGround:
246         {
247             RR = 0x3B;
248             GG = 0x1D;
249             BB = 0x08;
250             break;
251         }
252         case MiniMapDrawnFullPixel::water:
253         {
254             RR = 0x21;
255             GG = 0x36;
256             BB = 0x7A;
257             break;
258         }
259         case MiniMapDrawnFullPixel::lava:
260         {
261             RR = 0xB2;
262             GG = 0x22;
263             BB = 0x22;
264             break;
265         }
266         case MiniMapDrawnFullPixel::dirtGround:
267         {
268             RR = 0x3B;
269             GG = 0x1D;
270             BB = 0x08;
271             break;
272         }
273         case MiniMapDrawnFullPixel::dirtFull:
274         {
275             RR = 0x5B;
276             GG = 0x2D;
277             BB = 0x0C;
278             break;
279         }
280         case MiniMapDrawnFullPixel::rockGround:
281         {
282             RR = 0x30;
283             GG = 0x30;
284             BB = 0x30;
285             break;
286         }
287         case MiniMapDrawnFullPixel::rockFull:
288         {
289             RR = 0x41;
290             GG = 0x41;
291             BB = 0x41;
292             break;
293         }
294         default:
295         {
296             RR = 0x00;
297             GG = 0x00;
298             BB = 0xFF;
299             break;
300         }
301         case MiniMapDrawnFullPixel::pickupEntity:
302         {
303             RR = 0xDD;
304             GG = 0xDD;
305             BB = 0x12;
306             break;
307         }
308     }
309 
310     pixelBuffer->lock(pixelBox, Ogre::HardwareBuffer::HBL_NORMAL);
311     for(uint32_t x = minimapXMin; x < minimapXMax; ++x)
312     {
313         for(uint32_t y = minimapYMin; y < minimapYMax; ++y)
314         {
315             Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBuffer->getCurrentLock().data) - 1;
316             pDest += (minimapWidth * (minimapHeight - y - 1) * 4);
317             pDest += (x * 4);
318 
319             pDest++; //A, unused, shouldn't be here
320             // this is the order of colors I empirically found out to be working :)
321             *pDest++ = BB;  //B
322             *pDest++ = GG;  //G
323             *pDest++ = RR;  //R
324         }
325     }
326     pixelBuffer->unlock();
327 }
328 }
329 
MiniMapDrawnFull(CEGUI::Window * miniMapWindow)330 MiniMapDrawnFull::MiniMapDrawnFull(CEGUI::Window* miniMapWindow) :
331     mMiniMapWindow(miniMapWindow),
332     mGameMap(*ODFrameListener::getSingleton().getClientGameMap()),
333     mCameraManager(*ODFrameListener::getSingleton().getCameraManager()),
334     mTopLeftCornerX(0),
335     mTopLeftCornerY(0),
336     mWidth(static_cast<unsigned int>(mMiniMapWindow->getPixelSize().d_width)),
337     mHeight(static_cast<unsigned int>(mMiniMapWindow->getPixelSize().d_height)),
338     mPixelBox(mWidth, mHeight, 1, Ogre::PF_R8G8B8),
339     mMiniMapOgreTexture(Ogre::TextureManager::getSingletonPtr()->createManual(
340             "miniMapOgreTexture",
341             Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
342             Ogre::TEX_TYPE_2D,
343             mWidth, mHeight, 0, Ogre::PF_R8G8B8,
344             Ogre::TU_DYNAMIC_WRITE_ONLY)),
345     mPixelBuffer(mMiniMapOgreTexture->getBuffer())
346 {
347     uint32_t tileXMax = mGameMap.getMapSizeX();
348     uint32_t tileYMax = mGameMap.getMapSizeY();
349     uint32_t tileX = 0;
350     uint32_t tileY = 0;
351     uint32_t mapX = 0;
352     uint32_t mapY = 0;
353 
354     Ogre::Real gainX = static_cast<Ogre::Real>(mWidth) / static_cast<Ogre::Real>(tileXMax);
355     Ogre::Real gainY = static_cast<Ogre::Real>(mHeight) / static_cast<Ogre::Real>(tileYMax);
356 
357     while((mapX < mWidth) && (mapY < mHeight) && (tileX < tileXMax) && (tileY < tileYMax))
358     {
359         uint32_t tileXNext = static_cast<uint32_t>(round(static_cast<Ogre::Real>(mapX + 1) / gainX));
360         uint32_t tileYNext = static_cast<uint32_t>(round(static_cast<Ogre::Real>(mapY + 1) / gainY));
361         uint32_t mapXNext = static_cast<uint32_t>(round(static_cast<Ogre::Real>(tileX + 1) * gainX));
362         uint32_t mapYNext = static_cast<uint32_t>(round(static_cast<Ogre::Real>(tileY + 1) * gainY));
363 
364         if(tileXNext == tileX)
365             ++tileXNext;
366         if(tileYNext == tileY)
367             ++tileYNext;
368         if(mapXNext == mapX)
369             ++mapXNext;
370         if(mapYNext == mapY)
371             ++mapYNext;
372 
373         MiniMapDrawnFullTileStateListener* listener = new MiniMapDrawnFullTileStateListener(*this,
374             mapX, mapXNext, mapY, mapYNext, tileX, tileXNext, tileY, tileYNext);
375 
376         mTileStateListeners.push_back(listener);
377 
378         mapX = mapXNext;
379         tileX = tileXNext;
380         if(tileXNext >= tileXMax)
381         {
382             mapY = mapYNext;
383             tileY = tileYNext;
384             mapX = 0;
385             tileX = 0;
386         }
387     }
388 
389     // It  start, we fire the tile state changed event to make sure every pixel is
390     // correctly initialized. We also set the listeners on the tiles
391     for(MiniMapDrawnFullTileStateListener* listener : mTileStateListeners)
392     {
393         for(uint32_t xxx = listener->mTileXMin; xxx < listener->mTileXMax; ++xxx)
394         {
395             for(uint32_t yyy = listener->mTileYMin; yyy < listener->mTileYMax; ++yyy)
396             {
397                 Tile* tile = mGameMap.getTile(xxx, yyy);
398                 if(tile == nullptr)
399                     continue;
400 
401                 tile->addTileStateListener(*listener);
402             }
403         }
404 
405         listener->fireTileStateChanged();
406     }
407 
408     CEGUI::Texture& miniMapTextureGui = static_cast<CEGUI::OgreRenderer*>(CEGUI::System::getSingletonPtr()
409                                             ->getRenderer())->createTexture("miniMapTextureGui", mMiniMapOgreTexture);
410 
411     CEGUI::BasicImage& imageset = dynamic_cast<CEGUI::BasicImage&>(CEGUI::ImageManager::getSingletonPtr()->create("BasicImage", "MiniMapImageset"));
412     imageset.setArea(CEGUI::Rectf(CEGUI::Vector2f(0.0, 0.0),
413                                       CEGUI::Size<float>(
414                                           static_cast<float>(mWidth), static_cast<float>(mHeight)
415                                       )
416                                   ));
417 
418     // Link the image to the minimap
419     imageset.setTexture(&miniMapTextureGui);
420     mMiniMapWindow->setProperty("Image", CEGUI::PropertyHelper<CEGUI::Image*>::toString(&imageset));
421 
422     mMiniMapOgreTexture->load();
423 
424     mTopLeftCornerX = mMiniMapWindow->getUnclippedOuterRect().get().getPosition().d_x;
425     mTopLeftCornerY = mMiniMapWindow->getUnclippedOuterRect().get().getPosition().d_y;
426 }
427 
~MiniMapDrawnFull()428 MiniMapDrawnFull::~MiniMapDrawnFull()
429 {
430     for(MiniMapDrawnFullTileStateListener* listener : mTileStateListeners)
431     {
432         for(uint32_t xxx = listener->mTileXMin; xxx < listener->mTileXMax; ++xxx)
433         {
434             for(uint32_t yyy = listener->mTileYMin; yyy < listener->mTileYMax; ++yyy)
435             {
436                 Tile* tile = mGameMap.getTile(xxx, yyy);
437                 if(tile == nullptr)
438                     continue;
439 
440                 tile->removeTileStateListener(*listener);
441             }
442         }
443         delete listener;
444     }
445     mTileStateListeners.clear();
446 
447     mMiniMapWindow->setProperty("Image", "");
448     Ogre::TextureManager::getSingletonPtr()->remove("miniMapOgreTexture");
449     CEGUI::ImageManager::getSingletonPtr()->destroy("MiniMapImageset");
450     CEGUI::System::getSingletonPtr()->getRenderer()->destroyTexture("miniMapTextureGui");
451 }
452 
camera_2dPositionFromClick(int xx,int yy)453 Ogre::Vector2 MiniMapDrawnFull::camera_2dPositionFromClick(int xx, int yy)
454 {
455     Ogre::Vector2 v(0, 0);
456     Ogre::Real gainX = static_cast<Ogre::Real>(mGameMap.getMapSizeX())
457         / static_cast<Ogre::Real>(mWidth);
458     Ogre::Real gainY = static_cast<Ogre::Real>(mGameMap.getMapSizeY())
459         / static_cast<Ogre::Real>(mHeight);
460 
461     v.x = round(static_cast<Ogre::Real>(xx - mTopLeftCornerX) * gainX);
462     v.y = round(static_cast<Ogre::Real>(mHeight - yy + mTopLeftCornerY) * gainY);
463 
464     return v;
465 }
466 
updateTileState(uint32_t minimapXMin,uint32_t minimapXMax,uint32_t minimapYMin,uint32_t minimapYMax,uint32_t tileXMin,uint32_t tileXMax,uint32_t tileYMin,uint32_t tileYMax)467 void MiniMapDrawnFull::updateTileState(uint32_t minimapXMin, uint32_t minimapXMax,
468         uint32_t minimapYMin, uint32_t minimapYMax, uint32_t tileXMin,
469         uint32_t tileXMax, uint32_t tileYMin, uint32_t tileYMax)
470 {
471     Seat& localPlayerSeat = *(mGameMap.getLocalPlayer()->getSeat());
472     // We compute the tile representation
473     MiniMapDrawnFullPixel curValue = MiniMapDrawnFullPixel::dirtFull;
474     Seat* seatIfClaimed = nullptr;
475     for(uint32_t xxx = tileXMin; xxx < tileXMax; ++xxx)
476     {
477         for(uint32_t yyy = tileYMin; yyy < tileYMax; ++yyy)
478         {
479             Tile* tile = mGameMap.getTile(xxx, yyy);
480             if(tile == nullptr)
481                 continue;
482 
483             MiniMapDrawnFullPixel value = getPixelValueFromTile(localPlayerSeat,
484                 *tile);
485             if(value > curValue)
486             {
487                 curValue = value;
488                 switch(value)
489                 {
490                     case MiniMapDrawnFullPixel::claimedGround:
491                     case MiniMapDrawnFullPixel::claimedFull:
492                         seatIfClaimed = tile->getSeat();
493                         break;
494                     default:
495                         break;
496                 }
497             }
498         }
499     }
500 
501     // We paint corresponding pixels
502     colourFromPixelValue(curValue, seatIfClaimed, mPixelBuffer, mPixelBox,
503         mWidth, mHeight, minimapXMin, minimapXMax, minimapYMin, minimapYMax);
504 }
505 
crossSegment(const Ogre::Vector3 & p1,const Ogre::Vector3 & p2,uint32_t xMin,uint32_t xMax,uint32_t yMin,uint32_t yMax)506 bool MiniMapDrawnFull::crossSegment(const Ogre::Vector3& p1, const Ogre::Vector3& p2,
507         uint32_t xMin, uint32_t xMax, uint32_t yMin, uint32_t yMax)
508 {
509     if((p1.x < static_cast<Ogre::Real>(xMin)) &&
510        (p2.x < static_cast<Ogre::Real>(xMin)))
511     {
512         return false;
513     }
514     if((p1.x > static_cast<Ogre::Real>(xMax)) &&
515        (p2.x > static_cast<Ogre::Real>(xMax)))
516     {
517         return false;
518     }
519 
520     if((p1.y < static_cast<Ogre::Real>(yMin)) &&
521        (p2.y < static_cast<Ogre::Real>(yMin)))
522     {
523         return false;
524     }
525     if((p1.y > static_cast<Ogre::Real>(yMax)) &&
526        (p2.y > static_cast<Ogre::Real>(yMax)))
527     {
528         return false;
529     }
530 
531     Ogre::Real diffYPoints = p2.y - p1.y;
532     Ogre::Real diffXPoints = p2.x - p1.x;
533     Ogre::Real diffYMin = p2.y - static_cast<Ogre::Real>(yMin);
534     Ogre::Real diffXMin = p2.x - static_cast<Ogre::Real>(xMin);
535     Ogre::Real diffYMax = p2.y - static_cast<Ogre::Real>(yMax);
536     Ogre::Real diffXMax = p2.x - static_cast<Ogre::Real>(xMax);
537 
538     // Magic number to change the size of the line
539     static const Ogre::Real DIFF_MIN = 5;
540     if(
541        (
542         (diffYMin * diffXPoints - diffYPoints * diffXMin - DIFF_MIN< 0) &&
543         (diffYMax * diffXPoints - diffYPoints * diffXMax + DIFF_MIN >= 0)
544        ) ||
545        (
546         (diffYMax * diffXPoints - diffYPoints * diffXMax - DIFF_MIN< 0) &&
547         (diffYMin * diffXPoints - diffYPoints * diffXMin + DIFF_MIN >= 0)
548        )
549       )
550     {
551         return true;
552     }
553 
554     return false;
555 }
556 
update(Ogre::Real timeSinceLastFrame,const std::vector<Ogre::Vector3> & cornerTiles)557 void MiniMapDrawnFull::update(Ogre::Real timeSinceLastFrame, const std::vector<Ogre::Vector3>& cornerTiles)
558 {
559     const Ogre::Vector3& topRight = cornerTiles[0];
560     const Ogre::Vector3& topLeft = cornerTiles[1];
561     const Ogre::Vector3& bottomLeft = cornerTiles[2];
562     const Ogre::Vector3& bottomRight = cornerTiles[3];
563 
564     bool isSame = (mLastCornerTiles.size() == cornerTiles.size());
565     static const Ogre::Real squareDiffMin = 0.5;
566     for(uint32_t iii = 0; isSame && iii < mLastCornerTiles.size(); ++iii)
567     {
568         Ogre::Real val = (mLastCornerTiles[iii] - cornerTiles[iii]).squaredLength();
569         isSame &= (val <= squareDiffMin);
570     }
571 
572     if(isSame)
573         return;
574 
575     // We save corner tiles
576     mLastCornerTiles = cornerTiles;
577 
578     // We refresh the old rectangle
579     for(MiniMapDrawnFullTileStateListener* listener : mVisibleRectangle)
580     {
581         listener->fireTileStateChanged();
582     }
583     mVisibleRectangle.clear();
584 
585     // And we paint the new visible rectangle
586     mPixelBuffer->lock(mPixelBox, Ogre::HardwareBuffer::HBL_NORMAL);
587 
588     // we look for the tiles at the border of vision to paint them black
589     for(MiniMapDrawnFullTileStateListener* listener : mTileStateListeners)
590     {
591         bool isInBorder = false;
592 
593         // We check if the listener tiles are on the top line
594         if(!isInBorder &&
595             crossSegment(topRight, topLeft, listener->mTileXMin, listener->mTileXMax,
596                 listener->mTileYMin, listener->mTileYMax))
597         {
598             isInBorder = true;
599         }
600 
601         if(!isInBorder &&
602             crossSegment(topLeft, bottomLeft, listener->mTileXMin, listener->mTileXMax,
603                 listener->mTileYMin, listener->mTileYMax))
604         {
605             isInBorder = true;
606         }
607 
608         if(!isInBorder &&
609             crossSegment(bottomLeft, bottomRight, listener->mTileXMin, listener->mTileXMax,
610                 listener->mTileYMin, listener->mTileYMax))
611         {
612             isInBorder = true;
613         }
614 
615         if(!isInBorder &&
616             crossSegment(bottomRight, topRight, listener->mTileXMin, listener->mTileXMax,
617                 listener->mTileYMin, listener->mTileYMax))
618         {
619             isInBorder = true;
620         }
621 
622         if(!isInBorder)
623             continue;
624 
625         mVisibleRectangle.push_back(listener);
626         for(uint32_t xxx = listener->mMinimapXMin; xxx < listener->mMinimapXMax; ++xxx)
627         {
628             for(uint32_t yyy = listener->mMinimapYMin; yyy < listener->mMinimapYMax; ++yyy)
629             {
630                 Ogre::uint8* pDest = static_cast<Ogre::uint8*>(mPixelBuffer->getCurrentLock().data) - 1;
631                 pDest += (mWidth * (mHeight - yyy - 1) * 4);
632                 pDest += (xxx * 4);
633 
634                 pDest++; //A, unused, shouldn't be here
635                 // this is the order of colors I empirically found out to be working :)
636                 *pDest++ = 0x00;  //B
637                 *pDest++ = 0x00;  //G
638                 *pDest++ = 0x00;  //R
639             }
640         }
641     }
642     mPixelBuffer->unlock();
643 }
644