diff --git a/geometry/screenbase.cpp b/geometry/screenbase.cpp index b2e86886fe..20ec1eb0a4 100644 --- a/geometry/screenbase.cpp +++ b/geometry/screenbase.cpp @@ -151,8 +151,14 @@ void ScreenBase::PtoG(m2::RectD const & sr, m2::RectD & gr) const bool IsPanning(ScreenBase const & s1, ScreenBase const & s2) { - return (s1.GetScale() == s2.GetScale()) - && (s1.GetAngle() == s2.GetAngle()); + m2::PointD globPt(s1.GlobalRect().Center().x - s1.GlobalRect().minX(), + s1.GlobalRect().Center().y - s1.GlobalRect().minY()); + + m2::PointD p1 = s1.GtoP(s1.GlobalRect().Center()) - s1.GtoP(s1.GlobalRect().Center() + globPt); + + m2::PointD p2 = s2.GtoP(s2.GlobalRect().Center()) - s2.GtoP(s2.GlobalRect().Center() + globPt); + + return p1.EqualDxDy(p2, 0.00001); } void ScreenBase::ExtractGtoPParams(math::Matrix const & m, double &a, double &s, double &dx, double &dy) diff --git a/map/information_display.cpp b/map/information_display.cpp index 85def13f74..f3436713ea 100644 --- a/map/information_display.cpp +++ b/map/information_display.cpp @@ -457,8 +457,24 @@ void InformationDisplay::drawLog(DrawerYG * pDrawer) for (list::const_iterator it = s_log.begin(); it != s_log.end(); ++it) { m_yOffset += 20; + + m2::PointD startPt(m_displayRect.minX() + 10, m_displayRect.minY() + m_yOffset); + + m2::RectD textRect = pDrawer->screen()->textRect( + it->c_str(), + 10, + true, + false + ); + + pDrawer->screen()->drawRectangle( + m2::Inflate(m2::Offset(textRect, startPt), m2::PointD(2, 2)), + yg::Color(0, 0, 0, 128), + yg::maxDepth - 1 + ); + pDrawer->screen()->drawText( - m2::PointD(m_displayRect.minX() + 10, m_displayRect.minY() + m_yOffset), + startPt, 0, 10, yg::Color(0, 0, 0, 255), it->c_str(), diff --git a/map/render_queue_routine.cpp b/map/render_queue_routine.cpp index 0e0430a207..30e2c2f6aa 100644 --- a/map/render_queue_routine.cpp +++ b/map/render_queue_routine.cpp @@ -55,18 +55,13 @@ void RenderQueueRoutine::Cancel() m_currentRenderCommand->m_paintEvent->setIsCancelled(true); } -void RenderQueueRoutine::processResize(ScreenBase const & /*frameScreen*/) +void RenderQueueRoutine::processResize(ScreenBase const & frameScreen) { - threads::MutexGuard guard(*m_renderState->m_mutex.get()); - if (m_renderState->m_isResized) { size_t texW = m_renderState->m_textureWidth; size_t texH = m_renderState->m_textureHeight; - m_renderState->m_backBufferLayers.clear(); - m_renderState->m_backBufferLayers.push_back(make_shared_ptr(new yg::gl::Texture(texW, texH))); - m_renderState->m_depthBuffer.reset(); if (!m_isMultiSampled) @@ -78,6 +73,8 @@ void RenderQueueRoutine::processResize(ScreenBase const & /*frameScreen*/) m_threadDrawer->onSize(texW, texH); m_threadDrawer->screen()->frameBuffer()->onSize(texW, texH); + shared_ptr oldActualTarget = m_renderState->m_actualTarget; + m_renderState->m_actualTarget.reset(); m_renderState->m_actualTarget = make_shared_ptr(new yg::gl::Texture(texW, texH)); @@ -85,92 +82,96 @@ void RenderQueueRoutine::processResize(ScreenBase const & /*frameScreen*/) m_auxScreen->setRenderTarget(m_renderState->m_actualTarget); m_auxScreen->beginFrame(); m_auxScreen->clear(); + + if (oldActualTarget != 0) + { + m_auxScreen->blit(oldActualTarget, + m_renderState->m_actualScreen, + frameScreen); + oldActualTarget.reset(); + } m_auxScreen->endFrame(); -// m_renderState->m_actualTarget->fill(yg::Color(192, 192, 192, 255)); for (size_t i = 0; i < m_renderState->m_backBufferLayers.size(); ++i) { + shared_ptr oldBackBuffer = m_renderState->m_backBufferLayers[i]; + m_renderState->m_backBufferLayers[i].reset(); + m_renderState->m_backBufferLayers[i] = make_shared_ptr(new yg::gl::Texture(texW, texH)); + m_auxScreen->setRenderTarget(m_renderState->m_backBufferLayers[i]); m_auxScreen->beginFrame(); m_auxScreen->clear(); + + if (oldBackBuffer != 0) + { + m_auxScreen->blit(oldBackBuffer, + m_renderState->m_actualScreen, + frameScreen); + oldBackBuffer.reset(); + } m_auxScreen->endFrame(); + + m_renderState->m_actualScreen = frameScreen; } -// m_renderState->m_backBufferLayers[i]->fill(yg::Color(192, 192, 192, 255)); - - m_renderState->m_doRepaintAll = true; - m_renderState->m_isResized = false; } } -void RenderQueueRoutine::getUpdateAreas(vector & areas) +void RenderQueueRoutine::getUpdateAreas( + ScreenBase const & oldScreen, + m2::RectI const & oldRect, + ScreenBase const & newScreen, + m2::RectI const & newRect, + vector & areas) { - threads::MutexGuard guard(*m_renderState->m_mutex.get()); - size_t w = m_renderState->m_textureWidth; - size_t h = m_renderState->m_textureHeight; + areas.clear(); - if (m_renderState->m_doRepaintAll) + if (IsPanning(oldScreen, newScreen)) { - m_renderState->m_doRepaintAll = false; - areas.push_back(m2::RectI(0, 0, w, h)); - return; - } + m2::RectD o(newScreen.GtoP(oldScreen.PtoG(m2::PointD(oldRect.minX(), oldRect.minY()))), + newScreen.GtoP(oldScreen.PtoG(m2::PointD(oldRect.maxX(), oldRect.maxY())))); + m2::RectD n(newRect); - if (m_renderState->isPanning()) - { - /// adding two rendering sub-commands to render new areas, opened by panning. - - double dx = 0; - double dy = 0; - - m_renderState->m_actualScreen.PtoG(dx, dy); - m_renderState->m_currentScreen.GtoP(dx, dy); - - if (dx > 0) - dx = ceil(dx); - else - dx = floor(dx); - if (dy > 0) - dy = ceil(dy); - else - dy = floor(dy); - - double minX, maxX; - double minY, maxY; - - if (dx > 0) - minX = 0; - else - minX = w + dx; - - maxX = minX + my::Abs(dx); - - if (dy > 0) - minY = 0; - else - minY = h + dy; - - maxY = minY + my::Abs(dy); - - if ((my::Abs(dx) > w) || (my::Abs(dy) > h)) - areas.push_back(m2::RectI(0, 0, w, h)); - else + /// checking two corner cases + if (o.IsRectInside(n)) + return; + if (!o.IsIntersect(n)) { - if (minX != maxX) - areas.push_back(m2::RectI(minX, 0, maxX, h)); - if (minY != maxY) - { - if (minX == 0) - areas.push_back(m2::RectI(maxX, minY, w, maxY)); - else - areas.push_back(m2::RectI(0, minY, minX, maxY)); - } + areas.push_back(m2::RectI(n)); + return; } + + double leftBarMinX = 0; + double leftBarMaxX = 0; + double rightBarMinX = n.maxX(); + double rightBarMaxX = n.maxX(); + double topBarMinY = 0; + double topBarMaxY = 0; + double bottomBarMinY = n.maxY(); + double bottomBarMaxY = n.maxY(); + + if (o.minX() > n.minX()) + leftBarMaxX = ceil(o.minX()); + if (o.maxX() < n.maxX()) + rightBarMinX = floor(o.maxX()); + if (o.minY() > n.minY()) + topBarMaxY = ceil(o.minY()); + if (o.maxY() < n.maxY()) + bottomBarMinY = floor(o.maxY()); + + if (leftBarMinX != leftBarMaxX) + areas.push_back(m2::RectI(leftBarMinX, topBarMinY, leftBarMaxX, bottomBarMinY)); + if (topBarMinY != topBarMaxY) + areas.push_back(m2::RectI(leftBarMaxX, topBarMinY, rightBarMaxX, topBarMaxY)); + if (rightBarMinX != rightBarMaxX) + areas.push_back(m2::RectI(rightBarMinX, topBarMaxY, rightBarMaxX, bottomBarMaxY)); + if (bottomBarMinY != bottomBarMaxY) + areas.push_back(m2::RectI(leftBarMinX, bottomBarMinY, rightBarMinX, bottomBarMaxY)); } else { - areas.push_back(m2::RectI(0, 0, w, h)); + areas.push_back(newRect); /* int rectW = (w + 9) / 5; int rectH = (h + 9) / 5; @@ -245,13 +246,19 @@ void RenderQueueRoutine::Do() yg::gl::Screen::Params auxParams; auxParams.m_frameBuffer = m_frameBuffer; + auxParams.m_resourceManager = m_resourceManager; m_auxScreen = make_shared_ptr(new yg::gl::Screen(auxParams)); CHECK(m_visualScale != 0, ("Set the VisualScale first!")); m_threadDrawer->SetVisualScale(m_visualScale); - yg::gl::RenderState s; + bool isPanning = false; + /// update areas in pixel coordinates. + vector areas; + + m2::RectI surfaceRect; + m2::RectI textureRect; while (!IsCancelled()) { @@ -278,15 +285,61 @@ void RenderQueueRoutine::Do() m_renderCommands.erase(m_renderCommands.begin()); } - processResize(m_currentRenderCommand->m_frameScreen); - m_currentRenderCommand->m_paintEvent = make_shared_ptr(new PaintEvent(m_threadDrawer)); /// this prevents the framework from flooding us with a bunch of RenderCommands with the same screen. { threads::MutexGuard guard(*m_renderState->m_mutex.get()); + m_renderState->m_currentScreen = m_currentRenderCommand->m_frameScreen; - s = *m_renderState.get(); + + m2::RectI prevRect(0, 0, 0, 0); + ScreenBase prevScreen = m_renderState->m_actualScreen; + + if (m_renderState->m_actualTarget != 0) + prevRect = m2::RectI(0, 0, + m_renderState->m_actualTarget->width(), + m_renderState->m_actualTarget->height()); + + processResize(m_currentRenderCommand->m_frameScreen); + + /// saving parameters, which might be changed from the GUI thread for later use. + surfaceRect = m2::RectI(0, 0, m_renderState->m_surfaceWidth, m_renderState->m_surfaceHeight); + textureRect = m2::RectI(0, 0, m_renderState->m_textureWidth, m_renderState->m_textureHeight); + + m2::RectI curRect = textureRect; + + if (m_renderState->m_doRepaintAll) + { + areas.clear(); + areas.push_back(curRect); + m_threadDrawer->screen()->clearTextTree(); + m_renderState->m_doRepaintAll = false; + } + else + getUpdateAreas(prevScreen, + prevRect, + m_currentRenderCommand->m_frameScreen, + curRect, + areas); + + isPanning = IsPanning(prevScreen, m_renderState->m_currentScreen); + + if (isPanning) + { + m2::RectD oldRect = m2::RectD(m_renderState->m_currentScreen.GtoP(prevScreen.PtoG(m2::PointD(prevRect.minX(), prevRect.minY()))), + m_renderState->m_currentScreen.GtoP(prevScreen.PtoG(m2::PointD(prevRect.maxX(), prevRect.maxY())))); + m2::RectD redrawTextRect(curRect); + + if (!redrawTextRect.Intersect(oldRect)) + redrawTextRect = m2::RectD(0, 0, 0, 0); + + m_threadDrawer->screen()->offsetTextTree( + m_renderState->m_currentScreen.GtoP(prevScreen.PtoG(m2::PointD(0, 0))), + redrawTextRect); + } + else + m_threadDrawer->screen()->clearTextTree(); } } @@ -298,50 +351,29 @@ void RenderQueueRoutine::Do() if (m_currentRenderCommand != 0) { - /// update areas in pixel coordinates. - vector areas; - - if (s.m_doRepaintAll) - m_threadDrawer->screen()->clearTextTree(); - - getUpdateAreas(areas); - m_threadDrawer->beginFrame(); /// this fixes some strange issue with multisampled framebuffer. /// setRenderTarget should be made here. - m_threadDrawer->screen()->setRenderTarget(s.m_backBufferLayers.front()); + m_threadDrawer->screen()->setRenderTarget(m_renderState->m_backBufferLayers.front()); m_threadDrawer->screen()->enableClipRect(true); - m_threadDrawer->screen()->setClipRect(m2::RectI(0, 0, s.m_textureWidth, s.m_textureHeight)); + m_threadDrawer->screen()->setClipRect(textureRect); m_threadDrawer->clear(); - if (s.isPanning()) + if (isPanning) { m_threadDrawer->screen()->blit( - s.m_actualTarget, - s.m_actualScreen, - s.m_currentScreen); - - m2::RectD curRect(0, 0, s.m_textureWidth, s.m_textureHeight); - m2::RectD oldRect(s.m_currentScreen.GtoP(s.m_actualScreen.PtoG(m2::PointD(0, 0))), - s.m_currentScreen.GtoP(s.m_actualScreen.PtoG(m2::PointD(s.m_textureWidth, s.m_textureHeight)))); - - if (!curRect.Intersect(oldRect)) - curRect = m2::RectD(0, 0, 0, 0); - - m_threadDrawer->screen()->offsetTextTree( - s.m_currentScreen.GtoP(s.m_actualScreen.PtoG(m2::PointD(0, 0))), - curRect); + m_renderState->m_actualTarget, + m_renderState->m_actualScreen, + m_renderState->m_currentScreen); } - else - m_threadDrawer->screen()->clearTextTree(); - m_threadDrawer->screen()->setNeedTextRedraw(s.isPanning()); + m_threadDrawer->screen()->setNeedTextRedraw(isPanning); ScreenBase const & frameScreen = m_currentRenderCommand->m_frameScreen; m2::RectD glbRect; - frameScreen.PtoG(m2::RectD(0, 0, s.m_surfaceWidth, s.m_surfaceHeight), glbRect); + frameScreen.PtoG(m2::RectD(surfaceRect), glbRect); int scaleLevel = scales::GetScaleLevel(glbRect); for (size_t i = 0; i < areas.size(); ++i) @@ -363,7 +395,7 @@ void RenderQueueRoutine::Do() } /// setting the "whole texture" clip rect to render texts opened by panning. - m_threadDrawer->screen()->setClipRect(m2::RectI(0, 0, s.m_textureWidth, s.m_textureHeight)); + m_threadDrawer->screen()->setClipRect(textureRect); m_threadDrawer->endFrame(); } diff --git a/map/render_queue_routine.hpp b/map/render_queue_routine.hpp index 1f87dc1986..ea12d12649 100644 --- a/map/render_queue_routine.hpp +++ b/map/render_queue_routine.hpp @@ -98,7 +98,9 @@ public: /// Check, whether the resize command is queued, and resize accordingly. void processResize(ScreenBase const & frameScreen); /// Get update areas for the current render state - void getUpdateAreas(vector & areas); + void getUpdateAreas(ScreenBase const & oldScreen, m2::RectI const & oldRect, + ScreenBase const & newScreen, m2::RectI const & newRect, + vector & areas); /// Thread procedure void Do(); /// invalidate all connected window handles diff --git a/yg/render_state.cpp b/yg/render_state.cpp index 30e5d6f1d3..89b85bc121 100644 --- a/yg/render_state.cpp +++ b/yg/render_state.cpp @@ -11,7 +11,8 @@ namespace yg RenderState::RenderState() : m_isResized(false), m_doRepaintAll(false), - m_mutex(new threads::Mutex()) + m_mutex(new threads::Mutex()), + m_backBufferLayers(1) {} bool RenderState::isPanning() const @@ -48,8 +49,22 @@ namespace yg double const log2 = log(2.0); + unsigned oldTextureWidth = m_textureWidth; + unsigned oldTextureHeight = m_textureHeight; + m_textureWidth = pow(2, ceil(log(double(w)) / log2)); m_textureHeight = pow(2, ceil(log(double(h)) / log2)); + +/* + bool hasChangedTextureSize; + if ((oldTextureWidth != m_textureWidth) || (oldTextureHeight != m_textureHeight)) + hasChangedTextureSize = true; + else + hasChangedTextureSize = false; + + if (hasChangedTextureSize) + LOG(LINFO, ("TextureSize: ", m_textureWidth, m_textureHeight)); +*/ } } diff --git a/yg/render_state_updater.cpp b/yg/render_state_updater.cpp index adb08072d4..6a84cf02ea 100644 --- a/yg/render_state_updater.cpp +++ b/yg/render_state_updater.cpp @@ -96,6 +96,18 @@ namespace yg m_updateTimer.Reset(); } + void RenderStateUpdater::setClipRect(m2::RectI const & rect) + { + if ((m_renderState) && (m_indicesCount)) + { + updateActualTarget(); + m_indicesCount = 0; + m_updateTimer.Reset(); + } + + base_t::setClipRect(rect); + } + void RenderStateUpdater::endFrame() { if (m_renderState) diff --git a/yg/render_state_updater.hpp b/yg/render_state_updater.hpp index fb668134c3..b261c50140 100644 --- a/yg/render_state_updater.hpp +++ b/yg/render_state_updater.hpp @@ -46,6 +46,7 @@ namespace yg void beginFrame(); void endFrame(); + void setClipRect(m2::RectI const & rect); virtual void updateActualTarget(); }; }