1*b1cdbd2cSJim Jagielski /************************************************************** 2*b1cdbd2cSJim Jagielski * 3*b1cdbd2cSJim Jagielski * Licensed to the Apache Software Foundation (ASF) under one 4*b1cdbd2cSJim Jagielski * or more contributor license agreements. See the NOTICE file 5*b1cdbd2cSJim Jagielski * distributed with this work for additional information 6*b1cdbd2cSJim Jagielski * regarding copyright ownership. The ASF licenses this file 7*b1cdbd2cSJim Jagielski * to you under the Apache License, Version 2.0 (the 8*b1cdbd2cSJim Jagielski * "License"); you may not use this file except in compliance 9*b1cdbd2cSJim Jagielski * with the License. You may obtain a copy of the License at 10*b1cdbd2cSJim Jagielski * 11*b1cdbd2cSJim Jagielski * http://www.apache.org/licenses/LICENSE-2.0 12*b1cdbd2cSJim Jagielski * 13*b1cdbd2cSJim Jagielski * Unless required by applicable law or agreed to in writing, 14*b1cdbd2cSJim Jagielski * software distributed under the License is distributed on an 15*b1cdbd2cSJim Jagielski * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*b1cdbd2cSJim Jagielski * KIND, either express or implied. See the License for the 17*b1cdbd2cSJim Jagielski * specific language governing permissions and limitations 18*b1cdbd2cSJim Jagielski * under the License. 19*b1cdbd2cSJim Jagielski * 20*b1cdbd2cSJim Jagielski *************************************************************/ 21*b1cdbd2cSJim Jagielski 22*b1cdbd2cSJim Jagielski 23*b1cdbd2cSJim Jagielski 24*b1cdbd2cSJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove 25*b1cdbd2cSJim Jagielski #include "precompiled_canvas.hxx" 26*b1cdbd2cSJim Jagielski 27*b1cdbd2cSJim Jagielski #include <canvas/debug.hxx> 28*b1cdbd2cSJim Jagielski #include <tools/diagnose_ex.h> 29*b1cdbd2cSJim Jagielski #include <canvas/verbosetrace.hxx> 30*b1cdbd2cSJim Jagielski #include <canvas/canvastools.hxx> 31*b1cdbd2cSJim Jagielski 32*b1cdbd2cSJim Jagielski #include <vcl/canvastools.hxx> 33*b1cdbd2cSJim Jagielski #include <vcl/outdev.hxx> 34*b1cdbd2cSJim Jagielski #include <vcl/window.hxx> 35*b1cdbd2cSJim Jagielski #include <vcl/bitmapex.hxx> 36*b1cdbd2cSJim Jagielski 37*b1cdbd2cSJim Jagielski #include <basegfx/range/b2drectangle.hxx> 38*b1cdbd2cSJim Jagielski #include <basegfx/tools/canvastools.hxx> 39*b1cdbd2cSJim Jagielski 40*b1cdbd2cSJim Jagielski #include <boost/cast.hpp> 41*b1cdbd2cSJim Jagielski 42*b1cdbd2cSJim Jagielski #include "spritecanvashelper.hxx" 43*b1cdbd2cSJim Jagielski #include "canvascustomsprite.hxx" 44*b1cdbd2cSJim Jagielski 45*b1cdbd2cSJim Jagielski 46*b1cdbd2cSJim Jagielski using namespace ::com::sun::star; 47*b1cdbd2cSJim Jagielski 48*b1cdbd2cSJim Jagielski #define FPS_BOUNDS Rectangle(0,0,130,90) 49*b1cdbd2cSJim Jagielski #define INFO_COLOR COL_RED 50*b1cdbd2cSJim Jagielski 51*b1cdbd2cSJim Jagielski namespace vclcanvas 52*b1cdbd2cSJim Jagielski { 53*b1cdbd2cSJim Jagielski namespace 54*b1cdbd2cSJim Jagielski { 55*b1cdbd2cSJim Jagielski /** Sprite redraw at original position 56*b1cdbd2cSJim Jagielski 57*b1cdbd2cSJim Jagielski Used to repaint the whole canvas (background and all 58*b1cdbd2cSJim Jagielski sprites) 59*b1cdbd2cSJim Jagielski */ spriteRedraw(OutputDevice & rOutDev,const::canvas::Sprite::Reference & rSprite)60*b1cdbd2cSJim Jagielski void spriteRedraw( OutputDevice& rOutDev, 61*b1cdbd2cSJim Jagielski const ::canvas::Sprite::Reference& rSprite ) 62*b1cdbd2cSJim Jagielski { 63*b1cdbd2cSJim Jagielski // downcast to derived vclcanvas::Sprite interface, which 64*b1cdbd2cSJim Jagielski // provides the actual redraw methods. 65*b1cdbd2cSJim Jagielski ::boost::polymorphic_downcast< Sprite* >(rSprite.get())->redraw(rOutDev, 66*b1cdbd2cSJim Jagielski true); 67*b1cdbd2cSJim Jagielski } 68*b1cdbd2cSJim Jagielski calcNumPixel(const::canvas::Sprite::Reference & rSprite)69*b1cdbd2cSJim Jagielski double calcNumPixel( const ::canvas::Sprite::Reference& rSprite ) 70*b1cdbd2cSJim Jagielski { 71*b1cdbd2cSJim Jagielski const ::basegfx::B2DSize& rSize( 72*b1cdbd2cSJim Jagielski ::boost::polymorphic_downcast< Sprite* >(rSprite.get())->getSizePixel() ); 73*b1cdbd2cSJim Jagielski 74*b1cdbd2cSJim Jagielski return rSize.getX() * rSize.getY(); 75*b1cdbd2cSJim Jagielski } 76*b1cdbd2cSJim Jagielski repaintBackground(OutputDevice & rOutDev,OutputDevice & rBackBuffer,const::basegfx::B2DRange & rArea)77*b1cdbd2cSJim Jagielski void repaintBackground( OutputDevice& rOutDev, 78*b1cdbd2cSJim Jagielski OutputDevice& rBackBuffer, 79*b1cdbd2cSJim Jagielski const ::basegfx::B2DRange& rArea ) 80*b1cdbd2cSJim Jagielski { 81*b1cdbd2cSJim Jagielski const ::Point& rPos( ::vcl::unotools::pointFromB2DPoint( rArea.getMinimum()) ); 82*b1cdbd2cSJim Jagielski const ::Size& rSize( ::vcl::unotools::sizeFromB2DSize( rArea.getRange()) ); 83*b1cdbd2cSJim Jagielski 84*b1cdbd2cSJim Jagielski rOutDev.DrawOutDev( rPos, rSize, rPos, rSize, rBackBuffer ); 85*b1cdbd2cSJim Jagielski } 86*b1cdbd2cSJim Jagielski opaqueUpdateSpriteArea(const::canvas::Sprite::Reference & rSprite,OutputDevice & rOutDev,const::basegfx::B2IRange & rArea)87*b1cdbd2cSJim Jagielski void opaqueUpdateSpriteArea( const ::canvas::Sprite::Reference& rSprite, 88*b1cdbd2cSJim Jagielski OutputDevice& rOutDev, 89*b1cdbd2cSJim Jagielski const ::basegfx::B2IRange& rArea ) 90*b1cdbd2cSJim Jagielski { 91*b1cdbd2cSJim Jagielski const Rectangle& rRequestedArea( 92*b1cdbd2cSJim Jagielski ::vcl::unotools::rectangleFromB2IRectangle( rArea ) ); 93*b1cdbd2cSJim Jagielski 94*b1cdbd2cSJim Jagielski // clip output to actual update region (otherwise a) 95*b1cdbd2cSJim Jagielski // wouldn't save much render time, and b) will clutter 96*b1cdbd2cSJim Jagielski // scrolled sprite content outside this area) 97*b1cdbd2cSJim Jagielski rOutDev.EnableMapMode( sal_False ); 98*b1cdbd2cSJim Jagielski rOutDev.SetAntialiasing( ANTIALIASING_ENABLE_B2DDRAW ); 99*b1cdbd2cSJim Jagielski rOutDev.SetClipRegion( rRequestedArea ); 100*b1cdbd2cSJim Jagielski 101*b1cdbd2cSJim Jagielski // repaint affected sprite directly to output device (at 102*b1cdbd2cSJim Jagielski // the actual screen output position) 103*b1cdbd2cSJim Jagielski ::boost::polymorphic_downcast< Sprite* >( 104*b1cdbd2cSJim Jagielski rSprite.get() )->redraw( rOutDev, 105*b1cdbd2cSJim Jagielski false ); // rendering 106*b1cdbd2cSJim Jagielski // directly to 107*b1cdbd2cSJim Jagielski // frontbuffer 108*b1cdbd2cSJim Jagielski } 109*b1cdbd2cSJim Jagielski 110*b1cdbd2cSJim Jagielski /** Repaint sprite at original position 111*b1cdbd2cSJim Jagielski 112*b1cdbd2cSJim Jagielski Used for opaque updates, which render directly to the 113*b1cdbd2cSJim Jagielski front buffer. 114*b1cdbd2cSJim Jagielski */ spriteRedrawStub(OutputDevice & rOutDev,const::canvas::Sprite::Reference & rSprite)115*b1cdbd2cSJim Jagielski void spriteRedrawStub( OutputDevice& rOutDev, 116*b1cdbd2cSJim Jagielski const ::canvas::Sprite::Reference& rSprite ) 117*b1cdbd2cSJim Jagielski { 118*b1cdbd2cSJim Jagielski if( rSprite.is() ) 119*b1cdbd2cSJim Jagielski { 120*b1cdbd2cSJim Jagielski ::boost::polymorphic_downcast< Sprite* >( 121*b1cdbd2cSJim Jagielski rSprite.get() )->redraw( rOutDev, 122*b1cdbd2cSJim Jagielski false ); 123*b1cdbd2cSJim Jagielski } 124*b1cdbd2cSJim Jagielski } 125*b1cdbd2cSJim Jagielski 126*b1cdbd2cSJim Jagielski /** Repaint sprite at given position 127*b1cdbd2cSJim Jagielski 128*b1cdbd2cSJim Jagielski Used for generic update, which renders into vdev of 129*b1cdbd2cSJim Jagielski adapted size. 130*b1cdbd2cSJim Jagielski */ spriteRedrawStub2(OutputDevice & rOutDev,const::basegfx::B2DPoint & rOutPos,const::canvas::Sprite::Reference & rSprite)131*b1cdbd2cSJim Jagielski void spriteRedrawStub2( OutputDevice& rOutDev, 132*b1cdbd2cSJim Jagielski const ::basegfx::B2DPoint& rOutPos, 133*b1cdbd2cSJim Jagielski const ::canvas::Sprite::Reference& rSprite ) 134*b1cdbd2cSJim Jagielski { 135*b1cdbd2cSJim Jagielski if( rSprite.is() ) 136*b1cdbd2cSJim Jagielski { 137*b1cdbd2cSJim Jagielski Sprite* pSprite = ::boost::polymorphic_downcast< Sprite* >( 138*b1cdbd2cSJim Jagielski rSprite.get() ); 139*b1cdbd2cSJim Jagielski 140*b1cdbd2cSJim Jagielski // calc relative sprite position in rUpdateArea (which 141*b1cdbd2cSJim Jagielski // need not be the whole screen!) 142*b1cdbd2cSJim Jagielski const ::basegfx::B2DPoint& rSpriteScreenPos( pSprite->getPosPixel() ); 143*b1cdbd2cSJim Jagielski const ::basegfx::B2DPoint& rSpriteRenderPos( rSpriteScreenPos - rOutPos ); 144*b1cdbd2cSJim Jagielski 145*b1cdbd2cSJim Jagielski pSprite->redraw( rOutDev, rSpriteRenderPos, true ); 146*b1cdbd2cSJim Jagielski } 147*b1cdbd2cSJim Jagielski } 148*b1cdbd2cSJim Jagielski 149*b1cdbd2cSJim Jagielski /** Repaint sprite at original position 150*b1cdbd2cSJim Jagielski 151*b1cdbd2cSJim Jagielski Used for opaque updates from scrollUpdate(), which render 152*b1cdbd2cSJim Jagielski directly to the front buffer. 153*b1cdbd2cSJim Jagielski */ spriteRedrawStub3(OutputDevice & rOutDev,const::canvas::SpriteRedrawManager::AreaComponent & rComponent)154*b1cdbd2cSJim Jagielski void spriteRedrawStub3( OutputDevice& rOutDev, 155*b1cdbd2cSJim Jagielski const ::canvas::SpriteRedrawManager::AreaComponent& rComponent ) 156*b1cdbd2cSJim Jagielski { 157*b1cdbd2cSJim Jagielski const ::canvas::Sprite::Reference& rSprite( rComponent.second.getSprite() ); 158*b1cdbd2cSJim Jagielski 159*b1cdbd2cSJim Jagielski if( rSprite.is() ) 160*b1cdbd2cSJim Jagielski { 161*b1cdbd2cSJim Jagielski ::boost::polymorphic_downcast< Sprite* >( 162*b1cdbd2cSJim Jagielski rSprite.get() )->redraw( rOutDev, 163*b1cdbd2cSJim Jagielski false ); 164*b1cdbd2cSJim Jagielski } 165*b1cdbd2cSJim Jagielski } 166*b1cdbd2cSJim Jagielski renderInfoText(OutputDevice & rOutDev,const::rtl::OUString & rStr,const Point & rPos)167*b1cdbd2cSJim Jagielski void renderInfoText( OutputDevice& rOutDev, 168*b1cdbd2cSJim Jagielski const ::rtl::OUString& rStr, 169*b1cdbd2cSJim Jagielski const Point& rPos ) 170*b1cdbd2cSJim Jagielski { 171*b1cdbd2cSJim Jagielski Font aVCLFont; 172*b1cdbd2cSJim Jagielski aVCLFont.SetHeight( 20 ); 173*b1cdbd2cSJim Jagielski aVCLFont.SetColor( Color( INFO_COLOR ) ); 174*b1cdbd2cSJim Jagielski 175*b1cdbd2cSJim Jagielski rOutDev.SetTextAlign(ALIGN_TOP); 176*b1cdbd2cSJim Jagielski rOutDev.SetTextColor( Color( INFO_COLOR ) ); 177*b1cdbd2cSJim Jagielski rOutDev.SetFont( aVCLFont ); 178*b1cdbd2cSJim Jagielski 179*b1cdbd2cSJim Jagielski rOutDev.DrawText( rPos, rStr ); 180*b1cdbd2cSJim Jagielski } 181*b1cdbd2cSJim Jagielski 182*b1cdbd2cSJim Jagielski } 183*b1cdbd2cSJim Jagielski SpriteCanvasHelper()184*b1cdbd2cSJim Jagielski SpriteCanvasHelper::SpriteCanvasHelper() : 185*b1cdbd2cSJim Jagielski mpRedrawManager( NULL ), 186*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas( NULL ), 187*b1cdbd2cSJim Jagielski maVDev(), 188*b1cdbd2cSJim Jagielski maLastUpdate(), 189*b1cdbd2cSJim Jagielski mbShowFrameInfo( false ), 190*b1cdbd2cSJim Jagielski mbShowSpriteBounds( false ), 191*b1cdbd2cSJim Jagielski mbIsUnsafeScrolling( false ) 192*b1cdbd2cSJim Jagielski { 193*b1cdbd2cSJim Jagielski #if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0 194*b1cdbd2cSJim Jagielski // inverse defaults for verbose debug mode 195*b1cdbd2cSJim Jagielski mbShowSpriteBounds = mbShowFrameInfo = true; 196*b1cdbd2cSJim Jagielski #endif 197*b1cdbd2cSJim Jagielski } 198*b1cdbd2cSJim Jagielski init(const OutDevProviderSharedPtr & rOutDev,SpriteCanvas & rOwningSpriteCanvas,::canvas::SpriteRedrawManager & rManager,bool bProtect,bool bHaveAlpha)199*b1cdbd2cSJim Jagielski void SpriteCanvasHelper::init( const OutDevProviderSharedPtr& rOutDev, 200*b1cdbd2cSJim Jagielski SpriteCanvas& rOwningSpriteCanvas, 201*b1cdbd2cSJim Jagielski ::canvas::SpriteRedrawManager& rManager, 202*b1cdbd2cSJim Jagielski bool bProtect, 203*b1cdbd2cSJim Jagielski bool bHaveAlpha ) 204*b1cdbd2cSJim Jagielski { 205*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas = &rOwningSpriteCanvas; 206*b1cdbd2cSJim Jagielski mpRedrawManager = &rManager; 207*b1cdbd2cSJim Jagielski 208*b1cdbd2cSJim Jagielski CanvasHelper::init(rOwningSpriteCanvas,rOutDev,bProtect,bHaveAlpha); 209*b1cdbd2cSJim Jagielski } 210*b1cdbd2cSJim Jagielski disposing()211*b1cdbd2cSJim Jagielski void SpriteCanvasHelper::disposing() 212*b1cdbd2cSJim Jagielski { 213*b1cdbd2cSJim Jagielski mpRedrawManager = NULL; 214*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas = NULL; 215*b1cdbd2cSJim Jagielski 216*b1cdbd2cSJim Jagielski // forward to base 217*b1cdbd2cSJim Jagielski CanvasHelper::disposing(); 218*b1cdbd2cSJim Jagielski } 219*b1cdbd2cSJim Jagielski createSpriteFromAnimation(const uno::Reference<rendering::XAnimation> &)220*b1cdbd2cSJim Jagielski uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromAnimation( 221*b1cdbd2cSJim Jagielski const uno::Reference< rendering::XAnimation >& ) 222*b1cdbd2cSJim Jagielski { 223*b1cdbd2cSJim Jagielski return uno::Reference< rendering::XAnimatedSprite >(); 224*b1cdbd2cSJim Jagielski } 225*b1cdbd2cSJim Jagielski createSpriteFromBitmaps(const uno::Sequence<uno::Reference<rendering::XBitmap>> &,sal_Int8)226*b1cdbd2cSJim Jagielski uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromBitmaps( 227*b1cdbd2cSJim Jagielski const uno::Sequence< uno::Reference< rendering::XBitmap > >& , 228*b1cdbd2cSJim Jagielski sal_Int8 ) 229*b1cdbd2cSJim Jagielski { 230*b1cdbd2cSJim Jagielski return uno::Reference< rendering::XAnimatedSprite >(); 231*b1cdbd2cSJim Jagielski } 232*b1cdbd2cSJim Jagielski createCustomSprite(const geometry::RealSize2D & spriteSize)233*b1cdbd2cSJim Jagielski uno::Reference< rendering::XCustomSprite > SpriteCanvasHelper::createCustomSprite( const geometry::RealSize2D& spriteSize ) 234*b1cdbd2cSJim Jagielski { 235*b1cdbd2cSJim Jagielski if( !mpRedrawManager || !mpDevice ) 236*b1cdbd2cSJim Jagielski return uno::Reference< rendering::XCustomSprite >(); // we're disposed 237*b1cdbd2cSJim Jagielski 238*b1cdbd2cSJim Jagielski return uno::Reference< rendering::XCustomSprite >( 239*b1cdbd2cSJim Jagielski new CanvasCustomSprite( spriteSize, 240*b1cdbd2cSJim Jagielski *mpDevice, 241*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas, 242*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas->getFrontBuffer(), 243*b1cdbd2cSJim Jagielski mbShowSpriteBounds ) ); 244*b1cdbd2cSJim Jagielski } 245*b1cdbd2cSJim Jagielski createClonedSprite(const uno::Reference<rendering::XSprite> &)246*b1cdbd2cSJim Jagielski uno::Reference< rendering::XSprite > SpriteCanvasHelper::createClonedSprite( const uno::Reference< rendering::XSprite >& ) 247*b1cdbd2cSJim Jagielski { 248*b1cdbd2cSJim Jagielski return uno::Reference< rendering::XSprite >(); 249*b1cdbd2cSJim Jagielski } 250*b1cdbd2cSJim Jagielski updateScreen(sal_Bool bUpdateAll,bool & io_bSurfaceDirty)251*b1cdbd2cSJim Jagielski sal_Bool SpriteCanvasHelper::updateScreen( sal_Bool bUpdateAll, 252*b1cdbd2cSJim Jagielski bool& io_bSurfaceDirty ) 253*b1cdbd2cSJim Jagielski { 254*b1cdbd2cSJim Jagielski if( !mpRedrawManager || 255*b1cdbd2cSJim Jagielski !mpOwningSpriteCanvas || 256*b1cdbd2cSJim Jagielski !mpOwningSpriteCanvas->getFrontBuffer() || 257*b1cdbd2cSJim Jagielski !mpOwningSpriteCanvas->getBackBuffer() ) 258*b1cdbd2cSJim Jagielski { 259*b1cdbd2cSJim Jagielski return sal_False; // disposed, or otherwise dysfunctional 260*b1cdbd2cSJim Jagielski } 261*b1cdbd2cSJim Jagielski 262*b1cdbd2cSJim Jagielski // commit to backbuffer 263*b1cdbd2cSJim Jagielski flush(); 264*b1cdbd2cSJim Jagielski 265*b1cdbd2cSJim Jagielski OutputDevice& rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() ); 266*b1cdbd2cSJim Jagielski BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() ); 267*b1cdbd2cSJim Jagielski OutputDevice& rBackOutDev( pBackBuffer->getOutDev() ); 268*b1cdbd2cSJim Jagielski 269*b1cdbd2cSJim Jagielski // actual OutputDevice is a shared resource - restore its 270*b1cdbd2cSJim Jagielski // state when done. 271*b1cdbd2cSJim Jagielski tools::OutDevStateKeeper aStateKeeper( rOutDev ); 272*b1cdbd2cSJim Jagielski 273*b1cdbd2cSJim Jagielski const Size aOutDevSize( rBackOutDev.GetOutputSizePixel() ); 274*b1cdbd2cSJim Jagielski const Point aEmptyPoint(0,0); 275*b1cdbd2cSJim Jagielski 276*b1cdbd2cSJim Jagielski Window* pTargetWindow = NULL; 277*b1cdbd2cSJim Jagielski if( rOutDev.GetOutDevType() == OUTDEV_WINDOW ) 278*b1cdbd2cSJim Jagielski { 279*b1cdbd2cSJim Jagielski pTargetWindow = &static_cast<Window&>(rOutDev); // TODO(Q3): Evil downcast. 280*b1cdbd2cSJim Jagielski 281*b1cdbd2cSJim Jagielski // we're double-buffered, thus no need for paint area-limiting 282*b1cdbd2cSJim Jagielski // clips. besides that, will interfere with animations (as for 283*b1cdbd2cSJim Jagielski // Window-invalidate repaints, only parts of the window will 284*b1cdbd2cSJim Jagielski // be redrawn otherwise) 285*b1cdbd2cSJim Jagielski const Region aFullWindowRegion( Rectangle(aEmptyPoint, 286*b1cdbd2cSJim Jagielski aOutDevSize) ); 287*b1cdbd2cSJim Jagielski pTargetWindow->ExpandPaintClipRegion(aFullWindowRegion); 288*b1cdbd2cSJim Jagielski } 289*b1cdbd2cSJim Jagielski 290*b1cdbd2cSJim Jagielski // TODO(P1): Might be worthwile to track areas of background 291*b1cdbd2cSJim Jagielski // changes, too. 292*b1cdbd2cSJim Jagielski if( !bUpdateAll && !io_bSurfaceDirty ) 293*b1cdbd2cSJim Jagielski { 294*b1cdbd2cSJim Jagielski if( mbShowFrameInfo ) 295*b1cdbd2cSJim Jagielski { 296*b1cdbd2cSJim Jagielski // also repaint background below frame counter (fake 297*b1cdbd2cSJim Jagielski // that as a sprite vanishing in this area) 298*b1cdbd2cSJim Jagielski mpRedrawManager->updateSprite( ::canvas::Sprite::Reference(), 299*b1cdbd2cSJim Jagielski ::basegfx::B2DPoint(), 300*b1cdbd2cSJim Jagielski ::basegfx::B2DRectangle( 0.0, 0.0, 301*b1cdbd2cSJim Jagielski FPS_BOUNDS.Right(), 302*b1cdbd2cSJim Jagielski FPS_BOUNDS.Bottom() ) ); 303*b1cdbd2cSJim Jagielski } 304*b1cdbd2cSJim Jagielski 305*b1cdbd2cSJim Jagielski // background has not changed, so we're free to optimize 306*b1cdbd2cSJim Jagielski // repaint to areas where a sprite has changed 307*b1cdbd2cSJim Jagielski 308*b1cdbd2cSJim Jagielski // process each independent area of overlapping sprites 309*b1cdbd2cSJim Jagielski // separately. 310*b1cdbd2cSJim Jagielski mpRedrawManager->forEachSpriteArea( *this ); 311*b1cdbd2cSJim Jagielski } 312*b1cdbd2cSJim Jagielski else 313*b1cdbd2cSJim Jagielski { 314*b1cdbd2cSJim Jagielski // background has changed, so we currently have no choice 315*b1cdbd2cSJim Jagielski // but repaint everything (or caller requested that) 316*b1cdbd2cSJim Jagielski 317*b1cdbd2cSJim Jagielski maVDev->SetOutputSizePixel( aOutDevSize ); 318*b1cdbd2cSJim Jagielski maVDev->EnableMapMode( sal_False ); 319*b1cdbd2cSJim Jagielski maVDev->DrawOutDev( aEmptyPoint, aOutDevSize, 320*b1cdbd2cSJim Jagielski aEmptyPoint, aOutDevSize, 321*b1cdbd2cSJim Jagielski rBackOutDev ); 322*b1cdbd2cSJim Jagielski 323*b1cdbd2cSJim Jagielski // repaint all active sprites on top of background into 324*b1cdbd2cSJim Jagielski // VDev. 325*b1cdbd2cSJim Jagielski mpRedrawManager->forEachSprite( 326*b1cdbd2cSJim Jagielski ::boost::bind( 327*b1cdbd2cSJim Jagielski &spriteRedraw, 328*b1cdbd2cSJim Jagielski ::boost::ref( maVDev.get() ), 329*b1cdbd2cSJim Jagielski _1 ) ); 330*b1cdbd2cSJim Jagielski 331*b1cdbd2cSJim Jagielski // flush to screen 332*b1cdbd2cSJim Jagielski rOutDev.EnableMapMode( sal_False ); 333*b1cdbd2cSJim Jagielski rOutDev.SetAntialiasing( ANTIALIASING_ENABLE_B2DDRAW ); 334*b1cdbd2cSJim Jagielski rOutDev.SetClipRegion(); 335*b1cdbd2cSJim Jagielski rOutDev.DrawOutDev( aEmptyPoint, aOutDevSize, 336*b1cdbd2cSJim Jagielski aEmptyPoint, aOutDevSize, 337*b1cdbd2cSJim Jagielski *maVDev ); 338*b1cdbd2cSJim Jagielski } 339*b1cdbd2cSJim Jagielski 340*b1cdbd2cSJim Jagielski // change record vector must be cleared, for the next turn of 341*b1cdbd2cSJim Jagielski // rendering and sprite changing 342*b1cdbd2cSJim Jagielski mpRedrawManager->clearChangeRecords(); 343*b1cdbd2cSJim Jagielski 344*b1cdbd2cSJim Jagielski io_bSurfaceDirty = false; 345*b1cdbd2cSJim Jagielski 346*b1cdbd2cSJim Jagielski if( mbShowFrameInfo ) 347*b1cdbd2cSJim Jagielski { 348*b1cdbd2cSJim Jagielski renderFrameCounter( rOutDev ); 349*b1cdbd2cSJim Jagielski renderSpriteCount( rOutDev ); 350*b1cdbd2cSJim Jagielski renderMemUsage( rOutDev ); 351*b1cdbd2cSJim Jagielski } 352*b1cdbd2cSJim Jagielski 353*b1cdbd2cSJim Jagielski #if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0 354*b1cdbd2cSJim Jagielski static ::canvas::tools::ElapsedTime aElapsedTime; 355*b1cdbd2cSJim Jagielski 356*b1cdbd2cSJim Jagielski // log time immediately after surface flip 357*b1cdbd2cSJim Jagielski OSL_TRACE( "SpriteCanvasHelper::updateScreen(): flip done at %f", 358*b1cdbd2cSJim Jagielski aElapsedTime.getElapsedTime() ); 359*b1cdbd2cSJim Jagielski #endif 360*b1cdbd2cSJim Jagielski 361*b1cdbd2cSJim Jagielski // sync output with screen, to ensure that we don't queue up 362*b1cdbd2cSJim Jagielski // render requests (calling code might rely on timing, 363*b1cdbd2cSJim Jagielski // i.e. assume that things are visible on screen after 364*b1cdbd2cSJim Jagielski // updateScreen() returns). 365*b1cdbd2cSJim Jagielski if( pTargetWindow ) 366*b1cdbd2cSJim Jagielski { 367*b1cdbd2cSJim Jagielski // commit to screen 368*b1cdbd2cSJim Jagielski pTargetWindow->Sync(); 369*b1cdbd2cSJim Jagielski } 370*b1cdbd2cSJim Jagielski 371*b1cdbd2cSJim Jagielski return sal_True; 372*b1cdbd2cSJim Jagielski } 373*b1cdbd2cSJim Jagielski backgroundPaint(const::basegfx::B2DRange & rUpdateRect)374*b1cdbd2cSJim Jagielski void SpriteCanvasHelper::backgroundPaint( const ::basegfx::B2DRange& rUpdateRect ) 375*b1cdbd2cSJim Jagielski { 376*b1cdbd2cSJim Jagielski ENSURE_OR_THROW( mpOwningSpriteCanvas && 377*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas->getBackBuffer() && 378*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas->getFrontBuffer(), 379*b1cdbd2cSJim Jagielski "SpriteCanvasHelper::backgroundPaint(): NULL device pointer " ); 380*b1cdbd2cSJim Jagielski 381*b1cdbd2cSJim Jagielski OutputDevice& rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() ); 382*b1cdbd2cSJim Jagielski BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() ); 383*b1cdbd2cSJim Jagielski OutputDevice& rBackOutDev( pBackBuffer->getOutDev() ); 384*b1cdbd2cSJim Jagielski 385*b1cdbd2cSJim Jagielski repaintBackground( rOutDev, rBackOutDev, rUpdateRect ); 386*b1cdbd2cSJim Jagielski } 387*b1cdbd2cSJim Jagielski scrollUpdate(const::basegfx::B2DRange & rMoveStart,const::basegfx::B2DRange & rMoveEnd,const::canvas::SpriteRedrawManager::UpdateArea & rUpdateArea)388*b1cdbd2cSJim Jagielski void SpriteCanvasHelper::scrollUpdate( const ::basegfx::B2DRange& rMoveStart, 389*b1cdbd2cSJim Jagielski const ::basegfx::B2DRange& rMoveEnd, 390*b1cdbd2cSJim Jagielski const ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea ) 391*b1cdbd2cSJim Jagielski { 392*b1cdbd2cSJim Jagielski ENSURE_OR_THROW( mpOwningSpriteCanvas && 393*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas->getBackBuffer() && 394*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas->getFrontBuffer(), 395*b1cdbd2cSJim Jagielski "SpriteCanvasHelper::scrollUpdate(): NULL device pointer " ); 396*b1cdbd2cSJim Jagielski 397*b1cdbd2cSJim Jagielski OutputDevice& rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() ); 398*b1cdbd2cSJim Jagielski BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() ); 399*b1cdbd2cSJim Jagielski OutputDevice& rBackOutDev( pBackBuffer->getOutDev() ); 400*b1cdbd2cSJim Jagielski 401*b1cdbd2cSJim Jagielski const Size& rTargetSizePixel( rOutDev.GetOutputSizePixel() ); 402*b1cdbd2cSJim Jagielski const ::basegfx::B2IRange aOutputBounds( 0,0, 403*b1cdbd2cSJim Jagielski rTargetSizePixel.Width(), 404*b1cdbd2cSJim Jagielski rTargetSizePixel.Height() ); 405*b1cdbd2cSJim Jagielski 406*b1cdbd2cSJim Jagielski // round rectangles to integer pixel. Note: have to be 407*b1cdbd2cSJim Jagielski // extremely careful here, to avoid off-by-one errors for 408*b1cdbd2cSJim Jagielski // the destination area: otherwise, the next scroll update 409*b1cdbd2cSJim Jagielski // would copy pixel that are not supposed to be part of 410*b1cdbd2cSJim Jagielski // the sprite. 411*b1cdbd2cSJim Jagielski ::basegfx::B2IRange aSourceRect( 412*b1cdbd2cSJim Jagielski ::canvas::tools::spritePixelAreaFromB2DRange( rMoveStart ) ); 413*b1cdbd2cSJim Jagielski const ::basegfx::B2IRange& rDestRect( 414*b1cdbd2cSJim Jagielski ::canvas::tools::spritePixelAreaFromB2DRange( rMoveEnd ) ); 415*b1cdbd2cSJim Jagielski ::basegfx::B2IPoint aDestPos( rDestRect.getMinimum() ); 416*b1cdbd2cSJim Jagielski 417*b1cdbd2cSJim Jagielski ::std::vector< ::basegfx::B2IRange > aUnscrollableAreas; 418*b1cdbd2cSJim Jagielski 419*b1cdbd2cSJim Jagielski // Since strictly speaking, this scroll algorithm is plain 420*b1cdbd2cSJim Jagielski // buggy, the scrolled area might actually lie _below_ another 421*b1cdbd2cSJim Jagielski // window - we've made this feature configurable via 422*b1cdbd2cSJim Jagielski // mbIsUnsafeScrolling. 423*b1cdbd2cSJim Jagielski 424*b1cdbd2cSJim Jagielski // clip to output bounds (cannot properly scroll stuff 425*b1cdbd2cSJim Jagielski // _outside_ our screen area) 426*b1cdbd2cSJim Jagielski if( !mbIsUnsafeScrolling || 427*b1cdbd2cSJim Jagielski !::canvas::tools::clipScrollArea( aSourceRect, 428*b1cdbd2cSJim Jagielski aDestPos, 429*b1cdbd2cSJim Jagielski aUnscrollableAreas, 430*b1cdbd2cSJim Jagielski aOutputBounds ) ) 431*b1cdbd2cSJim Jagielski { 432*b1cdbd2cSJim Jagielski // fully clipped scroll area: cannot simply scroll 433*b1cdbd2cSJim Jagielski // then. Perform normal opaque update (can use that, since 434*b1cdbd2cSJim Jagielski // one of the preconditions for scrollable update is 435*b1cdbd2cSJim Jagielski // opaque sprite content) 436*b1cdbd2cSJim Jagielski 437*b1cdbd2cSJim Jagielski // repaint all affected sprites directly to output device 438*b1cdbd2cSJim Jagielski ::std::for_each( rUpdateArea.maComponentList.begin(), 439*b1cdbd2cSJim Jagielski rUpdateArea.maComponentList.end(), 440*b1cdbd2cSJim Jagielski ::boost::bind( 441*b1cdbd2cSJim Jagielski &spriteRedrawStub3, 442*b1cdbd2cSJim Jagielski ::boost::ref( rOutDev ), 443*b1cdbd2cSJim Jagielski _1 ) ); 444*b1cdbd2cSJim Jagielski } 445*b1cdbd2cSJim Jagielski else 446*b1cdbd2cSJim Jagielski { 447*b1cdbd2cSJim Jagielski // scroll rOutDev content 448*b1cdbd2cSJim Jagielski rOutDev.CopyArea( ::vcl::unotools::pointFromB2IPoint( aDestPos ), 449*b1cdbd2cSJim Jagielski ::vcl::unotools::pointFromB2IPoint( aSourceRect.getMinimum() ), 450*b1cdbd2cSJim Jagielski // TODO(Q2): use numeric_cast to check range 451*b1cdbd2cSJim Jagielski ::Size( static_cast<sal_Int32>(aSourceRect.getRange().getX()), 452*b1cdbd2cSJim Jagielski static_cast<sal_Int32>(aSourceRect.getRange().getY()) ) ); 453*b1cdbd2cSJim Jagielski 454*b1cdbd2cSJim Jagielski const ::canvas::SpriteRedrawManager::SpriteConnectedRanges::ComponentListType::const_iterator 455*b1cdbd2cSJim Jagielski aFirst( rUpdateArea.maComponentList.begin() ); 456*b1cdbd2cSJim Jagielski ::canvas::SpriteRedrawManager::SpriteConnectedRanges::ComponentListType::const_iterator 457*b1cdbd2cSJim Jagielski aSecond( aFirst ); ++aSecond; 458*b1cdbd2cSJim Jagielski 459*b1cdbd2cSJim Jagielski ENSURE_OR_THROW( aFirst->second.getSprite().is(), 460*b1cdbd2cSJim Jagielski "VCLCanvas::scrollUpdate(): no sprite" ); 461*b1cdbd2cSJim Jagielski 462*b1cdbd2cSJim Jagielski // repaint uncovered areas from sprite. Need to actually 463*b1cdbd2cSJim Jagielski // clip here, since we're only repainting _parts_ of the 464*b1cdbd2cSJim Jagielski // sprite 465*b1cdbd2cSJim Jagielski rOutDev.Push( PUSH_CLIPREGION ); 466*b1cdbd2cSJim Jagielski ::std::for_each( aUnscrollableAreas.begin(), 467*b1cdbd2cSJim Jagielski aUnscrollableAreas.end(), 468*b1cdbd2cSJim Jagielski ::boost::bind( &opaqueUpdateSpriteArea, 469*b1cdbd2cSJim Jagielski ::boost::cref(aFirst->second.getSprite()), 470*b1cdbd2cSJim Jagielski ::boost::ref(rOutDev), 471*b1cdbd2cSJim Jagielski _1 ) ); 472*b1cdbd2cSJim Jagielski rOutDev.Pop(); 473*b1cdbd2cSJim Jagielski } 474*b1cdbd2cSJim Jagielski 475*b1cdbd2cSJim Jagielski // repaint uncovered areas from backbuffer - take the 476*b1cdbd2cSJim Jagielski // _rounded_ rectangles from above, to have the update 477*b1cdbd2cSJim Jagielski // consistent with the scroll above. 478*b1cdbd2cSJim Jagielski ::std::vector< ::basegfx::B2DRange > aUncoveredAreas; 479*b1cdbd2cSJim Jagielski ::basegfx::computeSetDifference( aUncoveredAreas, 480*b1cdbd2cSJim Jagielski rUpdateArea.maTotalBounds, 481*b1cdbd2cSJim Jagielski ::basegfx::B2DRange( rDestRect ) ); 482*b1cdbd2cSJim Jagielski ::std::for_each( aUncoveredAreas.begin(), 483*b1cdbd2cSJim Jagielski aUncoveredAreas.end(), 484*b1cdbd2cSJim Jagielski ::boost::bind( &repaintBackground, 485*b1cdbd2cSJim Jagielski ::boost::ref(rOutDev), 486*b1cdbd2cSJim Jagielski ::boost::ref(rBackOutDev), 487*b1cdbd2cSJim Jagielski _1 ) ); 488*b1cdbd2cSJim Jagielski } 489*b1cdbd2cSJim Jagielski opaqueUpdate(const::basegfx::B2DRange & rTotalArea,const::std::vector<::canvas::Sprite::Reference> & rSortedUpdateSprites)490*b1cdbd2cSJim Jagielski void SpriteCanvasHelper::opaqueUpdate( const ::basegfx::B2DRange& rTotalArea, 491*b1cdbd2cSJim Jagielski const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ) 492*b1cdbd2cSJim Jagielski { 493*b1cdbd2cSJim Jagielski (void)rTotalArea; 494*b1cdbd2cSJim Jagielski 495*b1cdbd2cSJim Jagielski ENSURE_OR_THROW( mpOwningSpriteCanvas && 496*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas->getBackBuffer() && 497*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas->getFrontBuffer(), 498*b1cdbd2cSJim Jagielski "SpriteCanvasHelper::opaqueUpdate(): NULL device pointer " ); 499*b1cdbd2cSJim Jagielski 500*b1cdbd2cSJim Jagielski OutputDevice& rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() ); 501*b1cdbd2cSJim Jagielski 502*b1cdbd2cSJim Jagielski // no need to clip output to actual update region - there will 503*b1cdbd2cSJim Jagielski // always be ALL sprites contained in the rectangular update 504*b1cdbd2cSJim Jagielski // area containd in rTotalArea (that's the way 505*b1cdbd2cSJim Jagielski // B2DConnectedRanges work). If rTotalArea appears to be 506*b1cdbd2cSJim Jagielski // smaller than the sprite - then this sprite carries a clip, 507*b1cdbd2cSJim Jagielski // and the update will be constrained to that rect. 508*b1cdbd2cSJim Jagielski 509*b1cdbd2cSJim Jagielski // repaint all affected sprites directly to output device 510*b1cdbd2cSJim Jagielski ::std::for_each( rSortedUpdateSprites.begin(), 511*b1cdbd2cSJim Jagielski rSortedUpdateSprites.end(), 512*b1cdbd2cSJim Jagielski ::boost::bind( 513*b1cdbd2cSJim Jagielski &spriteRedrawStub, 514*b1cdbd2cSJim Jagielski ::boost::ref( rOutDev ), 515*b1cdbd2cSJim Jagielski _1 ) ); 516*b1cdbd2cSJim Jagielski } 517*b1cdbd2cSJim Jagielski genericUpdate(const::basegfx::B2DRange & rRequestedArea,const::std::vector<::canvas::Sprite::Reference> & rSortedUpdateSprites)518*b1cdbd2cSJim Jagielski void SpriteCanvasHelper::genericUpdate( const ::basegfx::B2DRange& rRequestedArea, 519*b1cdbd2cSJim Jagielski const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ) 520*b1cdbd2cSJim Jagielski { 521*b1cdbd2cSJim Jagielski ENSURE_OR_THROW( mpOwningSpriteCanvas && 522*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas->getBackBuffer() && 523*b1cdbd2cSJim Jagielski mpOwningSpriteCanvas->getFrontBuffer(), 524*b1cdbd2cSJim Jagielski "SpriteCanvasHelper::genericUpdate(): NULL device pointer " ); 525*b1cdbd2cSJim Jagielski 526*b1cdbd2cSJim Jagielski OutputDevice& rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() ); 527*b1cdbd2cSJim Jagielski BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() ); 528*b1cdbd2cSJim Jagielski OutputDevice& rBackOutDev( pBackBuffer->getOutDev() ); 529*b1cdbd2cSJim Jagielski 530*b1cdbd2cSJim Jagielski // limit size of update VDev to target outdev's size 531*b1cdbd2cSJim Jagielski const Size& rTargetSizePixel( rOutDev.GetOutputSizePixel() ); 532*b1cdbd2cSJim Jagielski 533*b1cdbd2cSJim Jagielski // round output position towards zero. Don't want to truncate 534*b1cdbd2cSJim Jagielski // a fraction of a sprite pixel... Clip position at origin, 535*b1cdbd2cSJim Jagielski // otherwise, truncation of size below might leave visible 536*b1cdbd2cSJim Jagielski // areas uncovered by VDev. 537*b1cdbd2cSJim Jagielski const ::Point aOutputPosition( 538*b1cdbd2cSJim Jagielski ::std::max( sal_Int32( 0 ), 539*b1cdbd2cSJim Jagielski static_cast< sal_Int32 >(rRequestedArea.getMinX()) ), 540*b1cdbd2cSJim Jagielski ::std::max( sal_Int32( 0 ), 541*b1cdbd2cSJim Jagielski static_cast< sal_Int32 >(rRequestedArea.getMinY()) ) ); 542*b1cdbd2cSJim Jagielski // round output size towards +infty. Don't want to truncate a 543*b1cdbd2cSJim Jagielski // fraction of a sprite pixel... Limit coverage of VDev to 544*b1cdbd2cSJim Jagielski // output device's area (i.e. not only to total size, but to 545*b1cdbd2cSJim Jagielski // cover _only_ the visible parts). 546*b1cdbd2cSJim Jagielski const ::Size aOutputSize( 547*b1cdbd2cSJim Jagielski ::std::max( sal_Int32( 0 ), 548*b1cdbd2cSJim Jagielski ::std::min( static_cast< sal_Int32 >(rTargetSizePixel.Width() - aOutputPosition.X()), 549*b1cdbd2cSJim Jagielski ::canvas::tools::roundUp( rRequestedArea.getMaxX() - aOutputPosition.X() ))), 550*b1cdbd2cSJim Jagielski ::std::max( sal_Int32( 0 ), 551*b1cdbd2cSJim Jagielski ::std::min( static_cast< sal_Int32 >(rTargetSizePixel.Height() - aOutputPosition.Y()), 552*b1cdbd2cSJim Jagielski ::canvas::tools::roundUp( rRequestedArea.getMaxY() - aOutputPosition.Y() )))); 553*b1cdbd2cSJim Jagielski 554*b1cdbd2cSJim Jagielski // early exit for empty output area. 555*b1cdbd2cSJim Jagielski if( aOutputSize.Width() == 0 && 556*b1cdbd2cSJim Jagielski aOutputSize.Height() == 0 ) 557*b1cdbd2cSJim Jagielski { 558*b1cdbd2cSJim Jagielski return; 559*b1cdbd2cSJim Jagielski } 560*b1cdbd2cSJim Jagielski 561*b1cdbd2cSJim Jagielski const Point aEmptyPoint(0,0); 562*b1cdbd2cSJim Jagielski const Size aCurrOutputSize( maVDev->GetOutputSizePixel() ); 563*b1cdbd2cSJim Jagielski 564*b1cdbd2cSJim Jagielski // adapt maVDev's size to the area that actually needs the 565*b1cdbd2cSJim Jagielski // repaint. 566*b1cdbd2cSJim Jagielski if( aCurrOutputSize.Width() < aOutputSize.Width() || 567*b1cdbd2cSJim Jagielski aCurrOutputSize.Height() < aOutputSize.Height() ) 568*b1cdbd2cSJim Jagielski { 569*b1cdbd2cSJim Jagielski // TODO(P1): Come up with a clever tactic to reduce maVDev 570*b1cdbd2cSJim Jagielski // from time to time. Reduction with threshold (say, if 571*b1cdbd2cSJim Jagielski // maVDev is more than twice too large) is not wise, as 572*b1cdbd2cSJim Jagielski // this might then toggle within the same updateScreen(), 573*b1cdbd2cSJim Jagielski // but for different disjunct sprite areas. 574*b1cdbd2cSJim Jagielski maVDev->SetOutputSizePixel( aOutputSize ); 575*b1cdbd2cSJim Jagielski } 576*b1cdbd2cSJim Jagielski 577*b1cdbd2cSJim Jagielski // paint background 578*b1cdbd2cSJim Jagielski maVDev->EnableMapMode( sal_False ); 579*b1cdbd2cSJim Jagielski maVDev->SetAntialiasing( ANTIALIASING_ENABLE_B2DDRAW ); 580*b1cdbd2cSJim Jagielski maVDev->SetClipRegion(); 581*b1cdbd2cSJim Jagielski maVDev->DrawOutDev( aEmptyPoint, aOutputSize, 582*b1cdbd2cSJim Jagielski aOutputPosition, aOutputSize, 583*b1cdbd2cSJim Jagielski rBackOutDev ); 584*b1cdbd2cSJim Jagielski 585*b1cdbd2cSJim Jagielski // repaint all affected sprites on top of background into 586*b1cdbd2cSJim Jagielski // VDev. 587*b1cdbd2cSJim Jagielski ::std::for_each( rSortedUpdateSprites.begin(), 588*b1cdbd2cSJim Jagielski rSortedUpdateSprites.end(), 589*b1cdbd2cSJim Jagielski ::boost::bind( &spriteRedrawStub2, 590*b1cdbd2cSJim Jagielski ::boost::ref( maVDev.get() ), 591*b1cdbd2cSJim Jagielski ::boost::cref( 592*b1cdbd2cSJim Jagielski ::vcl::unotools::b2DPointFromPoint(aOutputPosition)), 593*b1cdbd2cSJim Jagielski _1 ) ); 594*b1cdbd2cSJim Jagielski 595*b1cdbd2cSJim Jagielski // flush to screen 596*b1cdbd2cSJim Jagielski rOutDev.EnableMapMode( sal_False ); 597*b1cdbd2cSJim Jagielski rOutDev.SetAntialiasing( ANTIALIASING_ENABLE_B2DDRAW ); 598*b1cdbd2cSJim Jagielski rOutDev.DrawOutDev( aOutputPosition, aOutputSize, 599*b1cdbd2cSJim Jagielski aEmptyPoint, aOutputSize, 600*b1cdbd2cSJim Jagielski *maVDev ); 601*b1cdbd2cSJim Jagielski } 602*b1cdbd2cSJim Jagielski renderFrameCounter(OutputDevice & rOutDev)603*b1cdbd2cSJim Jagielski void SpriteCanvasHelper::renderFrameCounter( OutputDevice& rOutDev ) 604*b1cdbd2cSJim Jagielski { 605*b1cdbd2cSJim Jagielski const double denominator( maLastUpdate.getElapsedTime() ); 606*b1cdbd2cSJim Jagielski maLastUpdate.reset(); 607*b1cdbd2cSJim Jagielski 608*b1cdbd2cSJim Jagielski ::rtl::OUString text( ::rtl::math::doubleToUString( denominator == 0.0 ? 100.0 : 1.0/denominator, 609*b1cdbd2cSJim Jagielski rtl_math_StringFormat_F, 610*b1cdbd2cSJim Jagielski 2,'.',NULL,' ') ); 611*b1cdbd2cSJim Jagielski 612*b1cdbd2cSJim Jagielski // pad with leading space 613*b1cdbd2cSJim Jagielski while( text.getLength() < 6 ) 614*b1cdbd2cSJim Jagielski text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; 615*b1cdbd2cSJim Jagielski 616*b1cdbd2cSJim Jagielski text += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" fps")); 617*b1cdbd2cSJim Jagielski 618*b1cdbd2cSJim Jagielski renderInfoText( rOutDev, 619*b1cdbd2cSJim Jagielski text, 620*b1cdbd2cSJim Jagielski Point(0, 0) ); 621*b1cdbd2cSJim Jagielski } 622*b1cdbd2cSJim Jagielski 623*b1cdbd2cSJim Jagielski namespace 624*b1cdbd2cSJim Jagielski { 625*b1cdbd2cSJim Jagielski template< typename T > struct Adder 626*b1cdbd2cSJim Jagielski { 627*b1cdbd2cSJim Jagielski typedef void result_type; 628*b1cdbd2cSJim Jagielski Addervclcanvas::__anon7cf828720211::Adder629*b1cdbd2cSJim Jagielski Adder( T& rAdderTarget, 630*b1cdbd2cSJim Jagielski T nIncrement ) : 631*b1cdbd2cSJim Jagielski mpTarget( &rAdderTarget ), 632*b1cdbd2cSJim Jagielski mnIncrement( nIncrement ) 633*b1cdbd2cSJim Jagielski { 634*b1cdbd2cSJim Jagielski } 635*b1cdbd2cSJim Jagielski operator ()vclcanvas::__anon7cf828720211::Adder636*b1cdbd2cSJim Jagielski void operator()() { *mpTarget += mnIncrement; } operator ()vclcanvas::__anon7cf828720211::Adder637*b1cdbd2cSJim Jagielski void operator()( const ::canvas::Sprite::Reference& ) { *mpTarget += mnIncrement; } operator ()vclcanvas::__anon7cf828720211::Adder638*b1cdbd2cSJim Jagielski void operator()( T nIncrement ) { *mpTarget += nIncrement; } 639*b1cdbd2cSJim Jagielski 640*b1cdbd2cSJim Jagielski T* mpTarget; 641*b1cdbd2cSJim Jagielski T mnIncrement; 642*b1cdbd2cSJim Jagielski }; 643*b1cdbd2cSJim Jagielski makeAdder(T & rAdderTarget,T nIncrement)644*b1cdbd2cSJim Jagielski template< typename T> Adder<T> makeAdder( T& rAdderTarget, 645*b1cdbd2cSJim Jagielski T nIncrement ) 646*b1cdbd2cSJim Jagielski { 647*b1cdbd2cSJim Jagielski return Adder<T>(rAdderTarget, nIncrement); 648*b1cdbd2cSJim Jagielski } 649*b1cdbd2cSJim Jagielski } 650*b1cdbd2cSJim Jagielski renderSpriteCount(OutputDevice & rOutDev)651*b1cdbd2cSJim Jagielski void SpriteCanvasHelper::renderSpriteCount( OutputDevice& rOutDev ) 652*b1cdbd2cSJim Jagielski { 653*b1cdbd2cSJim Jagielski if( mpRedrawManager ) 654*b1cdbd2cSJim Jagielski { 655*b1cdbd2cSJim Jagielski sal_Int32 nCount(0); 656*b1cdbd2cSJim Jagielski 657*b1cdbd2cSJim Jagielski mpRedrawManager->forEachSprite( makeAdder(nCount,sal_Int32(1)) ); 658*b1cdbd2cSJim Jagielski ::rtl::OUString text( 659*b1cdbd2cSJim Jagielski ::rtl::OUString::valueOf( 660*b1cdbd2cSJim Jagielski // disambiguate overload... 661*b1cdbd2cSJim Jagielski static_cast<sal_Int64>(nCount) ) ); 662*b1cdbd2cSJim Jagielski 663*b1cdbd2cSJim Jagielski // pad with leading space 664*b1cdbd2cSJim Jagielski while( text.getLength() < 3 ) 665*b1cdbd2cSJim Jagielski text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; 666*b1cdbd2cSJim Jagielski 667*b1cdbd2cSJim Jagielski text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("Sprites: ")) + text; 668*b1cdbd2cSJim Jagielski 669*b1cdbd2cSJim Jagielski renderInfoText( rOutDev, 670*b1cdbd2cSJim Jagielski text, 671*b1cdbd2cSJim Jagielski Point(0, 30) ); 672*b1cdbd2cSJim Jagielski } 673*b1cdbd2cSJim Jagielski } 674*b1cdbd2cSJim Jagielski renderMemUsage(OutputDevice & rOutDev)675*b1cdbd2cSJim Jagielski void SpriteCanvasHelper::renderMemUsage( OutputDevice& rOutDev ) 676*b1cdbd2cSJim Jagielski { 677*b1cdbd2cSJim Jagielski BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() ); 678*b1cdbd2cSJim Jagielski 679*b1cdbd2cSJim Jagielski if( mpRedrawManager && 680*b1cdbd2cSJim Jagielski pBackBuffer ) 681*b1cdbd2cSJim Jagielski { 682*b1cdbd2cSJim Jagielski double nPixel(0.0); 683*b1cdbd2cSJim Jagielski 684*b1cdbd2cSJim Jagielski // accumulate pixel count for each sprite into fCount 685*b1cdbd2cSJim Jagielski mpRedrawManager->forEachSprite( ::boost::bind( 686*b1cdbd2cSJim Jagielski makeAdder(nPixel,1.0), 687*b1cdbd2cSJim Jagielski ::boost::bind( 688*b1cdbd2cSJim Jagielski &calcNumPixel, 689*b1cdbd2cSJim Jagielski _1 ) ) ); 690*b1cdbd2cSJim Jagielski 691*b1cdbd2cSJim Jagielski static const int NUM_VIRDEV(2); 692*b1cdbd2cSJim Jagielski static const int BYTES_PER_PIXEL(3); 693*b1cdbd2cSJim Jagielski 694*b1cdbd2cSJim Jagielski const Size& rVDevSize( maVDev->GetOutputSizePixel() ); 695*b1cdbd2cSJim Jagielski const Size& rBackBufferSize( pBackBuffer->getOutDev().GetOutputSizePixel() ); 696*b1cdbd2cSJim Jagielski 697*b1cdbd2cSJim Jagielski const double nMemUsage( nPixel * NUM_VIRDEV * BYTES_PER_PIXEL + 698*b1cdbd2cSJim Jagielski rVDevSize.Width()*rVDevSize.Height() * BYTES_PER_PIXEL + 699*b1cdbd2cSJim Jagielski rBackBufferSize.Width()*rBackBufferSize.Height() * BYTES_PER_PIXEL ); 700*b1cdbd2cSJim Jagielski 701*b1cdbd2cSJim Jagielski ::rtl::OUString text( ::rtl::math::doubleToUString( nMemUsage / 1048576.0, 702*b1cdbd2cSJim Jagielski rtl_math_StringFormat_F, 703*b1cdbd2cSJim Jagielski 2,'.',NULL,' ') ); 704*b1cdbd2cSJim Jagielski 705*b1cdbd2cSJim Jagielski // pad with leading space 706*b1cdbd2cSJim Jagielski while( text.getLength() < 4 ) 707*b1cdbd2cSJim Jagielski text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; 708*b1cdbd2cSJim Jagielski 709*b1cdbd2cSJim Jagielski text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("Mem: ")) + 710*b1cdbd2cSJim Jagielski text + 711*b1cdbd2cSJim Jagielski ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("MB")); 712*b1cdbd2cSJim Jagielski 713*b1cdbd2cSJim Jagielski renderInfoText( rOutDev, 714*b1cdbd2cSJim Jagielski text, 715*b1cdbd2cSJim Jagielski Point(0, 60) ); 716*b1cdbd2cSJim Jagielski } 717*b1cdbd2cSJim Jagielski } 718*b1cdbd2cSJim Jagielski } 719