diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /slideshow/source/engine/opengl/TransitionerImpl.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | slideshow/source/engine/opengl/TransitionerImpl.cxx | 1346 |
1 files changed, 1346 insertions, 0 deletions
diff --git a/slideshow/source/engine/opengl/TransitionerImpl.cxx b/slideshow/source/engine/opengl/TransitionerImpl.cxx new file mode 100644 index 000000000..faef77988 --- /dev/null +++ b/slideshow/source/engine/opengl/TransitionerImpl.cxx @@ -0,0 +1,1346 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <sal/types.h> + +#include <memory> + +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <com/sun/star/rendering/IntegerBitmapLayout.hpp> +#include <com/sun/star/rendering/ColorComponentTag.hpp> +#include <com/sun/star/rendering/ColorSpaceType.hpp> +#include <com/sun/star/rendering/RenderingIntent.hpp> +#include <com/sun/star/util/Endianness.hpp> +#include <com/sun/star/animations/TransitionType.hpp> +#undef IN +#undef OUT +#include <com/sun/star/animations/TransitionSubType.hpp> +#include <com/sun/star/presentation/XTransitionFactory.hpp> +#include <com/sun/star/presentation/XTransition.hpp> +#include <com/sun/star/presentation/XSlideShowView.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <com/sun/star/geometry/IntegerSize2D.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <rtl/ref.hxx> +#include <sal/log.hxx> + +#include <canvas/canvastools.hxx> + +#include <tools/diagnose_ex.h> + +#include <vcl/canvastools.hxx> +#include <vcl/opengl/OpenGLContext.hxx> +#include <vcl/opengl/OpenGLHelper.hxx> +#include <vcl/syschild.hxx> +#include <vcl/window.hxx> + +#include "TransitionImpl.hxx" + +#if OSL_DEBUG_LEVEL > 0 +#include <chrono> +#endif + +using namespace ::com::sun::star; +using ::com::sun::star::beans::XFastPropertySet; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; + +namespace +{ + +typedef cppu::WeakComponentImplHelper<presentation::XTransition> OGLTransitionerImplBase; + +#if OSL_DEBUG_LEVEL > 0 +class TimerContext +{ +public: + explicit TimerContext(OUString const& rWhat) + : m_aWhat(rWhat) + , m_StartTime(std::chrono::steady_clock::now()) + { + } + ~TimerContext() + { + auto const aDuration(std::chrono::steady_clock::now() - m_StartTime); + SAL_INFO("slideshow.opengl", m_aWhat << " took: " << std::chrono::duration_cast<std::chrono::microseconds>(aDuration).count()); + } +private: + OUString const m_aWhat; + std::chrono::steady_clock::time_point const m_StartTime; +}; +#endif + +struct OGLFormat +{ + GLint nInternalFormat; + GLenum eFormat; + GLenum eType; +}; + +/* channel ordering: (0:rgba, 1:bgra, 2:argb, 3:abgr) + */ +int calcComponentOrderIndex(const uno::Sequence<sal_Int8>& rTags) +{ + using namespace rendering::ColorComponentTag; + + static const sal_Int8 aOrderTable[] = + { + RGB_RED, RGB_GREEN, RGB_BLUE, ALPHA, + RGB_BLUE, RGB_GREEN, RGB_RED, ALPHA, + ALPHA, RGB_RED, RGB_GREEN, RGB_BLUE, + ALPHA, RGB_BLUE, RGB_GREEN, RGB_RED, + }; + + const sal_Int32 nNumComps(rTags.getLength()); + const sal_Int8* pLine=aOrderTable; + for(int i=0; i<4; ++i) + { + int j=0; + while( j<4 && j<nNumComps && pLine[j] == rTags[j] ) + ++j; + + // all of the line passed, this is a match! + if( j==nNumComps ) + return i; + + pLine+=4; + } + + return -1; +} + +/** This is the Transitioner class for OpenGL 3D transitions in + * slideshow. This class is implicitly + * constructed from XTransitionFactory. +*/ +class OGLTransitionerImpl : private cppu::BaseMutex, public OGLTransitionerImplBase +{ +public: + OGLTransitionerImpl(); + OGLTransitionerImpl(const OGLTransitionerImpl&) = delete; + OGLTransitionerImpl& operator=(const OGLTransitionerImpl&) = delete; + bool setTransition( const std::shared_ptr<OGLTransitionImpl>& pOGLTransition ); + bool initialize( const Reference< presentation::XSlideShowView >& xView, + const Reference< rendering::XBitmap >& xLeavingSlide, + const Reference< rendering::XBitmap >& xEnteringSlide ); + + // XTransition + virtual void SAL_CALL update( double nTime ) override; + virtual void SAL_CALL viewChanged( const Reference< presentation::XSlideShowView >& rView, + const Reference< rendering::XBitmap >& rLeavingBitmap, + const Reference< rendering::XBitmap >& rEnteringBitmap ) override; + +protected: + void disposeTextures(); + + // WeakComponentImplHelperBase + virtual void SAL_CALL disposing() override; + + bool isDisposed() const + { + return (rBHelper.bDisposed || rBHelper.bInDispose); + } + + void createTexture( GLuint* texID, + bool useMipmap, + const uno::Sequence<sal_Int8>& data, + const OGLFormat* pFormat ); + const OGLFormat* chooseFormats(); + +private: + void impl_initializeFlags( bool const bGLXPresent ); + + void impl_dispose(); + + void setSlides( const Reference< rendering::XBitmap >& xLeavingSlide , const uno::Reference< rendering::XBitmap >& xEnteringSlide ); + void impl_prepareSlides(); + + void impl_createTexture( bool useMipmap, const uno::Sequence<sal_Int8>& data, const OGLFormat* pFormat ); + + bool initWindowFromSlideShowView( const uno::Reference< presentation::XSlideShowView >& xView ); + /** After the window has been created, and the slides have been set, we'll initialize the slides with OpenGL. + */ + void GLInitSlides(); + + bool impl_prepareTransition(); + +private: + rtl::Reference<OpenGLContext> mpContext; + + /** OpenGL handle to the leaving slide's texture + */ + GLuint maLeavingSlideGL; + /** OpenGL handle to the entering slide's texture + */ + GLuint maEnteringSlideGL; + + Reference< presentation::XSlideShowView > mxView; + Reference< rendering::XIntegerBitmap > mxLeavingBitmap; + Reference< rendering::XIntegerBitmap > mxEnteringBitmap; + + /** raw bytes of the entering bitmap + */ + uno::Sequence<sal_Int8> maEnteringBytes; + + /** raw bytes of the leaving bitmap + */ + uno::Sequence<sal_Int8> maLeavingBytes; + + bool mbRestoreSync; + + /** the form the raw bytes are in for the bitmaps + */ + rendering::IntegerBitmapLayout maSlideBitmapLayout; + + /** the size of the slides + */ + geometry::IntegerSize2D maSlideSize; + + /** Our Transition to be used. + */ + std::shared_ptr<OGLTransitionImpl> mpTransition; + +public: + /** whether we are running on ATI fglrx with bug related to textures + */ + bool mbBrokenTexturesATI; + + /** GL version + */ + float mnGLVersion; + + /** + Whether the display has GLX extension on X11, always true otherwise (?) + */ + bool mbValidOpenGLContext; + +#if OSL_DEBUG_LEVEL > 0 + std::chrono::steady_clock::time_point m_UpdateStartTime; + std::chrono::steady_clock::time_point m_UpdateEndTime; + std::chrono::steady_clock::time_point m_StartTime; + std::chrono::steady_clock::time_point m_EndTime; + std::chrono::steady_clock::duration m_TotalUpdateDuration; + int mnFrameCount; +#endif +}; + +bool OGLTransitionerImpl::initialize( const Reference< presentation::XSlideShowView >& xView, + const Reference< rendering::XBitmap >& xLeavingSlide, + const Reference< rendering::XBitmap >& xEnteringSlide ) +{ + bool const bValidContext( initWindowFromSlideShowView( xView ) ); + impl_initializeFlags( bValidContext ); + + setSlides( xLeavingSlide, xEnteringSlide ); + + return mbValidOpenGLContext; +} + +void OGLTransitionerImpl::impl_initializeFlags( bool const bValidContext ) +{ + mbValidOpenGLContext = bValidContext; + if ( bValidContext ) { + CHECK_GL_ERROR(); + + mnGLVersion = OpenGLHelper::getGLVersion(); + SAL_INFO("slideshow.opengl", "GL version: " << mnGLVersion << "" ); + +#if defined( UNX ) && !defined( MACOSX ) + const GLubyte* vendor = glGetString( GL_VENDOR ); + /* TODO: check for version once the bug in fglrx driver is fixed */ + mbBrokenTexturesATI = (vendor && strcmp( reinterpret_cast<const char *>(vendor), "ATI Technologies Inc." ) == 0 ); +#endif + + CHECK_GL_ERROR(); + } +} + +bool OGLTransitionerImpl::initWindowFromSlideShowView( const Reference< presentation::XSlideShowView >& xView ) +{ + osl::MutexGuard const guard( m_aMutex ); + + if (isDisposed()) + return false; + + mxView = xView; + if( !mxView.is() ) + return false; + +#if OSL_DEBUG_LEVEL > 0 + TimerContext aTimerContext("initWindowFromSlideShowView"); +#endif + + /// take the XSlideShowView and extract the parent window from it. see viewmediashape.cxx + uno::Reference< rendering::XCanvas > xCanvas(mxView->getCanvas(), uno::UNO_QUERY_THROW); + uno::Sequence< uno::Any > aDeviceParams; + ::canvas::tools::getDeviceInfo( xCanvas, aDeviceParams ); + + OUString aImplName; + aDeviceParams[ 0 ] >>= aImplName; + + sal_Int64 aVal = 0; + aDeviceParams[1] >>= aVal; + + mpContext = OpenGLContext::Create(); + + OutputDevice* pDevice = reinterpret_cast<OutputDevice*>(aVal); + vcl::Window* pWindow = pDevice ? pDevice->GetOwnerWindow() : nullptr; + + if( !mpContext->init( pWindow) ) { + mpContext->requestLegacyContext(); + if( !mpContext->init( pWindow ) ) + return false; + } + SAL_INFO("slideshow.opengl", "created the context"); + + mpContext->makeCurrent(); + CHECK_GL_ERROR(); + + awt::Rectangle aCanvasArea = mxView->getCanvasArea(); + mpContext->setWinPosAndSize(Point(aCanvasArea.X, aCanvasArea.Y), Size(aCanvasArea.Width, aCanvasArea.Height)); + SAL_INFO("slideshow.opengl", "canvas area: " << aCanvasArea.X << "," << aCanvasArea.Y << " - " << aCanvasArea.Width << "x" << aCanvasArea.Height); + + CHECK_GL_ERROR(); + glEnable(GL_CULL_FACE); + CHECK_GL_ERROR(); + glCullFace(GL_BACK); + CHECK_GL_ERROR(); + glClearColor (0, 0, 0, 0); + CHECK_GL_ERROR(); + glClear(GL_COLOR_BUFFER_BIT); + CHECK_GL_ERROR(); + + mpContext->swapBuffers(); + + CHECK_GL_ERROR(); + + return true; +} + +void OGLTransitionerImpl::setSlides( const uno::Reference< rendering::XBitmap >& xLeavingSlide, + const uno::Reference< rendering::XBitmap >& xEnteringSlide ) +{ + osl::MutexGuard const guard( m_aMutex ); + + if (isDisposed()) + return; + + mxLeavingBitmap.set( xLeavingSlide , UNO_QUERY_THROW ); + mxEnteringBitmap.set( xEnteringSlide , UNO_QUERY_THROW ); + + maSlideSize = mxLeavingBitmap->getSize(); + SAL_INFO("slideshow.opengl", "leaving bitmap area: " << maSlideSize.Width << "x" << maSlideSize.Height); + maSlideSize = mxEnteringBitmap->getSize(); + SAL_INFO("slideshow.opengl", "entering bitmap area: " << maSlideSize.Width << "x" << maSlideSize.Height); + + //to avoid annoying flashing under X entering and leaving slides with opengl effects set the leaving + //bitmap as the background pixmap of the opengl child window and the entering bitmap as the background + //pixmap of the non-opengl parent window. If any expose events occur around the start and end of + //the transition then those windows are default filled by X with the desired start/end image so there's + //no visible flash + SystemChildWindow* pChildWindow = mpContext->getChildWindow(); + if (!pChildWindow) + return; + + css::uno::Reference<css::beans::XFastPropertySet> xEnteringFastPropertySet(mxEnteringBitmap, css::uno::UNO_QUERY); + css::uno::Reference<css::beans::XFastPropertySet> xLeavingFastPropertySet(mxLeavingBitmap, css::uno::UNO_QUERY); + css::uno::Sequence<css::uno::Any> aEnteringBitmap; + css::uno::Sequence<css::uno::Any> aLeavingBitmap; + if (xEnteringFastPropertySet && xLeavingFastPropertySet) + { + xEnteringFastPropertySet->getFastPropertyValue(1) >>= aEnteringBitmap; + xLeavingFastPropertySet->getFastPropertyValue(1) >>= aLeavingBitmap; + } + if (aEnteringBitmap.getLength() == 3 && aLeavingBitmap.getLength() == 3) + pChildWindow->SetLeaveEnterBackgrounds(aLeavingBitmap, aEnteringBitmap); +} + + +void OGLTransitionerImpl::impl_prepareSlides() +{ + geometry::IntegerRectangle2D aSlideRect; + aSlideRect.X1 = 0; + aSlideRect.X2 = maSlideSize.Width; + aSlideRect.Y1 = 0; + aSlideRect.Y2 = maSlideSize.Height; + + CHECK_GL_ERROR(); + mpContext->sync(); + CHECK_GL_ERROR(); + + maLeavingBytes = mxLeavingBitmap->getData(maSlideBitmapLayout, aSlideRect); + maEnteringBytes = mxEnteringBitmap->getData(maSlideBitmapLayout, aSlideRect); + + CHECK_GL_ERROR(); + GLInitSlides(); + + SAL_WARN_IF(maSlideBitmapLayout.PlaneStride != 0, "slideshow.opengl","only handle no plane stride now"); + + mpContext->sync(); + + CHECK_GL_ERROR(); + + // synchronized X still gives us much smoother play + // I suspect some issues in above code in slideshow + // synchronize whole transition for now + const GLWindow& rGLWindow(mpContext->getOpenGLWindow()); + mbRestoreSync = rGLWindow.Synchronize(true); +} + +bool OGLTransitionerImpl::impl_prepareTransition() +{ + if( mpTransition && mpTransition->getSettings().mnRequiredGLVersion <= mnGLVersion ) + return mpTransition->prepare( maLeavingSlideGL, maEnteringSlideGL, mpContext.get() ); + return false; +} + +bool OGLTransitionerImpl::setTransition( const std::shared_ptr<OGLTransitionImpl>& pTransition ) +{ + if ( mpTransition ) // already initialized + return true; + + mpTransition = pTransition; + + mpContext->makeCurrent(); + CHECK_GL_ERROR(); + + bool succeeded = impl_prepareTransition(); + if (!succeeded) { + mpTransition = nullptr; + return false; + } + + impl_prepareSlides(); + + // tdf#91456: When the OpenGL context is initialized but nothing has been rendered on it + // it can happen, that an "empty" screen is drawn. Therefore, drawing the content of time 0 + // onto the context + update(0); + + return true; +} + +void OGLTransitionerImpl::createTexture( GLuint* texID, + bool useMipmap, + const uno::Sequence<sal_Int8>& data, + const OGLFormat* pFormat ) +{ + CHECK_GL_ERROR(); + glDeleteTextures( 1, texID ); + glGenTextures( 1, texID ); + glBindTexture( GL_TEXTURE_2D, *texID ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); + CHECK_GL_ERROR(); + + impl_createTexture( useMipmap, data, pFormat ); + + SAL_WARN_IF(!glIsTexture(*texID), "slideshow.opengl", "Can't generate Leaving slide textures in OpenGL"); + CHECK_GL_ERROR(); +} + +class OGLColorSpace : public cppu::WeakImplHelper< css::rendering::XIntegerBitmapColorSpace > +{ +private: + uno::Sequence< sal_Int8 > maComponentTags; + uno::Sequence< sal_Int32 > maBitCounts; + + virtual sal_Int8 SAL_CALL getType( ) override + { + return rendering::ColorSpaceType::RGB; + } + virtual uno::Sequence< sal_Int8 > SAL_CALL getComponentTags( ) override + { + return maComponentTags; + } + virtual sal_Int8 SAL_CALL getRenderingIntent( ) override + { + return rendering::RenderingIntent::PERCEPTUAL; + } + virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) override + { + return uno::Sequence< beans::PropertyValue >(); + } + virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor, + const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override + { + // TODO(P3): if we know anything about target + // colorspace, this can be greatly sped up + uno::Sequence<rendering::ARGBColor> aIntermediate( + convertToARGB(deviceColor)); + return targetColorSpace->convertFromARGB(aIntermediate); + } + virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override + { + const double* pIn( deviceColor.getConstArray() ); + const std::size_t nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::RGBColor > aRes(nLen/4); + rendering::RGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i<nLen; i+=4 ) + { + *pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]); + pIn += 4; + } + return aRes; + } + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override + { + const double* pIn( deviceColor.getConstArray() ); + const std::size_t nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/4); + rendering::ARGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i<nLen; i+=4 ) + { + *pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]); + pIn += 4; + } + return aRes; + } + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override + { + const double* pIn( deviceColor.getConstArray() ); + const std::size_t nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/4); + rendering::ARGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i<nLen; i+=4 ) + { + *pOut++ = rendering::ARGBColor(pIn[3],pIn[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]); + pIn += 4; + } + return aRes; + } + virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override + { + const sal_Int32 nLen( rgbColor.getLength() ); + + uno::Sequence< double > aRes(nLen*4); + double* pColors=aRes.getArray(); + for( const rendering::RGBColor& rIn : rgbColor ) + { + *pColors++ = rIn.Red; + *pColors++ = rIn.Green; + *pColors++ = rIn.Blue; + *pColors++ = 1.0; + } + return aRes; + } + virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override + { + const sal_Int32 nLen( rgbColor.getLength() ); + + uno::Sequence< double > aRes(nLen*4); + double* pColors=aRes.getArray(); + for( const rendering::ARGBColor& rIn : rgbColor ) + { + *pColors++ = rIn.Red; + *pColors++ = rIn.Green; + *pColors++ = rIn.Blue; + *pColors++ = rIn.Alpha; + } + return aRes; + } + virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override + { + const sal_Int32 nLen( rgbColor.getLength() ); + + uno::Sequence< double > aRes(nLen*4); + double* pColors=aRes.getArray(); + for( const rendering::ARGBColor& rIn : rgbColor ) + { + *pColors++ = rIn.Red/rIn.Alpha; + *pColors++ = rIn.Green/rIn.Alpha; + *pColors++ = rIn.Blue/rIn.Alpha; + *pColors++ = rIn.Alpha; + } + return aRes; + } + + // XIntegerBitmapColorSpace + virtual sal_Int32 SAL_CALL getBitsPerPixel( ) override + { + return 32; + } + virtual uno::Sequence< sal_Int32 > SAL_CALL getComponentBitCounts( ) override + { + return maBitCounts; + } + virtual sal_Int8 SAL_CALL getEndianness( ) override + { + return util::Endianness::LITTLE; + } + virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< sal_Int8 >& deviceColor, + const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override + { + if( dynamic_cast<OGLColorSpace*>(targetColorSpace.get()) ) + { + const sal_Int32 nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence<double> aRes(nLen); + std::transform(deviceColor.begin(), deviceColor.end(), aRes.getArray(), + vcl::unotools::toDoubleColor); + return aRes; + } + else + { + // TODO(P3): if we know anything about target + // colorspace, this can be greatly sped up + uno::Sequence<rendering::ARGBColor> aIntermediate( + convertIntegerToARGB(deviceColor)); + return targetColorSpace->convertFromARGB(aIntermediate); + } + } + virtual uno::Sequence< sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< sal_Int8 >& deviceColor, + const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) override + { + if( dynamic_cast<OGLColorSpace*>(targetColorSpace.get()) ) + { + // it's us, so simply pass-through the data + return deviceColor; + } + else + { + // TODO(P3): if we know anything about target + // colorspace, this can be greatly sped up + uno::Sequence<rendering::ARGBColor> aIntermediate( + convertIntegerToARGB(deviceColor)); + return targetColorSpace->convertIntegerFromARGB(aIntermediate); + } + } + virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< sal_Int8 >& deviceColor ) override + { + const sal_Int8* pIn( deviceColor.getConstArray() ); + const std::size_t nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::RGBColor > aRes(nLen/4); + rendering::RGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i<nLen; i+=4 ) + { + *pOut++ = rendering::RGBColor( + vcl::unotools::toDoubleColor(pIn[0]), + vcl::unotools::toDoubleColor(pIn[1]), + vcl::unotools::toDoubleColor(pIn[2])); + pIn += 4; + } + return aRes; + } + + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< sal_Int8 >& deviceColor ) override + { + const sal_Int8* pIn( deviceColor.getConstArray() ); + const std::size_t nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/4); + rendering::ARGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i<nLen; i+=4 ) + { + *pOut++ = rendering::ARGBColor( + vcl::unotools::toDoubleColor(pIn[3]), + vcl::unotools::toDoubleColor(pIn[0]), + vcl::unotools::toDoubleColor(pIn[1]), + vcl::unotools::toDoubleColor(pIn[2])); + pIn += 4; + } + return aRes; + } + + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< sal_Int8 >& deviceColor ) override + { + const sal_Int8* pIn( deviceColor.getConstArray() ); + const std::size_t nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/4); + rendering::ARGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i<nLen; i+=4 ) + { + const sal_Int8 nAlpha( pIn[3] ); + *pOut++ = rendering::ARGBColor( + vcl::unotools::toDoubleColor(nAlpha), + vcl::unotools::toDoubleColor(nAlpha*pIn[0]), + vcl::unotools::toDoubleColor(nAlpha*pIn[1]), + vcl::unotools::toDoubleColor(nAlpha*pIn[2])); + pIn += 4; + } + return aRes; + } + + virtual uno::Sequence< sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override + { + const sal_Int32 nLen( rgbColor.getLength() ); + + uno::Sequence< sal_Int8 > aRes(nLen*4); + sal_Int8* pColors=aRes.getArray(); + for( const rendering::RGBColor& rIn : rgbColor ) + { + *pColors++ = vcl::unotools::toByteColor(rIn.Red); + *pColors++ = vcl::unotools::toByteColor(rIn.Green); + *pColors++ = vcl::unotools::toByteColor(rIn.Blue); + *pColors++ = -1; + } + return aRes; + } + + virtual uno::Sequence< sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override + { + const sal_Int32 nLen( rgbColor.getLength() ); + + uno::Sequence< sal_Int8 > aRes(nLen*4); + sal_Int8* pColors=aRes.getArray(); + for( const rendering::ARGBColor& rIn : rgbColor ) + { + *pColors++ = vcl::unotools::toByteColor(rIn.Red); + *pColors++ = vcl::unotools::toByteColor(rIn.Green); + *pColors++ = vcl::unotools::toByteColor(rIn.Blue); + *pColors++ = vcl::unotools::toByteColor(rIn.Alpha); + } + return aRes; + } + + virtual uno::Sequence< sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override + { + const sal_Int32 nLen( rgbColor.getLength() ); + + uno::Sequence< sal_Int8 > aRes(nLen*4); + sal_Int8* pColors=aRes.getArray(); + for( const rendering::ARGBColor& rIn : rgbColor ) + { + *pColors++ = vcl::unotools::toByteColor(rIn.Red/rIn.Alpha); + *pColors++ = vcl::unotools::toByteColor(rIn.Green/rIn.Alpha); + *pColors++ = vcl::unotools::toByteColor(rIn.Blue/rIn.Alpha); + *pColors++ = vcl::unotools::toByteColor(rIn.Alpha); + } + return aRes; + } + +public: + OGLColorSpace() : + maComponentTags(4), + maBitCounts(4) + { + sal_Int8* pTags = maComponentTags.getArray(); + sal_Int32* pBitCounts = maBitCounts.getArray(); + pTags[0] = rendering::ColorComponentTag::RGB_RED; + pTags[1] = rendering::ColorComponentTag::RGB_GREEN; + pTags[2] = rendering::ColorComponentTag::RGB_BLUE; + pTags[3] = rendering::ColorComponentTag::ALPHA; + + pBitCounts[0] = + pBitCounts[1] = + pBitCounts[2] = + pBitCounts[3] = 8; + } +}; + +struct OGLColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>, OGLColorSpaceHolder> +{ + uno::Reference<rendering::XIntegerBitmapColorSpace> operator()() + { + return new OGLColorSpace(); + } +}; + +uno::Reference<rendering::XIntegerBitmapColorSpace> const & +getOGLColorSpace() +{ + return OGLColorSpaceHolder::get(); +} + +void buildMipmaps( + GLint internalFormat, GLsizei width, GLsizei height, GLenum format, + GLenum type, const void * data) +{ + if (epoxy_has_gl_extension("GL_ARB_framebuffer_object")) { + glTexImage2D( + GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, + data); + glGenerateMipmap(GL_TEXTURE_2D); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + glTexImage2D( + GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, + data); + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); +} + +void OGLTransitionerImpl::impl_createTexture( + bool useMipmap, + const uno::Sequence<sal_Int8>& data, + const OGLFormat* pFormat ) +{ + if( !pFormat ) + { + CHECK_GL_ERROR(); + // force-convert color to ARGB8888 int color space + uno::Sequence<sal_Int8> tempBytes( + maSlideBitmapLayout.ColorSpace->convertToIntegerColorSpace( + data, + getOGLColorSpace())); + buildMipmaps( GL_RGBA, + maSlideSize.Width, + maSlideSize.Height, + GL_RGBA, + GL_UNSIGNED_BYTE, + &tempBytes[0]); + + if (epoxy_has_gl_extension("GL_EXT_texture_filter_anisotropic")) + { + //anistropic filtering (to make texturing not suck when looking at polygons from oblique angles) + GLfloat largest_supported_anisotropy; + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy); + } + } else { + if( mpTransition && !mbBrokenTexturesATI && !useMipmap) { + glTexImage2D( GL_TEXTURE_2D, 0, pFormat->nInternalFormat, maSlideSize.Width, maSlideSize.Height, 0, pFormat->eFormat, pFormat->eType, &data[0] ); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + } else { + buildMipmaps( pFormat->nInternalFormat, maSlideSize.Width, maSlideSize.Height, pFormat->eFormat, pFormat->eType, &data[0] ); + + if (epoxy_has_gl_extension("GL_EXT_texture_filter_anisotropic")) + { + //anistropic filtering (to make texturing not suck when looking at polygons from oblique angles) + GLfloat largest_supported_anisotropy; + glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy ); + } + } + } + CHECK_GL_ERROR(); +} + +const OGLFormat* OGLTransitionerImpl::chooseFormats() +{ + const OGLFormat* pDetectedFormat=nullptr; + uno::Reference<rendering::XIntegerBitmapColorSpace> xIntColorSpace( + maSlideBitmapLayout.ColorSpace); + + if( xIntColorSpace->getType() == rendering::ColorSpaceType::RGB || + xIntColorSpace->getType() == rendering::ColorSpaceType::SRGB ) + { + /* table for canvas->OGL format mapping. outer index is number + of color components (0:3, 1:4), then comes bits per pixel + (0:16, 1:24, 2:32), then channel ordering: (0:rgba, 1:bgra, + 2:argb, 3:abgr) + */ + static const OGLFormat lcl_RGB24[] = + { + // 24 bit RGB + {3, GL_BGR, GL_UNSIGNED_BYTE}, + {3, GL_RGB, GL_UNSIGNED_BYTE}, + {3, GL_BGR, GL_UNSIGNED_BYTE}, + {3, GL_RGB, GL_UNSIGNED_BYTE} + }; + +#if defined(GL_VERSION_1_2) && defined(GLU_VERSION_1_3) + // more format constants available + static const OGLFormat lcl_RGB16[] = + { + // 16 bit RGB + {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV}, + {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, + {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV}, + {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5} + }; + + static const OGLFormat lcl_ARGB16_4[] = + { + // 16 bit ARGB + {4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, + {4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, + {4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4}, + {4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4} + }; + + static const OGLFormat lcl_ARGB16_5[] = + { + // 16 bit ARGB + {4, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, + {4, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, + {4, GL_BGRA, GL_UNSIGNED_SHORT_5_5_5_1}, + {4, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1} + }; + + static const OGLFormat lcl_ARGB32[] = + { + // 32 bit ARGB + {4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, + {4, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}, + {4, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8}, + {4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8} + }; + + const uno::Sequence<sal_Int8> aComponentTags( + xIntColorSpace->getComponentTags()); + const uno::Sequence<sal_Int32> aComponentBitcounts( + xIntColorSpace->getComponentBitCounts()); + const sal_Int32 nNumComponents( aComponentBitcounts.getLength() ); + const sal_Int32 nBitsPerPixel( xIntColorSpace->getBitsPerPixel() ); + + // supported component ordering? + const int nComponentOrderIndex( + calcComponentOrderIndex(aComponentTags)); + if( nComponentOrderIndex != -1 ) + { + switch( nBitsPerPixel ) + { + case 16: + if( nNumComponents == 3 ) + { + pDetectedFormat = &lcl_RGB16[nComponentOrderIndex]; + } + else if( nNumComponents == 4 ) + { + if( aComponentBitcounts[1] == 4 ) + { + pDetectedFormat = &lcl_ARGB16_4[nComponentOrderIndex]; + } + else if( aComponentBitcounts[1] == 5 ) + { + pDetectedFormat = &lcl_ARGB16_5[nComponentOrderIndex]; + } + } + break; + case 24: + if( nNumComponents == 3 ) + { + pDetectedFormat = &lcl_RGB24[nComponentOrderIndex]; + } + break; + case 32: + if ( nNumComponents == 4 ) + { + pDetectedFormat = &lcl_ARGB32[nComponentOrderIndex]; + } + break; + } + } +#else + const uno::Sequence<sal_Int8> aComponentTags( + xIntColorSpace->getComponentTags()); + const int nComponentOrderIndex(calcComponentOrderIndex(aComponentTags)); + if( aComponentTags.getLength() == 3 && + nComponentOrderIndex != -1 && + xIntColorSpace->getBitsPerPixel() == 24 ) + { + pDetectedFormat = &lcl_RGB24[nComponentOrderIndex]; + } +#endif + } + + return pDetectedFormat; +} + +void OGLTransitionerImpl::GLInitSlides() +{ + osl::MutexGuard const guard( m_aMutex ); + + if (isDisposed() || !mpTransition || mpTransition->getSettings().mnRequiredGLVersion > mnGLVersion) + return; + +#if OSL_DEBUG_LEVEL > 0 + TimerContext aTimerContext("texture creation"); +#endif + + mpContext->makeCurrent(); + + const OGLFormat* pFormat = chooseFormats(); + + CHECK_GL_ERROR(); + createTexture( &maLeavingSlideGL, + mpTransition->getSettings().mbUseMipMapLeaving, + maLeavingBytes, + pFormat ); + + createTexture( &maEnteringSlideGL, + mpTransition->getSettings().mbUseMipMapEntering, + maEnteringBytes, + pFormat ); + + CHECK_GL_ERROR(); + mpContext->sync(); + CHECK_GL_ERROR(); +} + +void SAL_CALL OGLTransitionerImpl::update( double nTime ) +{ +#if OSL_DEBUG_LEVEL > 0 + mnFrameCount ++; + m_UpdateStartTime = std::chrono::steady_clock::now(); + if( mnFrameCount == 1 ) { + m_StartTime = m_UpdateStartTime; + m_TotalUpdateDuration = std::chrono::seconds(0); + } +#endif + osl::MutexGuard const guard( m_aMutex ); + + if (isDisposed() || !mbValidOpenGLContext || !mpTransition || mpTransition->getSettings().mnRequiredGLVersion > mnGLVersion) + return; + + mpContext->makeCurrent(); + CHECK_GL_ERROR(); + + glEnable(GL_DEPTH_TEST); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + CHECK_GL_ERROR(); + + const GLWindow& rGLWindow(mpContext->getOpenGLWindow()); + mpTransition->display(nTime, maLeavingSlideGL, maEnteringSlideGL, + maSlideSize.Width, maSlideSize.Height, + static_cast<double>(rGLWindow.Width), + static_cast<double>(rGLWindow.Height), + mpContext.get()); + + mpContext->swapBuffers(); + + mpContext->show(); + mpContext->sync(); + CHECK_GL_ERROR(); + +#if OSL_DEBUG_LEVEL > 0 + m_UpdateEndTime = std::chrono::steady_clock::now(); + + SAL_INFO("slideshow.opengl", "update time: " << nTime); + SAL_INFO("slideshow.opengl", "update took: " << std::chrono::duration_cast<std::chrono::milliseconds>(m_UpdateEndTime - m_UpdateStartTime).count()); + m_TotalUpdateDuration += m_UpdateEndTime - m_UpdateStartTime; +#endif +} + +void SAL_CALL OGLTransitionerImpl::viewChanged( const Reference< presentation::XSlideShowView >& rView, + const Reference< rendering::XBitmap >& rLeavingBitmap, + const Reference< rendering::XBitmap >& rEnteringBitmap ) +{ + SAL_INFO("slideshow.opengl", "transitioner: view changed"); + + impl_dispose(); + + initWindowFromSlideShowView( rView ); + setSlides( rLeavingBitmap, rEnteringBitmap ); + impl_prepareSlides(); + impl_prepareTransition(); +} + +void OGLTransitionerImpl::disposeTextures() +{ + if (!mbValidOpenGLContext) + return; + + mpContext->makeCurrent(); + CHECK_GL_ERROR(); + + glDeleteTextures(1,&maLeavingSlideGL); + maLeavingSlideGL = 0; + glDeleteTextures(1,&maEnteringSlideGL); + maEnteringSlideGL = 0; + + CHECK_GL_ERROR(); +} + +void OGLTransitionerImpl::impl_dispose() +{ + if (mbValidOpenGLContext) + { + mpContext->makeCurrent(); + CHECK_GL_ERROR(); + } + + if( mpTransition && mpTransition->getSettings().mnRequiredGLVersion <= mnGLVersion ) + mpTransition->finish(); + disposeTextures(); + if( mpContext.is() ) + mpContext->dispose(); + mpContext.clear(); +} + +// we are about to be disposed (someone call dispose() on us) +void OGLTransitionerImpl::disposing() +{ + osl::MutexGuard const guard( m_aMutex ); + +#if OSL_DEBUG_LEVEL > 0 + SAL_INFO("slideshow.opengl", "dispose " << this); + if( mnFrameCount ) { + m_EndTime = std::chrono::steady_clock::now(); + auto const duration = m_EndTime - m_StartTime; + SAL_INFO("slideshow.opengl", + "whole transition (frames: " << mnFrameCount + << ") took: " << std::chrono::duration_cast<std::chrono::microseconds>(duration).count() + << " fps: " + << ((static_cast<double>(mnFrameCount)*1000000000.0)/std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count()) + << " time spent in updates: " << std::chrono::duration_cast<std::chrono::microseconds>(m_TotalUpdateDuration).count() + << " percentage of transition time: " + << (100*((static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(m_TotalUpdateDuration).count()))/(static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count())))) + << '%' + ); + } +#endif + + if (mbRestoreSync && mpContext.is()) { + // try to reestablish synchronize state + const char* sal_synchronize = getenv("SAL_SYNCHRONIZE"); + mpContext->getOpenGLWindow().Synchronize(sal_synchronize && *sal_synchronize == '1' ); + } + + impl_dispose(); + + mpTransition.reset(); + + mxLeavingBitmap.clear(); + mxEnteringBitmap.clear(); + mxView.clear(); +} + +OGLTransitionerImpl::OGLTransitionerImpl() + : OGLTransitionerImplBase(m_aMutex) + , mpContext() + , maLeavingSlideGL(0) + , maEnteringSlideGL(0) + , mxView() + , maEnteringBytes() + , maLeavingBytes() + , mbRestoreSync(false) + , maSlideBitmapLayout() + , maSlideSize() + , mbBrokenTexturesATI(false) + , mnGLVersion(0) + , mbValidOpenGLContext(false) +#if OSL_DEBUG_LEVEL > 0 + , mnFrameCount(0) +#endif +{ +} + +typedef cppu::WeakComponentImplHelper<presentation::XTransitionFactory, lang::XServiceInfo> OGLTransitionFactoryImplBase; + +class OGLTransitionFactoryImpl : private cppu::BaseMutex, public OGLTransitionFactoryImplBase +{ +public: + explicit OGLTransitionFactoryImpl() : + OGLTransitionFactoryImplBase(m_aMutex) + {} + + // XServiceInfo + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override + { + return { "com.sun.star.presentation.TransitionFactory" }; + } + virtual OUString SAL_CALL getImplementationName() override + { + return "com.sun.star.comp.presentation.OGLTransitionFactory"; + } + virtual sal_Bool SAL_CALL supportsService(const OUString& aServiceName) override + { + return cppu::supportsService(this, aServiceName); + } + + // XTransitionFactory + virtual sal_Bool SAL_CALL hasTransition( sal_Int16 transitionType, sal_Int16 transitionSubType ) override + { + if( !OpenGLHelper::supportsOpenGL()) + return false; + // A set of css::animation::TransitionSubType that don't have any meaning (in the SMIL 2.0 + // standard) for MISCSHAPEWIPE have been chosen to refer to some of these "fancy" optional + // transitions. (The only subtypes of 'miscShapeWipe' defined in the standard are 'heart' + // and 'keyhole'.) The set of subtypes used seems to be a bit random; it starts from the + // beginning of the list (in the order (numeric) in our TransitionSubType set of constants) + // but then jumps a bit randomly. The numeric values as such have no meaning, but still. + + if( transitionType == animations::TransitionType::MISCSHAPEWIPE ) { + switch( transitionSubType ) + { + case animations::TransitionSubType::LEFTTORIGHT: // 1 + case animations::TransitionSubType::TOPTOBOTTOM: // 2 + case animations::TransitionSubType::TOPLEFT: // 3 + case animations::TransitionSubType::TOPRIGHT: // 4 + case animations::TransitionSubType::BOTTOMRIGHT: // 5 + case animations::TransitionSubType::BOTTOMLEFT: // 6 + case animations::TransitionSubType::TOPCENTER: // 7 + case animations::TransitionSubType::RIGHTCENTER: // 8 + case animations::TransitionSubType::BOTTOMCENTER: // 9 + case animations::TransitionSubType::CORNERSIN: // 11 + case animations::TransitionSubType::CORNERSOUT: // 12 + case animations::TransitionSubType::VERTICAL: // 13 + case animations::TransitionSubType::HORIZONTAL: // 14 + case animations::TransitionSubType::DIAMOND: // 26 + case animations::TransitionSubType::CIRCLE: // 27 + case animations::TransitionSubType::HEART: // 31 + case animations::TransitionSubType::FANOUTHORIZONTAL: // 55 + case animations::TransitionSubType::ACROSS: // 108 + return true; + + default: + return false; + } + } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::CROSSFADE ) { + return true; + } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::FADEOVERCOLOR ) { + return true; + } else if( transitionType == animations::TransitionType::IRISWIPE && transitionSubType == animations::TransitionSubType::DIAMOND ) { + return true; + } else if( transitionType == animations::TransitionType::ZOOM && transitionSubType == animations::TransitionSubType::ROTATEIN ) { + return true; + } else + return false; + } + + virtual uno::Reference< presentation::XTransition > SAL_CALL createTransition( + sal_Int16 transitionType, + sal_Int16 transitionSubType, + sal_Int32 transitionFadeColor, + const uno::Reference< presentation::XSlideShowView >& view, + const uno::Reference< rendering::XBitmap >& leavingBitmap, + const uno::Reference< rendering::XBitmap >& enteringBitmap ) override + { + if( !hasTransition( transitionType, transitionSubType ) ) + return uno::Reference< presentation::XTransition >(); + + rtl::Reference< OGLTransitionerImpl > xRes( new OGLTransitionerImpl() ); + if ( !xRes->initialize( view, leavingBitmap, enteringBitmap ) ) + return uno::Reference< presentation::XTransition >(); + + std::shared_ptr<OGLTransitionImpl> pTransition; + + if( transitionType == animations::TransitionType::MISCSHAPEWIPE ) { + switch( transitionSubType ) + { + case animations::TransitionSubType::LEFTTORIGHT: + pTransition = makeFallLeaving(); + break; + case animations::TransitionSubType::TOPTOBOTTOM: + pTransition = makeTurnAround(); + break; + case animations::TransitionSubType::TOPLEFT: + pTransition = makeIris(); + break; + case animations::TransitionSubType::TOPRIGHT: + pTransition = makeTurnDown(); + break; + case animations::TransitionSubType::BOTTOMRIGHT: + pTransition = makeRochade(); + break; + case animations::TransitionSubType::BOTTOMLEFT: + pTransition = makeVenetianBlinds( true, 8 ); + break; + case animations::TransitionSubType::TOPCENTER: + pTransition = makeVenetianBlinds( false, 6 ); + break; + case animations::TransitionSubType::RIGHTCENTER: + pTransition = makeStatic(); + break; + case animations::TransitionSubType::BOTTOMCENTER: + pTransition = makeDissolve(); + break; + case animations::TransitionSubType::CORNERSIN: + pTransition = makeInsideCubeFaceToLeft(); + break; + case animations::TransitionSubType::CORNERSOUT: + pTransition = makeOutsideCubeFaceToLeft(); + break; + case animations::TransitionSubType::VERTICAL: + pTransition = makeVortex(); + break; + case animations::TransitionSubType::HORIZONTAL: + pTransition = makeRipple(); + break; + case animations::TransitionSubType::CIRCLE: + pTransition = makeRevolvingCircles(8,128); + break; + case animations::TransitionSubType::FANOUTHORIZONTAL: + pTransition = makeHelix(20); + break; + case animations::TransitionSubType::ACROSS: + pTransition = makeNByMTileFlip(8,6); + break; + case animations::TransitionSubType::DIAMOND: + pTransition = makeGlitter(); + break; + case animations::TransitionSubType::HEART: + pTransition = makeHoneycomb(); + break; + } + } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::CROSSFADE ) { + pTransition = makeFadeSmoothly(); + } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::FADEOVERCOLOR ) { + pTransition = makeFadeThroughColor( transitionFadeColor == 0xffffff ); + } else if( transitionType == animations::TransitionType::IRISWIPE && transitionSubType == animations::TransitionSubType::DIAMOND ) { + pTransition = makeDiamond(); + } else if( transitionType == animations::TransitionType::ZOOM && transitionSubType == animations::TransitionSubType::ROTATEIN ) { + pTransition = makeNewsflash(); + } + + if ( !pTransition || !xRes->setTransition(pTransition) ) + return uno::Reference< presentation::XTransition >(); + + return xRes; + } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +slideshow_OGLTransitionFactoryImpl_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new OGLTransitionFactoryImpl()); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |