Otclient 1.0  14/8/2020
minimap.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2020 OTClient <https://github.com/edubart/otclient>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 
24 #include "minimap.h"
25 #include "tile.h"
26 
27 #include <zlib.h>
35 
37 
39 {
40  m_tiles.fill(MinimapTile());
41  m_texture.reset();
42  m_mustUpdate = false;
43 }
44 
46 {
47  if(!m_mustUpdate)
48  return;
49 
51 
52  bool shouldDraw = false;
53  for(int x = 0; x < MMBLOCK_SIZE; ++x) {
54  for(int y = 0; y < MMBLOCK_SIZE; ++y) {
55  const uint8 c = getTile(x, y).color;
56  uint32 col;
57  if(c != 255) {
58  col = Color::from8bit(c).rgba();
59  shouldDraw = true;
60  } else
61  col = Color::alpha.rgba();
62  image->setPixel(x, y, col);
63  }
64  }
65 
66  if(shouldDraw) {
67  if(!m_texture) {
68  m_texture = TexturePtr(new Texture(image, true));
69  } else {
70  m_texture->uploadPixels(image, true);
71  }
72  } else
73  m_texture.reset();
74 
75  m_mustUpdate = false;
76 }
77 
78 void MinimapBlock::updateTile(int x, int y, const MinimapTile& tile)
79 {
80  if(m_tiles[getTileIndex(x, y)].color != tile.color)
81  m_mustUpdate = true;
82 
83  m_tiles[getTileIndex(x, y)] = tile;
84 }
85 
87 {
88 }
89 
91 {
92  clean();
93 }
94 
96 {
97  for(int i = 0; i <= Otc::MAX_Z; ++i)
98  m_tileBlocks[i].clear();
99 }
100 
101 void Minimap::draw(const Rect& screenRect, const Position& mapCenter, float scale, const Color& color)
102 {
103  if(screenRect.isEmpty())
104  return;
105 
106  const Rect mapRect = calcMapRect(screenRect, mapCenter, scale);
107  g_painter->saveState();
108  g_painter->setColor(color);
109  g_painter->drawFilledRect(screenRect);
111  g_painter->setClipRect(screenRect);
112 
113  if(MMBLOCK_SIZE * scale <= 1 || !mapCenter.isMapPosition()) {
115  return;
116  }
117 
118  const Point blockOff = getBlockOffset(mapRect.topLeft());
119  const Point off = Point((mapRect.size() * scale).toPoint() - screenRect.size().toPoint()) / 2;
120  const Point start = screenRect.topLeft() - (mapRect.topLeft() - blockOff) * scale - off;
121 
122  for(int y = blockOff.y, ys = start.y; ys < screenRect.bottom(); y += MMBLOCK_SIZE, ys += MMBLOCK_SIZE * scale) {
123  if(y < 0 || y >= 65536)
124  continue;
125 
126  for(int x = blockOff.x, xs = start.x; xs < screenRect.right(); x += MMBLOCK_SIZE, xs += MMBLOCK_SIZE * scale) {
127  if(x < 0 || x >= 65536)
128  continue;
129 
130  Position blockPos(x, y, mapCenter.z);
131  if(!hasBlock(blockPos))
132  continue;
133 
134  MinimapBlock& block = getBlock(Position(x, y, mapCenter.z));
135  block.update();
136 
137  const TexturePtr& tex = block.getTexture();
138  if(tex) {
139  Rect src(0, 0, MMBLOCK_SIZE, MMBLOCK_SIZE);
140  Rect dest(Point(xs, ys), src.size() * scale);
141 
142  tex->setSmooth(scale < 1.0f);
143  g_painter->drawTexturedRect(dest, tex, src);
144  }
145  //g_painter->drawBoundingRect(Rect(xs,ys, MMBLOCK_SIZE * scale, MMBLOCK_SIZE * scale));
146  }
147  }
148 
150 }
151 
152 Point Minimap::getTilePoint(const Position& pos, const Rect& screenRect, const Position& mapCenter, float scale)
153 {
154  if(screenRect.isEmpty() || pos.z != mapCenter.z)
155  return Point(-1, -1);
156 
157  const Rect mapRect = calcMapRect(screenRect, mapCenter, scale);
158  const Point off = Point((mapRect.size() * scale).toPoint() - screenRect.size().toPoint()) / 2;
159  const Point posoff = (Point(pos.x, pos.y) - mapRect.topLeft()) * scale;
160  return posoff + screenRect.topLeft() - off + (Point(1, 1) * scale) / 2;
161 }
162 
163 Position Minimap::getTilePosition(const Point& point, const Rect& screenRect, const Position& mapCenter, float scale)
164 {
165  if(screenRect.isEmpty())
166  return Position();
167 
168  const Rect mapRect = calcMapRect(screenRect, mapCenter, scale);
169  const Point off = Point((mapRect.size() * scale).toPoint() - screenRect.size().toPoint()) / 2;
170  const Point pos2d = (point - screenRect.topLeft() + off) / scale + mapRect.topLeft();
171  return Position(pos2d.x, pos2d.y, mapCenter.z);
172 }
173 
174 Rect Minimap::getTileRect(const Position& pos, const Rect& screenRect, const Position& mapCenter, float scale)
175 {
176  if(screenRect.isEmpty() || pos.z != mapCenter.z)
177  return Rect();
178 
179  const int tileSize = 32 * scale;
180  Rect tileRect(0, 0, tileSize, tileSize);
181  tileRect.moveCenter(getTilePoint(pos, screenRect, mapCenter, scale));
182  return tileRect;
183 }
184 
185 Rect Minimap::calcMapRect(const Rect& screenRect, const Position& mapCenter, float scale)
186 {
187  const int w = screenRect.width() / scale, h = std::ceil(screenRect.height() / scale);
188  Rect mapRect(0, 0, w, h);
189  mapRect.moveCenter(Point(mapCenter.x, mapCenter.y));
190  return mapRect;
191 }
192 
193 void Minimap::updateTile(const Position& pos, const TilePtr& tile)
194 {
195  MinimapTile minimapTile;
196  if(tile) {
197  minimapTile.color = tile->getMinimapColorByte();
198  minimapTile.flags |= MinimapTileWasSeen;
199  if(!tile->isWalkable(true))
200  minimapTile.flags |= MinimapTileNotWalkable;
201  if(!tile->isPathable())
202  minimapTile.flags |= MinimapTileNotPathable;
203  minimapTile.speed = std::min<int>(static_cast<int>(std::ceil(tile->getGroundSpeed() / 10.0f)), 255);
204  }
205 
206  if(minimapTile != MinimapTile()) {
207  MinimapBlock& block = getBlock(pos);
208  const Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
209  block.updateTile(pos.x - offsetPos.x, pos.y - offsetPos.y, minimapTile);
210  block.justSaw();
211  }
212 }
213 
215 {
216  static MinimapTile nulltile;
217  if(pos.z <= Otc::MAX_Z && hasBlock(pos)) {
218  MinimapBlock& block = getBlock(pos);
219  const Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
220  return block.getTile(pos.x - offsetPos.x, pos.y - offsetPos.y);
221  }
222  return nulltile;
223 }
224 
225 bool Minimap::loadImage(const std::string& fileName, const Position& topLeft, float colorFactor)
226 {
227  if(colorFactor <= 0.01f)
228  colorFactor = 1.0f;
229 
230  try {
231  ImagePtr image = Image::load(fileName);
232 
233  const uint8 waterc = Color::to8bit(std::string("#3300cc"));
234 
235  // non pathable colors
236  Color nonPathableColors[] = {
237  std::string("#ffff00"), // yellow
238  };
239 
240  // non walkable colors
241  Color nonWalkableColors[] = {
242  std::string("#000000"), // oil, black
243  std::string("#006600"), // trees, dark green
244  std::string("#ff3300"), // walls, red
245  std::string("#666666"), // mountain, grey
246  std::string("#ff6600"), // lava, orange
247  std::string("#00ff00"), // positon
248  std::string("#ccffff"), // ice, very light blue
249  };
250 
251  for(int y = 0; y < image->getHeight(); ++y) {
252  for(int x = 0; x < image->getWidth(); ++x) {
253  Color color = *(uint32*)image->getPixel(x, y);
254  uint8 c = Color::to8bit(color * colorFactor);
255  int flags = 0;
256 
257  if(c == waterc || color.a() == 0) {
258  flags |= MinimapTileNotWalkable;
259  c = 255; // alpha
260  }
261 
262  if(flags != 0) {
263  for(Color& col : nonWalkableColors) {
264  if(col == color) {
265  flags |= MinimapTileNotWalkable;
266  break;
267  }
268  }
269  }
270 
271  if(flags != 0) {
272  for(Color& col : nonPathableColors) {
273  if(col == color) {
274  flags |= MinimapTileNotPathable;
275  break;
276  }
277  }
278  }
279 
280  if(c == 255)
281  continue;
282 
283  Position pos(topLeft.x + x, topLeft.y + y, topLeft.z);
284  MinimapBlock& block = getBlock(pos);
285  const Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
286  MinimapTile& tile = block.getTile(pos.x - offsetPos.x, pos.y - offsetPos.y);
287  if(!(tile.flags & MinimapTileWasSeen)) {
288  tile.color = c;
289  tile.flags = flags;
290  block.mustUpdate();
291  }
292  }
293  }
294  return true;
295  } catch(stdext::exception& e) {
296  g_logger.error(stdext::format("failed to load OTMM minimap: %s", e.what()));
297  return false;
298  }
299 }
300 
301 void Minimap::saveImage(const std::string&, const Rect&)
302 {
303  //TODO
304 }
305 
306 bool Minimap::loadOtmm(const std::string& fileName)
307 {
308  try {
309  FileStreamPtr fin = g_resources.openFile(fileName);
310  if(!fin)
311  stdext::throw_exception("unable to open file");
312 
313  fin->cache();
314 
315  const uint32 signature = fin->getU32();
316  if(signature != OTMM_SIGNATURE)
317  stdext::throw_exception("invalid OTMM file");
318 
319  const uint16 start = fin->getU16();
320  const uint16 version = fin->getU16();
321  fin->getU32(); // flags
322 
323  switch(version) {
324  case 1:
325  {
326  fin->getString(); // description
327  break;
328  }
329  default:
330  stdext::throw_exception("OTMM version not supported");
331  }
332 
333  fin->seek(start);
334 
335  const uint blockSize = MMBLOCK_SIZE * MMBLOCK_SIZE * sizeof(MinimapTile);
336  std::vector<uchar> compressBuffer(compressBound(blockSize));
337  std::vector<uchar> decompressBuffer(blockSize);
338 
339  while(true) {
340  Position pos;
341  pos.x = fin->getU16();
342  pos.y = fin->getU16();
343  pos.z = fin->getU8();
344 
345  // end of file or file is corrupted
346  if(!pos.isValid() || pos.z >= Otc::MAX_Z + 1)
347  break;
348 
349  MinimapBlock& block = getBlock(pos);
350  const ulong len = fin->getU16();
351  ulong destLen = blockSize;
352  fin->read(compressBuffer.data(), len);
353  const int ret = uncompress(decompressBuffer.data(), &destLen, compressBuffer.data(), len);
354  if(ret != Z_OK || destLen != blockSize)
355  break;
356 
357  memcpy((uchar*)&block.getTiles(), decompressBuffer.data(), blockSize);
358  block.mustUpdate();
359  block.justSaw();
360  }
361 
362  fin->close();
363  return true;
364  } catch(stdext::exception& e) {
365  g_logger.error(stdext::format("failed to load OTMM minimap: %s", e.what()));
366  return false;
367  }
368 }
369 
370 void Minimap::saveOtmm(const std::string& fileName)
371 {
372  try {
373  stdext::timer saveTimer;
374 
375  FileStreamPtr fin = g_resources.createFile(fileName);
376  fin->cache();
377 
378  //TODO: compression flag with zlib
379  const uint32 flags = 0;
380 
381  // header
382  fin->addU32(OTMM_SIGNATURE);
383  fin->addU16(0); // data start, will be overwritten later
384  fin->addU16(OTMM_VERSION);
385  fin->addU32(flags);
386 
387  // version 1 header
388  fin->addString("OTMM 1.0"); // description
389 
390  // go back and rewrite where the map data starts
391  const uint32 start = fin->tell();
392  fin->seek(4);
393  fin->addU16(start);
394  fin->seek(start);
395 
396  const uint blockSize = MMBLOCK_SIZE * MMBLOCK_SIZE * sizeof(MinimapTile);
397  std::vector<uchar> compressBuffer(compressBound(blockSize));
398  const int COMPRESS_LEVEL = 3;
399 
400  for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
401  for(auto& it : m_tileBlocks[z]) {
402  const int index = it.first;
403  MinimapBlock& block = it.second;
404  if(!block.wasSeen())
405  continue;
406 
407  const Position pos = getIndexPosition(index, z);
408  fin->addU16(pos.x);
409  fin->addU16(pos.y);
410  fin->addU8(pos.z);
411 
412  ulong len = blockSize;
413  const int ret = compress2(compressBuffer.data(), &len, (uchar*)&block.getTiles(), blockSize, COMPRESS_LEVEL);
414  assert(ret == Z_OK);
415  fin->addU16(len);
416  fin->write(compressBuffer.data(), len);
417  }
418  }
419 
420  // end of file
421  const Position invalidPos;
422  fin->addU16(invalidPos.x);
423  fin->addU16(invalidPos.y);
424  fin->addU8(invalidPos.z);
425 
426  fin->flush();
427 
428  fin->close();
429  } catch(stdext::exception& e) {
430  g_logger.error(stdext::format("failed to save OTMM minimap: %s", e.what()));
431  }
432 }
MinimapBlock::mustUpdate
void mustUpdate()
Definition: minimap.h:66
FileStream::write
void write(const void *buffer, uint count)
Definition: filestream.cpp:130
Painter::setColor
virtual void setColor(const Color &color)
Definition: painter.h:77
FileStream::seek
void seek(uint pos)
Definition: filestream.cpp:142
MMBLOCK_SIZE
@ MMBLOCK_SIZE
Definition: minimap.h:31
Painter::restoreSavedState
virtual void restoreSavedState()=0
MinimapBlock::getTile
MinimapTile & getTile(int x, int y)
Definition: minimap.h:61
stdext::timer
Definition: time.h:36
MinimapTileNotPathable
@ MinimapTileNotPathable
Definition: minimap.h:38
Color
Definition: color.h:32
Tile::getGroundSpeed
int getGroundSpeed()
Definition: tile.cpp:376
Minimap::loadOtmm
bool loadOtmm(const std::string &fileName)
Definition: minimap.cpp:306
TPoint::y
T y
Definition: point.h:83
MinimapBlock::update
void update()
Definition: minimap.cpp:45
FileStream::close
void close()
Definition: filestream.cpp:78
z
gc sort z
Definition: CMakeLists.txt:176
TRect< int >
FileStream::addU32
void addU32(uint32 v)
Definition: filestream.cpp:377
Position::x
int x
Definition: position.h:265
Image::load
static ImagePtr load(std::string file)
Definition: image.cpp:40
Tile::isWalkable
bool isWalkable(bool ignoreCreatures=false)
Definition: tile.cpp:528
Position::isValid
bool isValid() const
Definition: position.h:196
Texture
Definition: texture.h:28
uint32
uint32_t uint32
Definition: types.h:35
TRect::isEmpty
bool isEmpty() const
Definition: rect.h:49
resourcemanager.h
Logger::error
void error(const std::string &what)
Definition: logger.h:54
OTMM_SIGNATURE
@ OTMM_SIGNATURE
Definition: minimap.h:32
TRect::bottom
T bottom() const
Definition: rect.h:55
Minimap::saveImage
void saveImage(const std::string &fileName, const Rect &mapRect)
Definition: minimap.cpp:301
Point
TPoint< int > Point
Definition: point.h:86
Position::y
int y
Definition: position.h:266
FileStream::getString
std::string getString()
Definition: filestream.cpp:309
stdext::format
std::string format()
Definition: format.h:84
Color::a
uint8 a() const
Definition: color.h:44
MinimapTileNotWalkable
@ MinimapTileNotWalkable
Definition: minimap.h:39
Tile::getMinimapColorByte
uint8 getMinimapColorByte()
Definition: tile.cpp:384
MinimapTile::color
uint8 color
Definition: minimap.h:47
minimap.h
MinimapBlock::clean
void clean()
Definition: minimap.cpp:38
framebuffermanager.h
Position::z
short z
Definition: position.h:267
FileStream::addString
void addString(const std::string &v)
Definition: filestream.cpp:448
uint16
uint16_t uint16
Definition: types.h:36
Image
Definition: image.h:29
g_resources
ResourceManager g_resources
Definition: resourcemanager.cpp:32
TRect::topLeft
TPoint< T > topLeft() const
Definition: rect.h:60
painter.h
Minimap::updateTile
void updateTile(const Position &pos, const TilePtr &tile)
Definition: minimap.cpp:193
Texture::uploadPixels
void uploadPixels(const ImagePtr &image, bool buildMipmaps=false, bool compress=false)
Definition: texture.cpp:71
Minimap::getTile
const MinimapTile & getTile(const Position &pos)
Definition: minimap.cpp:214
uint
unsigned int uint
Definition: types.h:31
FileStream::cache
void cache()
Definition: filestream.cpp:58
MinimapTile::flags
uint8 flags
Definition: minimap.h:46
FileStream::getU16
uint16 getU16()
Definition: filestream.cpp:199
MinimapBlock::getTileIndex
uint getTileIndex(int x, int y)
Definition: minimap.h:63
g_logger
Logger g_logger
Definition: logger.cpp:35
Minimap::clean
void clean()
Definition: minimap.cpp:95
stdext::shared_object_ptr::reset
void reset()
Definition: shared_object.h:79
Position
Definition: position.h:33
image.h
Size
TSize< int > Size
Definition: size.h:107
TPoint::x
T x
Definition: point.h:83
TRect::moveCenter
void moveCenter(const TPoint< T > &p)
Definition: rect.h:122
Position::isMapPosition
bool isMapPosition() const
Definition: position.h:195
FileStream::read
int read(void *buffer, uint size, uint nmemb=1)
Definition: filestream.cpp:109
TexturePtr
stdext::shared_object_ptr< Texture > TexturePtr
Definition: declarations.h:49
ulong
unsigned long ulong
Definition: types.h:32
Otc::MAX_Z
@ MAX_Z
Definition: const.h:37
Minimap::terminate
void terminate()
Definition: minimap.cpp:90
Minimap::init
void init()
Definition: minimap.cpp:86
MinimapTile
Definition: minimap.h:43
Minimap::getTileRect
Rect getTileRect(const Position &pos, const Rect &screenRect, const Position &mapCenter, float scale)
Definition: minimap.cpp:174
stdext::throw_exception
void throw_exception(const std::string &what)
Throws a generic exception.
Definition: exception.h:43
Rect
TRect< int > Rect
Definition: rect.h:319
Minimap::getTilePosition
Position getTilePosition(const Point &point, const Rect &screenRect, const Position &mapCenter, float scale)
Definition: minimap.cpp:163
ResourceManager::openFile
FileStreamPtr openFile(const std::string &fileName)
Definition: resourcemanager.cpp:232
Painter::setClipRect
virtual void setClipRect(const Rect &clipRect)=0
filestream.h
Color::alpha
static const Color alpha
Definition: color.h:100
Minimap::getTilePoint
Point getTilePoint(const Position &pos, const Rect &screenRect, const Position &mapCenter, float scale)
Definition: minimap.cpp:152
stdext::exception::what
virtual const char * what() const
Definition: exception.h:37
FileStream::tell
uint tell()
Definition: filestream.cpp:167
Painter::resetColor
void resetColor()
Definition: painter.h:108
uchar
unsigned char uchar
Definition: types.h:29
TRect::right
T right() const
Definition: rect.h:54
texture.h
stdext::shared_object_ptr
Definition: shared_object.h:39
Texture::setSmooth
virtual void setSmooth(bool smooth)
Definition: texture.cpp:131
g_minimap
Minimap g_minimap
Definition: minimap.cpp:36
g_painter
Painter * g_painter
Definition: painter.cpp:28
MinimapTile::speed
uint8 speed
Definition: minimap.h:48
Tile::isPathable
bool isPathable()
Definition: tile.cpp:544
TRect::height
T height() const
Definition: rect.h:70
FileStream::getU32
uint32 getU32()
Definition: filestream.cpp:215
FileStream::flush
void flush()
Definition: filestream.cpp:90
MinimapBlock::updateTile
void updateTile(int x, int y, const MinimapTile &tile)
Definition: minimap.cpp:78
TSize::toPoint
TPoint< T > toPoint() const
Definition: size.h:37
MinimapBlock::getTexture
const TexturePtr & getTexture()
Definition: minimap.h:64
MinimapBlock
Definition: minimap.h:55
MinimapTileWasSeen
@ MinimapTileWasSeen
Definition: minimap.h:37
Minimap
Definition: minimap.h:78
Minimap::saveOtmm
void saveOtmm(const std::string &fileName)
Definition: minimap.cpp:370
MinimapBlock::justSaw
void justSaw()
Definition: minimap.h:67
TPoint< int >
Painter::saveState
virtual void saveState()=0
TRect::size
TSize< T > size() const
Definition: rect.h:71
FileStream::addU8
void addU8(uint8 v)
Definition: filestream.cpp:354
Color::from8bit
static Color from8bit(int color)
Definition: color.h:90
Color::to8bit
static uint8 to8bit(const Color &color)
Definition: color.h:82
Painter::drawFilledRect
virtual void drawFilledRect(const Rect &dest)=0
ResourceManager::createFile
FileStreamPtr createFile(const std::string &fileName)
Definition: resourcemanager.cpp:250
tile.h
TRect::width
T width() const
Definition: rect.h:69
Color::rgba
uint32 rgba() const
Definition: color.h:54
OTMM_VERSION
@ OTMM_VERSION
Definition: minimap.h:33
MinimapBlock::getTiles
std::array< MinimapTile, MMBLOCK_SIZE *MMBLOCK_SIZE > & getTiles()
Definition: minimap.h:65
FileStream::getU8
uint8 getU8()
Definition: filestream.cpp:183
Minimap::draw
void draw(const Rect &screenRect, const Position &mapCenter, float scale, const Color &color)
Definition: minimap.cpp:101
uint8
uint8_t uint8
Definition: types.h:37
Painter::drawTexturedRect
virtual void drawTexturedRect(const Rect &dest, const TexturePtr &texture, const Rect &src)=0
Minimap::loadImage
bool loadImage(const std::string &fileName, const Position &topLeft, float colorFactor)
Definition: minimap.cpp:225
FileStream::addU16
void addU16(uint16 v)
Definition: filestream.cpp:365
stdext::exception
Definition: exception.h:31
MinimapBlock::wasSeen
bool wasSeen()
Definition: minimap.h:68