Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  TransitionerImpl.cxx   Sprache: C

 
/* -*- 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 <comphelper/diagnose_ex.hxx>

#include <utility>
#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 aWhat)
        : m_aWhat(std::move(aWhat))
        , 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 >&&nbsp;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 >&&nbsp;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(u"initWindowFromSlideShowView"_ustr);
#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() == 2 && aLeavingBitmap.getLength() == 2)
        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 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(deviceColor[i], deviceColor[i + 1], deviceColor[i + 2]);
        }
        return aRes;
    }
    virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override
    {
        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(deviceColor[i+3], deviceColor[i], deviceColor[i+1], deviceColor[i+2]);
        }
        return aRes;
    }
    virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override
    {
        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(deviceColor[i+3],
                                           deviceColor[i+3] * deviceColor[i],
                                           deviceColor[i+3] * deviceColor[i+1],
                                           deviceColor[i+3] * deviceColor[i+2]);
        }
        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();
        forconst 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();
        forconst 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();
        forconst 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
    {
        ifdynamic_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
    {
        ifdynamic_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 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(deviceColor[i + 0]),
                vcl::unotools::toDoubleColor(deviceColor[i + 1]),
                vcl::unotools::toDoubleColor(deviceColor[i + 2]));
        }
        return aRes;
    }

    virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< sal_Int8 >& deviceColor ) override
    {
        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(deviceColor[i + 3]),
                vcl::unotools::toDoubleColor(deviceColor[i + 0]),
                vcl::unotools::toDoubleColor(deviceColor[i + 1]),
                vcl::unotools::toDoubleColor(deviceColor[i + 2]));
        }
        return aRes;
    }

    virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< sal_Int8 >& deviceColor ) override
    {
        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(deviceColor[i + 3]);
            *pOut++ = rendering::ARGBColor(
                vcl::unotools::toDoubleColor(nAlpha),
                vcl::unotools::toDoubleColor(nAlpha * deviceColor[i + 0]),
                vcl::unotools::toDoubleColor(nAlpha * deviceColor[i + 1]),
                vcl::unotools::toDoubleColor(nAlpha * deviceColor[i + 2]));
        }
        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();
        forconst 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();
        forconst 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();
        forconst 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;
    }
};

uno::Reference<rendering::XIntegerBitmapColorSpace> const &
getOGLColorSpace()
{
    static uno::Reference<rendering::XIntegerBitmapColorSpace> theSpace = new OGLColorSpace();
    return theSpace;
}

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(u"texture creation"_ustr);
#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 { u"com.sun.star.presentation.TransitionFactory"_ustr };
    }
    virtual OUString SAL_CALL getImplementationName() override
    {
        return u"com.sun.star.comp.presentation.OGLTransitionFactory"_ustr;
    }
    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: */

Messung V0.5
C=92 H=94 G=92

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge