Otclient  14/8/2020
mapview.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 #include "mapview.h"
24 
25 #include "creature.h"
26 #include "map.h"
27 #include "tile.h"
28 #include "statictext.h"
29 #include "animatedtext.h"
30 #include "missile.h"
31 #include "shadermanager.h"
32 #include "lightview.h"
33 
40 
41 
42 enum {
43  // 3840x2160 => 1080p optimized
44  // 2560x1440 => 720p optimized
45  // 1728x972 => 480p optimized
46 
47  NEAR_VIEW_AREA = 32*32,
48  MID_VIEW_AREA = 64*64,
49  FAR_VIEW_AREA = 128*128,
51 };
52 
54 {
55  m_viewMode = NEAR_VIEW;
56  m_lockedFirstVisibleFloor = -1;
57  m_cachedFirstVisibleFloor = 7;
58  m_cachedLastVisibleFloor = 7;
59  m_updateTilesPos = 0;
60  m_fadeOutTime = 0;
61  m_fadeInTime = 0;
62  m_minimumAmbientLight = 0;
64 
65  m_framebuffer = g_framebuffers.createFrameBuffer();
66  setVisibleDimension(Size(15, 11));
67 
68  m_shader = g_shaders.getDefaultMapShader();
69 }
70 
72 {
73 #ifndef NDEBUG
74  assert(!g_app.isTerminated());
75 #endif
76 }
77 
78 void MapView::draw(const Rect& rect)
79 {
80  // update visible tiles cache when needed
81  if(m_mustUpdateVisibleTilesCache || m_updateTilesPos > 0)
82  updateVisibleTilesCache(m_mustUpdateVisibleTilesCache ? 0 : m_updateTilesPos);
83 
84  float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS;
85  Position cameraPosition = getCameraPosition();
86 
87  int drawFlags = 0;
88  // First branch:
89  // This is unlikely to be false because a lot of us
90  // don't wanna hear their GPU fan while playing a
91  // 2D game.
92  //
93  // Second & Third branch:
94  // This is likely to be true since not many people have
95  // low-end graphics cards.
97  drawFlags = Otc::DrawAnimations;
98 
99  if(m_viewMode == NEAR_VIEW)
102  else
104 
105  if(m_mustDrawVisibleTilesCache || (drawFlags & Otc::DrawAnimations)) {
106  m_framebuffer->bind();
107 
108  if(m_mustCleanFramebuffer) {
109  Rect clearRect = Rect(0, 0, m_drawDimension * m_tileSize);
111  g_painter->drawFilledRect(clearRect);
112 
113  if(m_drawLights) {
114  m_lightView->reset();
115  m_lightView->resize(m_framebuffer->getSize());
116 
117  Light ambientLight;
118  if(cameraPosition.z <= Otc::SEA_FLOOR) {
119  ambientLight = g_map.getLight();
120  } else {
121  ambientLight.color = 215;
122  ambientLight.intensity = 0;
123  }
124  ambientLight.intensity = std::max<int>(m_minimumAmbientLight*255, ambientLight.intensity);
125  m_lightView->setGlobalLight(ambientLight);
126  }
127  }
129 
130  auto it = m_cachedVisibleTiles.begin();
131  auto end = m_cachedVisibleTiles.end();
132  for(int z=m_cachedLastVisibleFloor;z>=m_cachedFirstVisibleFloor;--z) {
133 
134  while(it != end) {
135  const TilePtr& tile = *it;
136  Position tilePos = tile->getPosition();
137  if(tilePos.z != z)
138  break;
139  else
140  ++it;
141 
142  if (g_map.isCovered(tilePos, m_cachedFirstVisibleFloor))
143  tile->draw(transformPositionTo2D(tilePos, cameraPosition), scaleFactor, drawFlags);
144  else
145  tile->draw(transformPositionTo2D(tilePos, cameraPosition), scaleFactor, drawFlags, m_lightView.get());
146  }
147 
148  if(drawFlags & Otc::DrawMissiles) {
149  for(const MissilePtr& missile : g_map.getFloorMissiles(z)) {
150  missile->draw(transformPositionTo2D(missile->getPosition(), cameraPosition), scaleFactor, drawFlags & Otc::DrawAnimations, m_lightView.get());
151  }
152  }
153  }
154 
155  m_framebuffer->release();
156 
157  // generating mipmaps each frame can be slow in older cards
158  //m_framebuffer->getTexture()->buildHardwareMipmaps();
159 
160  m_mustDrawVisibleTilesCache = false;
161  }
162 
163 
164  float fadeOpacity = 1.0f;
165  if(!m_shaderSwitchDone && m_fadeOutTime > 0) {
166  fadeOpacity = 1.0f - (m_fadeTimer.timeElapsed() / m_fadeOutTime);
167  if(fadeOpacity < 0.0f) {
168  m_shader = m_nextShader;
169  m_nextShader = nullptr;
170  m_shaderSwitchDone = true;
171  m_fadeTimer.restart();
172  }
173  }
174 
175  if(m_shaderSwitchDone && m_shader && m_fadeInTime > 0)
176  fadeOpacity = std::min<float>(m_fadeTimer.timeElapsed() / m_fadeInTime, 1.0f);
177 
178  Rect srcRect = calcFramebufferSource(rect.size());
179  Point drawOffset = srcRect.topLeft();
180 
181  if(m_shader && g_painter->hasShaders() && g_graphics.shouldUseShaders() && m_viewMode == NEAR_VIEW) {
182  Rect framebufferRect = Rect(0,0, m_drawDimension * m_tileSize);
183  Point center = srcRect.center();
184  Point globalCoord = Point(cameraPosition.x - m_drawDimension.width()/2, -(cameraPosition.y - m_drawDimension.height()/2)) * m_tileSize;
185  m_shader->bind();
186  m_shader->setUniformValue(ShaderManager::MAP_CENTER_COORD, center.x / (float)framebufferRect.width(), 1.0f - center.y / (float)framebufferRect.height());
187  m_shader->setUniformValue(ShaderManager::MAP_GLOBAL_COORD, globalCoord.x / (float)framebufferRect.height(), globalCoord.y / (float)framebufferRect.height());
188  m_shader->setUniformValue(ShaderManager::MAP_ZOOM, scaleFactor);
189  g_painter->setShaderProgram(m_shader);
190  }
191 
193  g_painter->setOpacity(fadeOpacity);
194  glDisable(GL_BLEND);
195 #if 0
196  // debug source area
198  m_framebuffer->bind();
200  g_painter->drawBoundingRect(srcRect, 2);
201  m_framebuffer->release();
203  m_framebuffer->draw(rect);
204 #else
205  m_framebuffer->draw(rect, srcRect);
206 #endif
209  glEnable(GL_BLEND);
210 
211 
212  // this could happen if the player position is not known yet
213  if(!cameraPosition.isValid())
214  return;
215 
216  float horizontalStretchFactor = rect.width() / (float)srcRect.width();
217  float verticalStretchFactor = rect.height() / (float)srcRect.height();
218 
219  // avoid drawing texts on map in far zoom outs
220  if(m_viewMode == NEAR_VIEW) {
221  for(const CreaturePtr& creature : m_cachedFloorVisibleCreatures) {
222  if(!creature->canBeSeen())
223  continue;
224 
225  PointF jumpOffset = creature->getJumpOffset() * scaleFactor;
226  Point creatureOffset = Point(16 - creature->getDisplacementX(), - creature->getDisplacementY() - 2);
227  Position pos = creature->getPosition();
228  Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
229  p += (creature->getDrawOffset() + creatureOffset) * scaleFactor - Point(stdext::round(jumpOffset.x), stdext::round(jumpOffset.y));
230  p.x = p.x * horizontalStretchFactor;
231  p.y = p.y * verticalStretchFactor;
232  p += rect.topLeft();
233 
234  int flags = 0;
235  if(m_drawNames){ flags = Otc::DrawNames; }
236  if(m_drawHealthBars) { flags |= Otc::DrawBars; }
237  if(m_drawManaBar) { flags |= Otc::DrawManaBar; }
238  creature->drawInformation(p, g_map.isCovered(pos, m_cachedFirstVisibleFloor), rect, flags);
239  }
240  }
241 
242  // lights are drawn after names and before texts
243  if(m_drawLights)
244  m_lightView->draw(rect, srcRect);
245 
246  if(m_viewMode == NEAR_VIEW && m_drawTexts) {
247  for(const StaticTextPtr& staticText : g_map.getStaticTexts()) {
248  Position pos = staticText->getPosition();
249 
250  // ony draw static texts from current camera floor, unless yells
251  //if(pos.z != cameraPosition.z && !staticText->isYell())
252  // continue;
253 
254  if(pos.z != cameraPosition.z && staticText->getMessageMode() == Otc::MessageNone)
255  continue;
256 
257  Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
258  p.x = p.x * horizontalStretchFactor;
259  p.y = p.y * verticalStretchFactor;
260  p += rect.topLeft();
261  staticText->drawText(p, rect);
262  }
263 
264  for(const AnimatedTextPtr& animatedText : g_map.getAnimatedTexts()) {
265  Position pos = animatedText->getPosition();
266 
267  /*
268  // only draw animated texts from visible floors
269  if(pos.z < m_cachedFirstVisibleFloor || pos.z > m_cachedLastVisibleFloor)
270  continue;
271 
272  // dont draw animated texts from covered tiles
273  if(pos.z != cameraPosition.z && g_map.isCovered(pos, m_cachedFirstVisibleFloor))
274  continue;
275  */
276  if(pos.z != cameraPosition.z)
277  continue;
278 
279  Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
280  p.x = p.x * horizontalStretchFactor;
281  p.y = p.y * verticalStretchFactor;
282  p += rect.topLeft();
283  animatedText->drawText(p, rect);
284  }
285  }
286 }
287 
288 void MapView::updateVisibleTilesCache(int start)
289 {
290  if(start == 0) {
291  m_cachedFirstVisibleFloor = calcFirstVisibleFloor();
292  m_cachedLastVisibleFloor = calcLastVisibleFloor();
293  assert(m_cachedFirstVisibleFloor >= 0 && m_cachedLastVisibleFloor >= 0 &&
294  m_cachedFirstVisibleFloor <= Otc::MAX_Z && m_cachedLastVisibleFloor <= Otc::MAX_Z);
295 
296  if(m_cachedLastVisibleFloor < m_cachedFirstVisibleFloor)
297  m_cachedLastVisibleFloor = m_cachedFirstVisibleFloor;
298 
299  m_cachedFloorVisibleCreatures.clear();
300  m_cachedVisibleTiles.clear();
301 
302  m_mustCleanFramebuffer = true;
303  m_mustDrawVisibleTilesCache = true;
304  m_mustUpdateVisibleTilesCache = false;
305  m_updateTilesPos = 0;
306  } else
307  m_mustCleanFramebuffer = false;
308 
309  // there is no tile to render on invalid positions
310  Position cameraPosition = getCameraPosition();
311  if(!cameraPosition.isValid())
312  return;
313 
314  bool stop = false;
315 
316  // clear current visible tiles cache
317  m_cachedVisibleTiles.clear();
318  m_mustDrawVisibleTilesCache = true;
319  m_updateTilesPos = 0;
320 
321  // cache visible tiles in draw order
322  // draw from last floor (the lower) to first floor (the higher)
323  for(int iz = m_cachedLastVisibleFloor; iz >= m_cachedFirstVisibleFloor && !stop; --iz) {
324  if(m_viewMode <= FAR_VIEW) {
325  const int numDiagonals = m_drawDimension.width() + m_drawDimension.height() - 1;
326  // loop through / diagonals beginning at top left and going to top right
327  for(int diagonal = 0; diagonal < numDiagonals && !stop; ++diagonal) {
328  // loop current diagonal tiles
329  int advance = std::max<int>(diagonal - m_drawDimension.height(), 0);
330  for(int iy = diagonal - advance, ix = advance; iy >= 0 && ix < m_drawDimension.width() && !stop; --iy, ++ix) {
331  // only start really looking tiles in the desired start
332  if(m_updateTilesPos < start) {
333  m_updateTilesPos++;
334  continue;
335  }
336 
337  // avoid rendering too much tiles at once
338  if((int)m_cachedVisibleTiles.size() > MAX_TILE_DRAWS && m_viewMode >= HUGE_VIEW) {
339  stop = true;
340  break;
341  }
342 
343  // position on current floor
344  //TODO: check position limits
345  Position tilePos = cameraPosition.translated(ix - m_virtualCenterOffset.x, iy - m_virtualCenterOffset.y);
346  // adjust tilePos to the wanted floor
347  tilePos.coveredUp(cameraPosition.z - iz);
348  if(const TilePtr& tile = g_map.getTile(tilePos)) {
349  // skip tiles that have nothing
350  if(!tile->isDrawable())
351  continue;
352  // skip tiles that are completely behind another tile
353  if(g_map.isCompletelyCovered(tilePos, m_cachedFirstVisibleFloor))
354  continue;
355  m_cachedVisibleTiles.push_back(tile);
356  }
357  m_updateTilesPos++;
358  }
359  }
360  } else {
361  // cache tiles in spiral mode
362  static std::vector<Point> spiral;
363  if(start == 0) {
364  spiral.resize(m_drawDimension.area());
365  int width = m_drawDimension.width();
366  int height = m_drawDimension.height();
367  int tpx = width/2 - 2;
368  int tpy = height/2 - 2;
369  int count = 0;
370  Rect area(0, 0, m_drawDimension);
371  spiral[count++] = Point(tpx+1,tpy+1);
372  for(int step = 1; tpx >= 0 || tpy >= 0; ++step, --tpx, --tpy) {
373  int qs = 2*step;
374  Rect lines[4] = {
375  Rect(tpx, tpy, qs, 1),
376  Rect(tpx + qs, tpy, 1, qs),
377  Rect(tpx + 1, tpy + qs, qs, 1),
378  Rect(tpx, tpy + 1, 1, qs),
379  };
380 
381  for(auto &line: lines) {
382  int sx = std::max<int>(line.left(), area.left());
383  int ex = std::min<int>(line.right(), area.right());
384  int sy = std::max<int>(line.top(), area.top());
385  int ey = std::min<int>(line.bottom(), area.bottom());
386  for(int qx=sx;qx<=ex;++qx)
387  for(int qy=sy;qy<=ey;++qy)
388  spiral[count++] = Point(qx, qy);
389  }
390  }
391  }
392 
393  for(m_updateTilesPos = start; m_updateTilesPos < (int)spiral.size(); ++m_updateTilesPos) {
394  // avoid rendering too much tiles at once
395  if((int)m_cachedVisibleTiles.size() > MAX_TILE_DRAWS) {
396  stop = true;
397  break;
398  }
399 
400  const Point& p = spiral[m_updateTilesPos];
401  Position tilePos = cameraPosition.translated(p.x - m_virtualCenterOffset.x, p.y - m_virtualCenterOffset.y);
402  tilePos.coveredUp(cameraPosition.z - iz);
403  if(const TilePtr& tile = g_map.getTile(tilePos)) {
404  if(tile->isDrawable())
405  m_cachedVisibleTiles.push_back(tile);
406  }
407  }
408  }
409  }
410 
411  if(!stop) {
412  m_updateTilesPos = 0;
413  m_spiral.clear();
414  }
415 
416  if(start == 0 && m_viewMode <= NEAR_VIEW)
417  m_cachedFloorVisibleCreatures = g_map.getSightSpectators(cameraPosition, false);
418 }
419 
420 void MapView::updateGeometry(const Size& visibleDimension, const Size& optimizedSize)
421 {
422  int tileSize = 0;
423  Size bufferSize;
424 
425  int possiblesTileSizes[] = {1,2,4,8,16,32};
426  for(int candidateTileSize : possiblesTileSizes) {
427  bufferSize = (visibleDimension + Size(3,3)) * candidateTileSize;
428  if(bufferSize.width() > g_graphics.getMaxTextureSize() || bufferSize.height() > g_graphics.getMaxTextureSize())
429  break;
430 
431  tileSize = candidateTileSize;
432  if(optimizedSize.width() < bufferSize.width() - 3*candidateTileSize && optimizedSize.height() < bufferSize.height() - 3*candidateTileSize)
433  break;
434  }
435 
436  if(tileSize == 0) {
437  g_logger.traceError("reached max zoom out");
438  return;
439  }
440 
441  Size drawDimension = visibleDimension + Size(3,3);
442  Point virtualCenterOffset = (drawDimension/2 - Size(1,1)).toPoint();
443  Point visibleCenterOffset = virtualCenterOffset;
444 
445  ViewMode viewMode = m_viewMode;
446  if(m_autoViewMode) {
447  if(tileSize >= 32 && visibleDimension.area() <= NEAR_VIEW_AREA)
448  viewMode = NEAR_VIEW;
449  else if(tileSize >= 16 && visibleDimension.area() <= MID_VIEW_AREA)
450  viewMode = MID_VIEW;
451  else if(tileSize >= 8 && visibleDimension.area() <= FAR_VIEW_AREA)
452  viewMode = FAR_VIEW;
453  else
454  viewMode = HUGE_VIEW;
455 
456  if(viewMode >= FAR_VIEW)
457  m_multifloor = false;
458  else
459  m_multifloor = true;
460  }
461 
462  // draw actually more than what is needed to avoid massive recalculations on huge views
463  /*
464  if(viewMode >= HUGE_VIEW) {
465  Size oldDimension = drawDimension;
466  drawDimension = (m_framebuffer->getSize() / tileSize);
467  virtualCenterOffset += (drawDimension - oldDimension).toPoint() / 2;
468  }
469  */
470 
471  m_viewMode = viewMode;
472  m_visibleDimension = visibleDimension;
473  m_drawDimension = drawDimension;
474  m_tileSize = tileSize;
475  m_virtualCenterOffset = virtualCenterOffset;
476  m_visibleCenterOffset = visibleCenterOffset;
477  m_optimizedSize = optimizedSize;
478  m_framebuffer->resize(bufferSize);
479  requestVisibleTilesCacheUpdate();
480 }
481 
483 {
484  requestVisibleTilesCacheUpdate();
485 }
486 
488 {
489  requestVisibleTilesCacheUpdate();
490 }
491 
492 void MapView::lockFirstVisibleFloor(int firstVisibleFloor)
493 {
494  m_lockedFirstVisibleFloor = firstVisibleFloor;
495  requestVisibleTilesCacheUpdate();
496 }
497 
499 {
500  m_lockedFirstVisibleFloor = -1;
501  requestVisibleTilesCacheUpdate();
502 }
503 
504 void MapView::setVisibleDimension(const Size& visibleDimension)
505 {
506  if(visibleDimension == m_visibleDimension)
507  return;
508 
509  if(visibleDimension.width() % 2 != 1 || visibleDimension.height() % 2 != 1) {
510  g_logger.traceError("visible dimension must be odd");
511  return;
512  }
513 
514  if(visibleDimension < Size(3,3)) {
515  g_logger.traceError("reach max zoom in");
516  return;
517  }
518 
519  updateGeometry(visibleDimension, m_optimizedSize);
520 }
521 
523 {
524  m_viewMode = viewMode;
525  requestVisibleTilesCacheUpdate();
526 }
527 
528 void MapView::setAutoViewMode(bool enable)
529 {
530  m_autoViewMode = enable;
531  if(enable)
532  updateGeometry(m_visibleDimension, m_optimizedSize);
533 }
534 
535 void MapView::optimizeForSize(const Size& visibleSize)
536 {
537  updateGeometry(m_visibleDimension, visibleSize);
538 }
539 
541 {
542  m_follow = true;
543  m_followingCreature = creature;
544  requestVisibleTilesCacheUpdate();
545 }
546 
548 {
549  m_follow = false;
550  m_customCameraPosition = pos;
551  requestVisibleTilesCacheUpdate();
552 }
553 
554 Position MapView::getPosition(const Point& point, const Size& mapSize)
555 {
556  Position cameraPosition = getCameraPosition();
557 
558  // if we have no camera, its impossible to get the tile
559  if(!cameraPosition.isValid())
560  return Position();
561 
562  Rect srcRect = calcFramebufferSource(mapSize);
563  float sh = srcRect.width() / (float)mapSize.width();
564  float sv = srcRect.height() / (float)mapSize.height();
565 
566  Point framebufferPos = Point(point.x * sh, point.y * sv);
567  Point centerOffset = (framebufferPos + srcRect.topLeft()) / m_tileSize;
568 
569  Point tilePos2D = getVisibleCenterOffset() - m_drawDimension.toPoint() + centerOffset + Point(2,2);
570  if(tilePos2D.x + cameraPosition.x < 0 && tilePos2D.y + cameraPosition.y < 0)
571  return Position();
572 
573  Position position = Position(tilePos2D.x, tilePos2D.y, 0) + cameraPosition;
574 
575  if(!position.isValid())
576  return Position();
577 
578  return position;
579 }
580 
581 void MapView::move(int x, int y)
582 {
583  m_moveOffset.x += x;
584  m_moveOffset.y += y;
585 
586  int32_t tmp = m_moveOffset.x / 32;
587  bool requestTilesUpdate = false;
588  if(tmp != 0) {
589  m_customCameraPosition.x += tmp;
590  m_moveOffset.x %= 32;
591  requestTilesUpdate = true;
592  }
593 
594  tmp = m_moveOffset.y / 32;
595  if(tmp != 0) {
596  m_customCameraPosition.y += tmp;
597  m_moveOffset.y %= 32;
598  requestTilesUpdate = true;
599  }
600 
601  if(requestTilesUpdate)
602  requestVisibleTilesCacheUpdate();
603 }
604 
605 Rect MapView::calcFramebufferSource(const Size& destSize)
606 {
607  float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS;
608  Point drawOffset = ((m_drawDimension - m_visibleDimension - Size(1,1)).toPoint()/2) * m_tileSize;
609  if(isFollowingCreature())
610  drawOffset += m_followingCreature->getWalkOffset() * scaleFactor;
611  else if(!m_moveOffset.isNull())
612  drawOffset += m_moveOffset * scaleFactor;
613 
614  Size srcSize = destSize;
615  Size srcVisible = m_visibleDimension * m_tileSize;
616  srcSize.scale(srcVisible, Fw::KeepAspectRatio);
617  drawOffset.x += (srcVisible.width() - srcSize.width()) / 2;
618  drawOffset.y += (srcVisible.height() - srcSize.height()) / 2;
619 
620  return Rect(drawOffset, srcSize);
621 }
622 
623 int MapView::calcFirstVisibleFloor()
624 {
625  int z = 7;
626  // return forced first visible floor
627  if(m_lockedFirstVisibleFloor != -1) {
628  z = m_lockedFirstVisibleFloor;
629  } else {
630  Position cameraPosition = getCameraPosition();
631 
632  // this could happens if the player is not known yet
633  if(cameraPosition.isValid()) {
634  // avoid rendering multifloors in far views
635  if(!m_multifloor) {
636  z = cameraPosition.z;
637  } else {
638  // if nothing is limiting the view, the first visible floor is 0
639  int firstFloor = 0;
640 
641  // limits to underground floors while under sea level
642  if(cameraPosition.z > Otc::SEA_FLOOR)
643  firstFloor = std::max<int>(cameraPosition.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::UNDERGROUND_FLOOR);
644 
645  // loop in 3x3 tiles around the camera
646  for(int ix = -1; ix <= 1 && firstFloor < cameraPosition.z; ++ix) {
647  for(int iy = -1; iy <= 1 && firstFloor < cameraPosition.z; ++iy) {
648  Position pos = cameraPosition.translated(ix, iy);
649 
650  // process tiles that we can look through, e.g. windows, doors
651  if((ix == 0 && iy == 0) || ((std::abs(ix) != std::abs(iy)) && g_map.isLookPossible(pos))) {
652  Position upperPos = pos;
653  Position coveredPos = pos;
654 
655  while(coveredPos.coveredUp() && upperPos.up() && upperPos.z >= firstFloor) {
656  // check tiles physically above
657  TilePtr tile = g_map.getTile(upperPos);
658  if(tile && tile->limitsFloorsView(!g_map.isLookPossible(pos))) {
659  firstFloor = upperPos.z + 1;
660  break;
661  }
662 
663  // check tiles geometrically above
664  tile = g_map.getTile(coveredPos);
665  if(tile && tile->limitsFloorsView(g_map.isLookPossible(pos))) {
666  firstFloor = coveredPos.z + 1;
667  break;
668  }
669  }
670  }
671  }
672  }
673  z = firstFloor;
674  }
675  }
676  }
677 
678  // just ensure the that the floor is in the valid range
679  z = stdext::clamp<int>(z, 0, (int)Otc::MAX_Z);
680  return z;
681 }
682 
683 int MapView::calcLastVisibleFloor()
684 {
685  if(!m_multifloor)
686  return calcFirstVisibleFloor();
687 
688  int z = 7;
689 
690  Position cameraPosition = getCameraPosition();
691  // this could happens if the player is not known yet
692  if(cameraPosition.isValid()) {
693  // view only underground floors when below sea level
694  if(cameraPosition.z > Otc::SEA_FLOOR)
695  z = cameraPosition.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
696  else
697  z = Otc::SEA_FLOOR;
698  }
699 
700  if(m_lockedFirstVisibleFloor != -1)
701  z = std::max<int>(m_lockedFirstVisibleFloor, z);
702 
703  // just ensure the that the floor is in the valid range
704  z = stdext::clamp<int>(z, 0, (int)Otc::MAX_Z);
705  return z;
706 }
707 
709 {
710  if(isFollowingCreature())
711  return m_followingCreature->getPosition();
712 
713  return m_customCameraPosition;
714 }
715 
716 void MapView::setShader(const PainterShaderProgramPtr& shader, float fadein, float fadeout)
717 {
718  if((m_shader == shader && m_shaderSwitchDone) || (m_nextShader == shader && !m_shaderSwitchDone))
719  return;
720 
721  if(fadeout > 0.0f && m_shader) {
722  m_nextShader = shader;
723  m_shaderSwitchDone = false;
724  } else {
725  m_shader = shader;
726  m_nextShader = nullptr;
727  m_shaderSwitchDone = true;
728  }
729  m_fadeTimer.restart();
730  m_fadeInTime = fadein;
731  m_fadeOutTime = fadeout;
732 }
733 
734 
735 void MapView::setDrawLights(bool enable)
736 {
737  if(enable == m_drawLights)
738  return;
739 
740  if(enable)
741  m_lightView = LightViewPtr(new LightView);
742  else
743  m_lightView = nullptr;
744  m_drawLights = enable;
745 }
746 
747 /* vim: set ts=4 sw=4 et: */
Painter::setColor
virtual void setColor(const Color &color)
Definition: painter.h:77
MapView::NEAR_VIEW
@ NEAR_VIEW
Definition: mapview.h:38
LightView::setGlobalLight
void setGlobalLight(const Light &light)
Definition: lightview.cpp:74
Painter::restoreSavedState
virtual void restoreSavedState()=0
Otc::TILE_PIXELS
@ TILE_PIXELS
Definition: const.h:29
lightview.h
eventdispatcher.h
graphics.h
g_map
Map g_map
Definition: map.cpp:36
LightView::resize
void resize(const Size &size)
Definition: lightview.cpp:125
MapView::lockFirstVisibleFloor
void lockFirstVisibleFloor(int firstVisibleFloor)
Definition: mapview.cpp:492
TPoint::y
T y
Definition: point.h:83
Otc::DrawNames
@ DrawNames
Definition: const.h:61
unlikely
#define unlikely(x)
Definition: compiler.h:71
z
gc sort z
Definition: CMakeLists.txt:176
Otc::DrawMissiles
@ DrawMissiles
Definition: const.h:55
Painter::saveAndResetState
virtual void saveAndResetState()=0
TRect< int >
Position::x
int x
Definition: position.h:243
TSize::scale
void scale(const TSize< T > &s, Fw::AspectRatioMode mode)
Definition: size.h:76
Position::isValid
bool isValid() const
Definition: position.h:182
Otc::DrawBars
@ DrawBars
Definition: const.h:60
Otc::DrawManaBar
@ DrawManaBar
Definition: const.h:63
MapView::onTileUpdate
void onTileUpdate(const Position &pos)
Definition: mapview.cpp:482
Fw::KeepAspectRatio
@ KeepAspectRatio
Definition: const.h:188
Map::isShowingAnimations
bool isShowingAnimations()
Definition: map.cpp:418
FAR_VIEW_AREA
@ FAR_VIEW_AREA
Definition: mapview.cpp:49
Tile::limitsFloorsView
bool limitsFloorsView(bool isFreeView=false)
Definition: tile.cpp:585
TSize::area
T area() const
Definition: size.h:101
resourcemanager.h
Map::getStaticTexts
std::vector< StaticTextPtr > getStaticTexts()
Definition: map.h:242
Otc::DrawItems
@ DrawItems
Definition: const.h:52
Tile::getPosition
const Position & getPosition()
Definition: tile.h:87
Otc::DrawGroundBorders
@ DrawGroundBorders
Definition: const.h:49
Map::isCompletelyCovered
bool isCompletelyCovered(const Position &pos, int firstFloor=0)
Definition: map.cpp:634
Map::getTile
const TilePtr & getTile(const Position &pos)
Definition: map.cpp:310
MapView::getPosition
Position getPosition(const Point &point, const Size &mapSize)
Definition: mapview.cpp:554
Graphics::getMaxTextureSize
int getMaxTextureSize()
Definition: graphics.h:55
Otc::SEA_FLOOR
@ SEA_FLOOR
Definition: const.h:32
MapView::FAR_VIEW
@ FAR_VIEW
Definition: mapview.h:40
Point
TPoint< int > Point
Definition: point.h:86
Position::y
int y
Definition: position.h:244
MapView::isFollowingCreature
bool isFollowingCreature()
Definition: mapview.h:87
MapView::setDrawLights
void setDrawLights(bool enable)
Definition: mapview.cpp:735
stdext::round
double round(double r)
Definition: math.cpp:64
ShaderProgram::setUniformValue
void setUniformValue(int location, const Color &color)
Definition: shaderprogram.h:68
TSize::width
int width() const
Definition: size.h:43
ShaderManager::getDefaultMapShader
const PainterShaderProgramPtr & getDefaultMapShader()
Definition: shadermanager.h:51
Painter::setShaderProgram
virtual void setShaderProgram(PainterShaderProgram *shaderProgram)
Definition: painter.h:80
LightView
Definition: lightview.h:37
creature.h
Map::getSightSpectators
std::vector< CreaturePtr > getSightSpectators(const Position &centerPos, bool multiFloor)
Definition: map.cpp:569
Otc::DrawGround
@ DrawGround
Definition: const.h:48
framebuffermanager.h
Map::getAnimatedTexts
std::vector< AnimatedTextPtr > getAnimatedTexts()
Definition: map.h:241
Position::z
short z
Definition: position.h:245
Color::green
static const Color green
Definition: color.h:105
likely
#define likely(x)
Definition: compiler.h:70
ShaderManager::MAP_ZOOM
@ MAP_ZOOM
Definition: shadermanager.h:37
Painter::hasShaders
virtual bool hasShaders()=0
MapView::setShader
void setShader(const PainterShaderProgramPtr &shader, float fadein, float fadeout)
Definition: mapview.cpp:716
TRect::topLeft
TPoint< T > topLeft() const
Definition: rect.h:60
Light::intensity
uint8 intensity
Definition: thingtype.h:119
Otc::UNDERGROUND_FLOOR
@ UNDERGROUND_FLOOR
Definition: const.h:34
FrameBuffer::draw
void draw()
Definition: framebuffer.cpp:97
Tile::draw
void draw(const Point &dest, float scaleFactor, int drawFlags, LightView *lightView=nullptr)
Definition: tile.cpp:42
ShaderManager::MAP_GLOBAL_COORD
@ MAP_GLOBAL_COORD
Definition: shadermanager.h:36
FrameBuffer::release
void release()
Definition: framebuffer.cpp:91
mapview.h
g_logger
Logger g_logger
Definition: logger.cpp:35
MAX_TILE_DRAWS
@ MAX_TILE_DRAWS
Definition: mapview.cpp:50
Position::translated
Position translated(int dx, int dy, short dz=0) const
Definition: position.h:187
MapView::setVisibleDimension
void setVisibleDimension(const Size &visibleDimension)
Definition: mapview.cpp:504
Otc::MessageNone
@ MessageNone
Definition: const.h:287
MapView::setAutoViewMode
void setAutoViewMode(bool enable)
Definition: mapview.cpp:528
MapView::unlockFirstVisibleFloor
void unlockFirstVisibleFloor()
Definition: mapview.cpp:498
Position
Definition: position.h:33
MapView::MID_VIEW
@ MID_VIEW
Definition: mapview.h:39
g_shaders
ShaderManager g_shaders
Definition: shadermanager.cpp:29
Color::white
static const Color white
Definition: color.h:101
Timer::timeElapsed
float timeElapsed()
Definition: timer.h:38
Painter::resetOpacity
void resetOpacity()
Definition: painter.h:106
missile.h
image.h
Painter::drawBoundingRect
virtual void drawBoundingRect(const Rect &dest, int innerLineWidth=1)=0
Map::getLight
Light getLight()
Definition: map.h:235
ShaderProgram::bind
bool bind()
Definition: shaderprogram.cpp:106
Size
TSize< int > Size
Definition: size.h:107
map.h
Timer::restart
void restart()
Definition: timer.cpp:27
TPoint::x
T x
Definition: point.h:83
g_graphics
Graphics g_graphics
Definition: graphics.cpp:44
AwareRange::vertical
int vertical()
Definition: map.h:135
ShaderManager::MAP_CENTER_COORD
@ MAP_CENTER_COORD
Definition: shadermanager.h:35
MID_VIEW_AREA
@ MID_VIEW_AREA
Definition: mapview.cpp:48
MapView::getCameraPosition
Position getCameraPosition()
Definition: mapview.cpp:708
AwareRange::horizontal
int horizontal()
Definition: map.h:134
Creature::getWalkOffset
Point getWalkOffset()
Definition: creature.h:97
Otc::DrawEffects
@ DrawEffects
Definition: const.h:54
Otc::MAX_Z
@ MAX_Z
Definition: const.h:33
Painter::resetShaderProgram
void resetShaderProgram()
Definition: painter.h:109
g_app
ConsoleApplication g_app
Definition: consoleapplication.cpp:32
TPoint::isNull
bool isNull() const
Definition: point.h:41
Color::black
static const Color black
Definition: color.h:102
MapView::setCameraPosition
void setCameraPosition(const Position &pos)
Definition: mapview.cpp:547
Rect
TRect< int > Rect
Definition: rect.h:319
FrameBuffer::bind
void bind()
Definition: framebuffer.cpp:84
FrameBufferManager::createFrameBuffer
FrameBufferPtr createFrameBuffer()
Definition: framebuffermanager.cpp:39
Graphics::shouldUseShaders
bool shouldUseShaders()
Definition: graphics.h:78
TSize::height
int height() const
Definition: size.h:44
LightViewPtr
stdext::shared_object_ptr< LightView > LightViewPtr
Definition: declarations.h:58
Map::getFloorMissiles
const std::vector< MissilePtr > & getFloorMissiles(int z)
Definition: map.h:239
LightView::draw
void draw(const Rect &dest, const Rect &src)
Definition: lightview.cpp:130
stdext::shared_object_ptr< Tile >
Map::isForcingAnimations
bool isForcingAnimations()
Definition: map.cpp:413
Map::isLookPossible
bool isLookPossible(const Position &pos)
Definition: map.cpp:615
Otc::DrawWalls
@ DrawWalls
Definition: const.h:64
Application::isTerminated
bool isTerminated()
Definition: application.h:50
g_painter
Painter * g_painter
Definition: painter.cpp:28
Light::color
uint8 color
Definition: thingtype.h:120
FrameBuffer::resize
void resize(const Size &size)
Definition: framebuffer.cpp:57
LightView::reset
void reset()
Definition: lightview.cpp:69
Otc::DrawCreatures
@ DrawCreatures
Definition: const.h:53
TRect::height
T height() const
Definition: rect.h:70
Otc::DrawAnimations
@ DrawAnimations
Definition: const.h:59
NEAR_VIEW_AREA
@ NEAR_VIEW_AREA
Definition: mapview.cpp:47
Light
Definition: thingtype.h:117
MapView::MapView
MapView()
Definition: mapview.cpp:53
TSize::toPoint
TPoint< T > toPoint() const
Definition: size.h:37
MapView::getVisibleCenterOffset
Point getVisibleCenterOffset()
Definition: mapview.h:72
MapView::draw
void draw(const Rect &rect)
Definition: mapview.cpp:78
MapView::ViewMode
ViewMode
Definition: mapview.h:37
MapView::followCreature
void followCreature(const CreaturePtr &creature)
Definition: mapview.cpp:540
MapView::optimizeForSize
void optimizeForSize(const Size &visibleSize)
Definition: mapview.cpp:535
statictext.h
TPoint< int >
TRect::size
TSize< T > size() const
Definition: rect.h:71
Thing::getPosition
Position getPosition()
Definition: thing.h:45
FrameBuffer::getSize
Size getSize()
Definition: framebuffer.cpp:148
Otc::AWARE_UNDEGROUND_FLOOR_RANGE
@ AWARE_UNDEGROUND_FLOOR_RANGE
Definition: const.h:35
g_framebuffers
FrameBufferManager g_framebuffers
Definition: framebuffermanager.cpp:26
Painter::drawFilledRect
virtual void drawFilledRect(const Rect &dest)=0
MapView::move
void move(int x, int y)
Definition: mapview.cpp:581
Position::up
bool up(int n=1)
Definition: position.h:207
tile.h
animatedtext.h
TRect::width
T width() const
Definition: rect.h:69
MapView::~MapView
~MapView()
Definition: mapview.cpp:71
TRect::center
TPoint< T > center() const
Definition: rect.h:68
MapView::setViewMode
void setViewMode(ViewMode viewMode)
Definition: mapview.cpp:522
TSize< int >
stdext::shared_object_ptr::get
T * get() const
Definition: shared_object.h:82
Painter::setOpacity
virtual void setOpacity(float opacity)
Definition: painter.h:91
shadermanager.h
application.h
MapView::onMapCenterChange
void onMapCenterChange(const Position &pos)
Definition: mapview.cpp:487
Map::isCovered
bool isCovered(const Position &pos, int firstFloor=0)
Definition: map.cpp:621
MapView::HUGE_VIEW
@ HUGE_VIEW
Definition: mapview.h:41
Map::getAwareRange
AwareRange getAwareRange()
Definition: map.h:233
Position::coveredUp
bool coveredUp(int n=1)
Definition: position.h:225