56 m_lockedFirstVisibleFloor = -1;
57 m_cachedFirstVisibleFloor = 7;
58 m_cachedLastVisibleFloor = 7;
62 m_minimumAmbientLight = 0;
81 if(m_mustUpdateVisibleTilesCache || m_updateTilesPos > 0)
82 updateVisibleTilesCache(m_mustUpdateVisibleTilesCache ? 0 : m_updateTilesPos);
106 m_framebuffer->
bind();
108 if(m_mustCleanFramebuffer) {
109 Rect clearRect =
Rect(0, 0, m_drawDimension * m_tileSize);
114 m_lightView->
reset();
121 ambientLight.
color = 215;
124 ambientLight.
intensity = std::max<int>(m_minimumAmbientLight*255, ambientLight.
intensity);
130 auto it = m_cachedVisibleTiles.begin();
131 auto end = m_cachedVisibleTiles.end();
132 for(
int z=m_cachedLastVisibleFloor;
z>=m_cachedFirstVisibleFloor;--
z) {
143 tile->
draw(transformPositionTo2D(tilePos, cameraPosition), scaleFactor, drawFlags);
145 tile->
draw(transformPositionTo2D(tilePos, cameraPosition), scaleFactor, drawFlags, m_lightView.
get());
150 missile->draw(transformPositionTo2D(missile->getPosition(), cameraPosition), scaleFactor, drawFlags &
Otc::DrawAnimations, m_lightView.
get());
160 m_mustDrawVisibleTilesCache =
false;
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;
175 if(m_shaderSwitchDone && m_shader && m_fadeInTime > 0)
176 fadeOpacity = std::min<float>(m_fadeTimer.
timeElapsed() / m_fadeInTime, 1.0f);
178 Rect srcRect = calcFramebufferSource(rect.
size());
182 Rect framebufferRect =
Rect(0,0, m_drawDimension * m_tileSize);
184 Point globalCoord =
Point(cameraPosition.
x - m_drawDimension.
width()/2, -(cameraPosition.
y - m_drawDimension.
height()/2)) * m_tileSize;
198 m_framebuffer->
bind();
203 m_framebuffer->
draw(rect);
205 m_framebuffer->
draw(rect, srcRect);
216 float horizontalStretchFactor = rect.
width() / (float)srcRect.
width();
217 float verticalStretchFactor = rect.
height() / (float)srcRect.
height();
221 for(
const CreaturePtr& creature : m_cachedFloorVisibleCreatures) {
222 if(!creature->canBeSeen())
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;
230 p.
x = p.
x * horizontalStretchFactor;
231 p.
y = p.
y * verticalStretchFactor;
238 creature->drawInformation(p,
g_map.
isCovered(pos, m_cachedFirstVisibleFloor), rect, flags);
244 m_lightView->
draw(rect, srcRect);
246 if(m_viewMode ==
NEAR_VIEW && m_drawTexts) {
248 Position pos = staticText->getPosition();
257 Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
258 p.
x = p.
x * horizontalStretchFactor;
259 p.
y = p.
y * verticalStretchFactor;
261 staticText->drawText(p, rect);
265 Position pos = animatedText->getPosition();
276 if(pos.
z != cameraPosition.
z)
279 Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
280 p.
x = p.
x * horizontalStretchFactor;
281 p.
y = p.
y * verticalStretchFactor;
283 animatedText->drawText(p, rect);
288 void MapView::updateVisibleTilesCache(
int start)
291 m_cachedFirstVisibleFloor = calcFirstVisibleFloor();
292 m_cachedLastVisibleFloor = calcLastVisibleFloor();
293 assert(m_cachedFirstVisibleFloor >= 0 && m_cachedLastVisibleFloor >= 0 &&
296 if(m_cachedLastVisibleFloor < m_cachedFirstVisibleFloor)
297 m_cachedLastVisibleFloor = m_cachedFirstVisibleFloor;
299 m_cachedFloorVisibleCreatures.clear();
300 m_cachedVisibleTiles.clear();
302 m_mustCleanFramebuffer =
true;
303 m_mustDrawVisibleTilesCache =
true;
304 m_mustUpdateVisibleTilesCache =
false;
305 m_updateTilesPos = 0;
307 m_mustCleanFramebuffer =
false;
317 m_cachedVisibleTiles.clear();
318 m_mustDrawVisibleTilesCache =
true;
319 m_updateTilesPos = 0;
323 for(
int iz = m_cachedLastVisibleFloor; iz >= m_cachedFirstVisibleFloor && !stop; --iz) {
325 const int numDiagonals = m_drawDimension.
width() + m_drawDimension.
height() - 1;
327 for(
int diagonal = 0; diagonal < numDiagonals && !stop; ++diagonal) {
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) {
332 if(m_updateTilesPos < start) {
345 Position tilePos = cameraPosition.
translated(ix - m_virtualCenterOffset.
x, iy - m_virtualCenterOffset.
y);
350 if(!tile->isDrawable())
355 m_cachedVisibleTiles.push_back(tile);
362 static std::vector<Point> spiral;
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;
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) {
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),
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);
393 for(m_updateTilesPos = start; m_updateTilesPos < (int)spiral.size(); ++m_updateTilesPos) {
400 const Point& p = spiral[m_updateTilesPos];
401 Position tilePos = cameraPosition.
translated(p.
x - m_virtualCenterOffset.
x, p.
y - m_virtualCenterOffset.
y);
404 if(tile->isDrawable())
405 m_cachedVisibleTiles.push_back(tile);
412 m_updateTilesPos = 0;
416 if(start == 0 && m_viewMode <=
NEAR_VIEW)
420 void MapView::updateGeometry(
const Size& visibleDimension,
const Size& optimizedSize)
425 int possiblesTileSizes[] = {1,2,4,8,16,32};
426 for(
int candidateTileSize : possiblesTileSizes) {
427 bufferSize = (visibleDimension +
Size(3,3)) * candidateTileSize;
431 tileSize = candidateTileSize;
432 if(optimizedSize.
width() < bufferSize.
width() - 3*candidateTileSize && optimizedSize.
height() < bufferSize.
height() - 3*candidateTileSize)
437 g_logger.traceError(
"reached max zoom out");
441 Size drawDimension = visibleDimension +
Size(3,3);
442 Point virtualCenterOffset = (drawDimension/2 -
Size(1,1)).toPoint();
443 Point visibleCenterOffset = virtualCenterOffset;
457 m_multifloor =
false;
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();
484 requestVisibleTilesCacheUpdate();
489 requestVisibleTilesCacheUpdate();
494 m_lockedFirstVisibleFloor = firstVisibleFloor;
495 requestVisibleTilesCacheUpdate();
500 m_lockedFirstVisibleFloor = -1;
501 requestVisibleTilesCacheUpdate();
506 if(visibleDimension == m_visibleDimension)
509 if(visibleDimension.
width() % 2 != 1 || visibleDimension.
height() % 2 != 1) {
510 g_logger.traceError(
"visible dimension must be odd");
514 if(visibleDimension <
Size(3,3)) {
515 g_logger.traceError(
"reach max zoom in");
519 updateGeometry(visibleDimension, m_optimizedSize);
524 m_viewMode = viewMode;
525 requestVisibleTilesCacheUpdate();
530 m_autoViewMode = enable;
532 updateGeometry(m_visibleDimension, m_optimizedSize);
537 updateGeometry(m_visibleDimension, visibleSize);
543 m_followingCreature = creature;
544 requestVisibleTilesCacheUpdate();
550 m_customCameraPosition = pos;
551 requestVisibleTilesCacheUpdate();
562 Rect srcRect = calcFramebufferSource(mapSize);
563 float sh = srcRect.
width() / (float)mapSize.
width();
566 Point framebufferPos =
Point(point.
x * sh, point.
y * sv);
567 Point centerOffset = (framebufferPos + srcRect.
topLeft()) / m_tileSize;
570 if(tilePos2D.
x + cameraPosition.
x < 0 && tilePos2D.
y + cameraPosition.
y < 0)
586 int32_t tmp = m_moveOffset.
x / 32;
587 bool requestTilesUpdate =
false;
589 m_customCameraPosition.
x += tmp;
590 m_moveOffset.
x %= 32;
591 requestTilesUpdate =
true;
594 tmp = m_moveOffset.
y / 32;
596 m_customCameraPosition.
y += tmp;
597 m_moveOffset.
y %= 32;
598 requestTilesUpdate =
true;
601 if(requestTilesUpdate)
602 requestVisibleTilesCacheUpdate();
605 Rect MapView::calcFramebufferSource(
const Size& destSize)
608 Point drawOffset = ((m_drawDimension - m_visibleDimension -
Size(1,1)).toPoint()/2) * m_tileSize;
610 drawOffset += m_followingCreature->
getWalkOffset() * scaleFactor;
611 else if(!m_moveOffset.
isNull())
612 drawOffset += m_moveOffset * scaleFactor;
614 Size srcSize = destSize;
615 Size srcVisible = m_visibleDimension * m_tileSize;
617 drawOffset.
x += (srcVisible.
width() - srcSize.
width()) / 2;
618 drawOffset.
y += (srcVisible.
height() - srcSize.
height()) / 2;
620 return Rect(drawOffset, srcSize);
623 int MapView::calcFirstVisibleFloor()
627 if(m_lockedFirstVisibleFloor != -1) {
628 z = m_lockedFirstVisibleFloor;
636 z = cameraPosition.
z;
646 for(
int ix = -1; ix <= 1 && firstFloor < cameraPosition.
z; ++ix) {
647 for(
int iy = -1; iy <= 1 && firstFloor < cameraPosition.
z; ++iy) {
651 if((ix == 0 && iy == 0) || ((std::abs(ix) != std::abs(iy)) &&
g_map.
isLookPossible(pos))) {
655 while(coveredPos.
coveredUp() && upperPos.
up() && upperPos.
z >= firstFloor) {
659 firstFloor = upperPos.
z + 1;
666 firstFloor = coveredPos.
z + 1;
683 int MapView::calcLastVisibleFloor()
686 return calcFirstVisibleFloor();
700 if(m_lockedFirstVisibleFloor != -1)
701 z = std::max<int>(m_lockedFirstVisibleFloor,
z);
713 return m_customCameraPosition;
718 if((m_shader == shader && m_shaderSwitchDone) || (m_nextShader == shader && !m_shaderSwitchDone))
721 if(fadeout > 0.0f && m_shader) {
722 m_nextShader = shader;
723 m_shaderSwitchDone =
false;
726 m_nextShader =
nullptr;
727 m_shaderSwitchDone =
true;
730 m_fadeInTime = fadein;
731 m_fadeOutTime = fadeout;
737 if(enable == m_drawLights)
743 m_lightView =
nullptr;
744 m_drawLights = enable;