saving surface content on resize. fixes redraw after landscape/portrait orientation change.

This commit is contained in:
rachytski 2011-03-07 21:00:19 +02:00 committed by Alex Zolotarev
parent a2424700e5
commit 758a3b3748
7 changed files with 192 additions and 108 deletions

View file

@ -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<double, 3, 3> const & m, double &a, double &s, double &dx, double &dy)

View file

@ -457,8 +457,24 @@ void InformationDisplay::drawLog(DrawerYG * pDrawer)
for (list<string>::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(),

View file

@ -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<RT_TRAITS, false>(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<yg::gl::BaseTexture> oldActualTarget = m_renderState->m_actualTarget;
m_renderState->m_actualTarget.reset();
m_renderState->m_actualTarget = make_shared_ptr(new yg::gl::Texture<RT_TRAITS, false>(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<yg::gl::BaseTexture> oldBackBuffer = m_renderState->m_backBufferLayers[i];
m_renderState->m_backBufferLayers[i].reset();
m_renderState->m_backBufferLayers[i] = make_shared_ptr(new yg::gl::Texture<RT_TRAITS, false>(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<m2::RectI> & areas)
void RenderQueueRoutine::getUpdateAreas(
ScreenBase const & oldScreen,
m2::RectI const & oldRect,
ScreenBase const & newScreen,
m2::RectI const & newRect,
vector<m2::RectI> & 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<m2::RectI> 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<m2::RectI> 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();
}

View file

@ -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<m2::RectI> & areas);
void getUpdateAreas(ScreenBase const & oldScreen, m2::RectI const & oldRect,
ScreenBase const & newScreen, m2::RectI const & newRect,
vector<m2::RectI> & areas);
/// Thread procedure
void Do();
/// invalidate all connected window handles

View file

@ -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));
*/
}
}

View file

@ -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)

View file

@ -46,6 +46,7 @@ namespace yg
void beginFrame();
void endFrame();
void setClipRect(m2::RectI const & rect);
virtual void updateActualTarget();
};
}