Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/GAP/pkg/recog/misc/steve/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 22.0.2025 mit Größe 90 B image not shown  

Quelle  TransitionImpl.cxx   Sprache: unbekannt

 
/* -*- 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 <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <vcl/opengl/OpenGLHelper.hxx>
#include <vcl/opengl/OpenGLContext.hxx>
#include <sal/log.hxx>

#include <algorithm>
#include <array>

#include <comphelper/random.hxx>

#include "Operation.hxx"
#include "TransitionImpl.hxx"
#include <cmath>

TransitionScene::TransitionScene(TransitionScene const& rOther)
    : maLeavingSlidePrimitives(rOther.maLeavingSlidePrimitives)
    , maEnteringSlidePrimitives(rOther.maEnteringSlidePrimitives)
    , maOverallOperations(rOther.maOverallOperations)
    , maSceneObjects(rOther.maSceneObjects)
{
}

TransitionScene& TransitionScene::operator=(const TransitionScene& rOther)
{
    TransitionScene aTmp(rOther);
    swap(aTmp);
    return *this;
}

void TransitionScene::swap(TransitionScene& rOther)
{
    using std::swap;

    swap(maLeavingSlidePrimitives, rOther.maLeavingSlidePrimitives);
    swap(maEnteringSlidePrimitives, rOther.maEnteringSlidePrimitives);
    swap(maOverallOperations, rOther.maOverallOperations);
    swap(maSceneObjects, rOther.maSceneObjects);
}

OGLTransitionImpl::~OGLTransitionImpl()
{
}

void OGLTransitionImpl::uploadModelViewProjectionMatrices()
{
    double EyePos(10.0);
    double const RealF(1.0);
    double const RealN(-1.0);
    double const RealL(-1.0);
    double RealR(1.0);
    double const RealB(-1.0);
    double RealT(1.0);
    double ClipN(EyePos+5.0*RealN);
    double ClipF(EyePos+15.0*RealF);
    double ClipL(RealL*8.0);
    double ClipR(RealR*8.0);
    double ClipB(RealB*8.0);
    double ClipT(RealT*8.0);

    glm::mat4 projection = glm::frustum<float>(ClipL, ClipR, ClipB, ClipT, ClipN, ClipF);
    //This scaling is to take the plane with BottomLeftCorner(-1,-1,0) and TopRightCorner(1,1,0) and map it to the screen after the perspective division.
    glm::vec3 scale(1.0 / (((RealR * 2.0 * ClipN) / (EyePos * (ClipR - ClipL))) - ((ClipR + ClipL) / (ClipR - ClipL))),
                    1.0 / (((RealT * 2.0 * ClipN) / (EyePos * (ClipT - ClipB))) - ((ClipT + ClipB) / (ClipT - ClipB))),
                    1.0);
    projection = glm::scale(projection, scale);
    glm::mat4 modelview = glm::translate(glm::mat4(), glm::vec3(0, 0, -EyePos));

    GLint location = glGetUniformLocation( m_nProgramObject, "u_projectionMatrix" );
    if( location != -1 ) {
        glUniformMatrix4fv(location, 1, false, glm::value_ptr(projection));
        CHECK_GL_ERROR();
    }

    location = glGetUniformLocation( m_nProgramObject, "u_modelViewMatrix" );
    if( location != -1 ) {
        glUniformMatrix4fv(location, 1, false, glm::value_ptr(modelview));
        CHECK_GL_ERROR();
    }
}

static std::vector<int> uploadPrimitives(const Primitives_t& primitives)
{
    int size = 0;
    for (const Primitive& primitive: primitives)
        size += primitive.getVerticesByteSize();

    CHECK_GL_ERROR();
    glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_STATIC_DRAW);
    CHECK_GL_ERROR();
    Vertex *buf = static_cast<Vertex*>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));

    std::vector<int> indices;
    int last_pos = 0;
    for (const Primitive& primitive: primitives) {
        indices.push_back(last_pos);
        int num = primitive.writeVertices(buf);
        buf += num;
        last_pos += num;
    }

    CHECK_GL_ERROR();
    glUnmapBuffer(GL_ARRAY_BUFFER);
    CHECK_GL_ERROR();
    return indices;
}

bool OGLTransitionImpl::prepare( sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, OpenGLContext *pContext )
{
    m_nProgramObject = makeShader();
    if (!m_nProgramObject)
        return false;

    CHECK_GL_ERROR();
    glUseProgram( m_nProgramObject );
    CHECK_GL_ERROR();

    const SceneObjects_t& rSceneObjects(maScene.getSceneObjects());
    for(const auto& rSceneObject : rSceneObjects) {
        rSceneObject->prepare(m_nProgramObject);
    }

    GLint location = glGetUniformLocation( m_nProgramObject, "leavingSlideTexture" );
    if( location != -1 ) {
        glUniform1i( location, 0 );  // texture unit 0
        CHECK_GL_ERROR();
    }

    location = glGetUniformLocation( m_nProgramObject, "enteringSlideTexture" );
    if( location != -1 ) {
        glUniform1i( location, 2 );  // texture unit 2
        CHECK_GL_ERROR();
    }

    uploadModelViewProjectionMatrices();

    m_nPrimitiveTransformLocation = glGetUniformLocation( m_nProgramObject, "u_primitiveTransformMatrix" );
    m_nSceneTransformLocation = glGetUniformLocation( m_nProgramObject, "u_sceneTransformMatrix" );
    m_nOperationsTransformLocation = glGetUniformLocation( m_nProgramObject, "u_operationsTransformMatrix" );
    m_nTimeLocation = glGetUniformLocation( m_nProgramObject, "time" );

    glGenVertexArrays(1, &m_nVertexArrayObject);
    glBindVertexArray(m_nVertexArrayObject);

    glGenBuffers(1, &m_nVertexBufferObject);
    glBindBuffer(GL_ARRAY_BUFFER, m_nVertexBufferObject);

    // In practice both leaving and entering slides share the same primitives.
    m_nFirstIndices = uploadPrimitives(getScene().getLeavingSlide());

    // Attribute bindings
    m_nPositionLocation = glGetAttribLocation(m_nProgramObject, "a_position");
    if (m_nPositionLocation != -1) {
        glEnableVertexAttribArray(m_nPositionLocation);
        glVertexAttribPointer( m_nPositionLocation, 3, GL_FLOAT, falsesizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)) );
        CHECK_GL_ERROR();
    }

    m_nNormalLocation = glGetAttribLocation(m_nProgramObject, "a_normal");
    if (m_nNormalLocation != -1) {
        glEnableVertexAttribArray(m_nNormalLocation);
        glVertexAttribPointer( m_nNormalLocation, 3, GL_FLOAT, falsesizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, normal)) );
        CHECK_GL_ERROR();
    }

    m_nTexCoordLocation = glGetAttribLocation(m_nProgramObject, "a_texCoord");
    if (m_nTexCoordLocation != -1) {
        glEnableVertexAttribArray(m_nTexCoordLocation);
        glVertexAttribPointer( m_nTexCoordLocation, 2, GL_FLOAT, falsesizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, texcoord)) );
        CHECK_GL_ERROR();
    }

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    CHECK_GL_ERROR();

    prepareTransition( glLeavingSlideTex, glEnteringSlideTex, pContext );
    return true;
}

void OGLTransitionImpl::finish()
{
    const SceneObjects_t& rSceneObjects(maScene.getSceneObjects());
    for(const auto& rSceneObject : rSceneObjects) {
        rSceneObject->finish();
    }

    finishTransition();

    CHECK_GL_ERROR();
    if( m_nProgramObject ) {
        glDeleteBuffers(1, &m_nVertexBufferObject);
        m_nVertexBufferObject = 0;
        glDeleteVertexArrays(1, &m_nVertexArrayObject);
        m_nVertexArrayObject = 0;
        glDeleteProgram( m_nProgramObject );
        m_nProgramObject = 0;
    }
    CHECK_GL_ERROR();
}

void OGLTransitionImpl::prepare( doubledouble )
{
}

void OGLTransitionImpl::cleanup()
{
}

void OGLTransitionImpl::prepareTransition( sal_Int32, sal_Int32, OpenGLContext* )
{
}

void OGLTransitionImpl::finishTransition()
{
}

void OGLTransitionImpl::displaySlides_( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale, OpenGLContext * )
{
    CHECK_GL_ERROR();
    applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );

    glUniform1f( m_nTimeLocation, nTime );

    glActiveTexture( GL_TEXTURE2 );
    glBindTexture( GL_TEXTURE_2D, glEnteringSlideTex );
    glActiveTexture( GL_TEXTURE0 );

    displaySlide( nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale );
    CHECK_GL_ERROR();
}

void OGLTransitionImpl::display( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex,
                                 double SlideWidth, double SlideHeight, double DispWidth, double DispHeight, OpenGLContext *pContext )
{
    const double SlideWidthScale = SlideWidth/DispWidth;
    const double SlideHeightScale = SlideHeight/DispHeight;

    CHECK_GL_ERROR();
    glBindVertexArray(m_nVertexArrayObject);
    prepare( SlideWidth, SlideHeight );

    CHECK_GL_ERROR();
    displaySlides_( nTime, glLeavingSlideTex, glEnteringSlideTex, SlideWidthScale, SlideHeightScale, pContext );
    CHECK_GL_ERROR();
    displayScene( nTime, SlideWidth, SlideHeight, DispWidth, DispHeight );
    CHECK_GL_ERROR();
}

void OGLTransitionImpl::applyOverallOperations( double nTime, double SlideWidthScale, double SlideHeightScale )
{
    const Operations_t& rOverallOperations(maScene.getOperations());
    glm::mat4 matrix;
    for(const auto& rOperation : rOverallOperations)
        rOperation->interpolate(matrix, nTime, SlideWidthScale, SlideHeightScale);
    CHECK_GL_ERROR();
    if (m_nOperationsTransformLocation != -1) {
        glUniformMatrix4fv(m_nOperationsTransformLocation, 1, false, glm::value_ptr(matrix));
        CHECK_GL_ERROR();
    }
}

static void displayPrimitives(const Primitives_t& primitives, GLint primitiveTransformLocation, double nTime, double WidthScale, double HeightScale, std::vector<int>::const_iterator first)
{
    for (const Primitive& primitive: primitives)
        primitive.display(primitiveTransformLocation, nTime, WidthScale, HeightScale, *first++);
}

void
OGLTransitionImpl::displaySlide(
        const double nTime,
        const sal_Int32 glSlideTex, const Primitives_t& primitives,
        double SlideWidthScale, double SlideHeightScale )
{
    CHECK_GL_ERROR();
    glBindTexture(GL_TEXTURE_2D, glSlideTex);
    CHECK_GL_ERROR();
    if (m_nSceneTransformLocation != -1) {
        glUniformMatrix4fv(m_nSceneTransformLocation, 1, false, glm::value_ptr(glm::mat4()));
        CHECK_GL_ERROR();
    }
    displayPrimitives(primitives, m_nPrimitiveTransformLocation, nTime, SlideWidthScale, SlideHeightScale, m_nFirstIndices.cbegin());
    CHECK_GL_ERROR();
}

void
OGLTransitionImpl::displayUnbufferedSlide(
        const double nTime,
        const sal_Int32 glSlideTex, const Primitives_t& primitives,
        double SlideWidthScale, double SlideHeightScale )
{
    CHECK_GL_ERROR();
    glBindTexture(GL_TEXTURE_2D, glSlideTex);
    CHECK_GL_ERROR();
    glBindVertexArray(0);
    CHECK_GL_ERROR();
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    CHECK_GL_ERROR();
    if (m_nSceneTransformLocation != -1) {
        glUniformMatrix4fv(m_nSceneTransformLocation, 1, false, glm::value_ptr(glm::mat4()));
        CHECK_GL_ERROR();
    }
    for (const Primitive& primitive: primitives)
        primitive.display(m_nPrimitiveTransformLocation, nTime, SlideWidthScale, SlideHeightScale);
    CHECK_GL_ERROR();
    glBindVertexArray(m_nVertexArrayObject);
    CHECK_GL_ERROR();
    glBindBuffer(GL_ARRAY_BUFFER, m_nVertexBufferObject);
    CHECK_GL_ERROR();
}

void OGLTransitionImpl::displayScene( double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
{
    const SceneObjects_t& rSceneObjects(maScene.getSceneObjects());
    CHECK_GL_ERROR();
    for(const auto& rSceneObject : rSceneObjects)
        rSceneObject->display(m_nSceneTransformLocation, m_nPrimitiveTransformLocation, nTime, SlideWidth, SlideHeight, DispWidth, DispHeight);
    CHECK_GL_ERROR();
}

void Primitive::display(GLint primitiveTransformLocation, double nTime, double WidthScale, double HeightScale) const
{
    glm::mat4 matrix;
    applyOperations( matrix, nTime, WidthScale, HeightScale );

    CHECK_GL_ERROR();
    if (primitiveTransformLocation != -1) {
        glUniformMatrix4fv(primitiveTransformLocation, 1, false, glm::value_ptr(matrix));
        CHECK_GL_ERROR();
    }

    GLuint nVertexArrayObject;
    glGenVertexArrays(1, &nVertexArrayObject);
    CHECK_GL_ERROR();
    glBindVertexArray(nVertexArrayObject);
    CHECK_GL_ERROR();

    GLuint nBuffer;
    glGenBuffers(1, &nBuffer);
    CHECK_GL_ERROR();
    glBindBuffer(GL_ARRAY_BUFFER, nBuffer);
    CHECK_GL_ERROR();
    glBufferData(GL_ARRAY_BUFFER, getVerticesByteSize(), Vertices.data(), GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    CHECK_GL_ERROR();
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr);
    CHECK_GL_ERROR();
    glDrawArrays( GL_TRIANGLES, 0, Vertices.size() );
    CHECK_GL_ERROR();

    glDeleteBuffers(1, &nBuffer);
    CHECK_GL_ERROR();

    glDeleteVertexArrays(1, &nVertexArrayObject);
    CHECK_GL_ERROR();
}

void Primitive::display(GLint primitiveTransformLocation, double nTime, double WidthScale, double HeightScale, int first) const
{
    glm::mat4 matrix;
    applyOperations( matrix, nTime, WidthScale, HeightScale );

    CHECK_GL_ERROR();
    if (primitiveTransformLocation != -1) {
        glUniformMatrix4fv(primitiveTransformLocation, 1, false, glm::value_ptr(matrix));
        CHECK_GL_ERROR();
    }
    glDrawArrays( GL_TRIANGLES, first, Vertices.size() );

    CHECK_GL_ERROR();
}

void Primitive::applyOperations(glm::mat4& matrix, double nTime, double WidthScaledouble HeightScale) const
{
    for(const auto & rOperation : Operations)
        rOperation->interpolate(matrix, nTime, WidthScale, HeightScale);
    matrix = glm::scale(matrix, glm::vec3(WidthScale, HeightScale, 1));
}

void SceneObject::display(GLint sceneTransformLocation, GLint primitiveTransformLocation, double nTime, double /* SlideWidth */, double /* SlideHeight */, double DispWidth, double DispHeight ) const
{
    // fixme: allow various model spaces, now we make it so that
    // it is regular -1,-1 to 1,1, where the whole display fits in
    glm::mat4 matrix;
    if (DispHeight > DispWidth)
        matrix = glm::scale(matrix, glm::vec3(DispHeight/DispWidth, 1, 1));
    else
        matrix = glm::scale(matrix, glm::vec3(1, DispWidth/DispHeight, 1));
    CHECK_GL_ERROR();
    if (sceneTransformLocation != -1) {
        glUniformMatrix4fv(sceneTransformLocation, 1, false, glm::value_ptr(matrix));
        CHECK_GL_ERROR();
    }
    displayPrimitives(maPrimitives, primitiveTransformLocation, nTime, 1, 1, maFirstIndices.cbegin());
    CHECK_GL_ERROR();
}

void SceneObject::pushPrimitive(const Primitive &p)
{
    maPrimitives.push_back(p);
}

SceneObject::SceneObject()
    : maPrimitives()
{
}

SceneObject::~SceneObject()
{
}

namespace
{

class Iris : public SceneObject
{
public:
    Iris() = default;

    virtual void prepare(GLuint program) override;
    virtual void display(GLint sceneTransformLocation, GLint primitiveTransformLocation, double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight) const override;
    virtual void finish() override;

private:
    GLuint maTexture = 0;
    GLuint maBuffer = 0;
    GLuint maVertexArray = 0;
};

void Iris::display(GLint sceneTransformLocation, GLint primitiveTransformLocation, double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight ) const
{
    glBindVertexArray(maVertexArray);
    CHECK_GL_ERROR();
    glBindTexture(GL_TEXTURE_2D, maTexture);
    CHECK_GL_ERROR();
    SceneObject::display(sceneTransformLocation, primitiveTransformLocation, nTime, SlideWidth, SlideHeight, DispWidth, DispHeight);
}

void Iris::prepare(GLuint program)
{
    CHECK_GL_ERROR();
    static const GLubyte img[3] = { 80, 80, 80 };

    glGenTextures(1, &maTexture);
    glBindTexture(GL_TEXTURE_2D, maTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    CHECK_GL_ERROR();

    glGenVertexArrays(1, &maVertexArray);
    glBindVertexArray(maVertexArray);

    glGenBuffers(1, &maBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, maBuffer);
    maFirstIndices = uploadPrimitives(maPrimitives);

    // Attribute bindings
    GLint location = glGetAttribLocation(program, "a_position");
    if (location != -1) {
        glEnableVertexAttribArray(location);
        glVertexAttribPointer( location, 3, GL_FLOAT, falsesizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)) );
        CHECK_GL_ERROR();
    }

    location = glGetAttribLocation(program, "a_normal");
    if (location != -1) {
        glEnableVertexAttribArray(location);
        glVertexAttribPointer( location, 3, GL_FLOAT, falsesizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, normal)) );
        CHECK_GL_ERROR();
    }

    location = glGetAttribLocation(program, "a_texCoord");
    if (location != -1) {
        glEnableVertexAttribArray(location);
        glVertexAttribPointer( location, 2, GL_FLOAT, falsesizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, texcoord)) );
        CHECK_GL_ERROR();
    }

    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void Iris::finish()
{
    CHECK_GL_ERROR();
    glDeleteBuffers(1, &maBuffer);
    CHECK_GL_ERROR();
    glDeleteVertexArrays(1, &maVertexArray);
    CHECK_GL_ERROR();
    glDeleteTextures(1, &maTexture);
    CHECK_GL_ERROR();
}

}

namespace
{

class ReflectionTransition : public OGLTransitionImpl
{
public:
    ReflectionTransition(const TransitionScene& rScene, const TransitionSettings& ;rSettings)
        : OGLTransitionImpl(rScene, rSettings)
    {}

private:
    virtual GLuint makeShader() const override;
    virtual void displaySlides_( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale, OpenGLContext *pContext ) override;

    virtual void prepareTransition( sal_Int32, sal_Int32, OpenGLContext* ) override {
        glDisable(GL_CULL_FACE);
    }

    virtual void finishTransition() override {
        glEnable(GL_CULL_FACE);
    }
};

GLuint ReflectionTransition::makeShader() const
{
    return OpenGLHelper::LoadShaders( u"reflectionVertexShader"_ustr, u"reflectionFragmentShader"_ustr );
}

void ReflectionTransition::displaySlides_( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex,
                                              double SlideWidthScale, double SlideHeightScale, OpenGLContext * )
{
    CHECK_GL_ERROR();
    applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );

    sal_Int32 texture;
    Primitives_t slide;
    if (nTime < 0.5) {
        texture = glLeavingSlideTex;
        slide = getScene().getLeavingSlide();
    } else {
        texture = glEnteringSlideTex;
        slide = getScene().getEnteringSlide();
    }

    displaySlide( nTime, texture, slide, SlideWidthScale, SlideHeightScale );
    CHECK_GL_ERROR();
}

std::shared_ptr<OGLTransitionImpl>
makeReflectionTransition(
        Primitives_t&& rLeavingSlidePrimitives,
        Primitives_t&& rEnteringSlidePrimitives,
        Operations_t&& rOverallOperations,
        const TransitionSettings& rSettings)
{
    return std::make_shared<ReflectionTransition>(
            TransitionScene(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives), std::move(rOverallOperations), SceneObjects_t()),
            rSettings);
}

}

namespace
{

class SimpleTransition : public OGLTransitionImpl
{
public:
    SimpleTransition(const TransitionScene& rScene, const TransitionSettings& rSettings)
        : OGLTransitionImpl(rScene, rSettings)
    {
    }

private:
    virtual GLuint makeShader() const override;

    virtual void displaySlides_( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale, OpenGLContext *pContext ) override;
};

GLuint SimpleTransition::makeShader() const
{
    return OpenGLHelper::LoadShaders( u"basicVertexShader"_ustr, u"basicFragmentShader"_ustr );
}

void SimpleTransition::displaySlides_( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex,
                                       double SlideWidthScale, double SlideHeightScale, OpenGLContext * )
{
    CHECK_GL_ERROR();
    applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );

    CHECK_GL_ERROR();
    displaySlide( nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale );
    displaySlide( nTime, glEnteringSlideTex, getScene().getEnteringSlide(), SlideWidthScale, SlideHeightScale );
    CHECK_GL_ERROR();
}

std::shared_ptr<OGLTransitionImpl>
makeSimpleTransition(
        Primitives_t&& rLeavingSlidePrimitives,
        Primitives_t&& rEnteringSlidePrimitives,
        Operations_t&& rOverallOperations,
        SceneObjects_t&& rSceneObjects,
        const TransitionSettings& rSettings)
{
    return std::make_shared<SimpleTransition>(
            TransitionScene(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives),
                            std::move(rOverallOperations), std::move(rSceneObjects)),
            rSettings);
}

std::shared_ptr<OGLTransitionImpl>
makeSimpleTransition(
        Primitives_t&& rLeavingSlidePrimitives,
        Primitives_t&& rEnteringSlidePrimitives,
        Operations_t&& rOverallOperations,
        const TransitionSettings& rSettings = TransitionSettings())
{
    return makeSimpleTransition(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives),
                                std::move(rOverallOperations), SceneObjects_t(), rSettings);
}

std::shared_ptr<OGLTransitionImpl>
makeSimpleTransition(
        Primitives_t&& rLeavingSlidePrimitives,
        Primitives_t&& rEnteringSlidePrimitives,
        SceneObjects_t&& rSceneObjects,
        const TransitionSettings& rSettings)
{
    return makeSimpleTransition(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives),
                                Operations_t(), std::move(rSceneObjects), rSettings);
}

std::shared_ptr<OGLTransitionImpl>
makeSimpleTransition(
        Primitives_t&& rLeavingSlidePrimitives,
        Primitives_t&& rEnteringSlidePrimitives,
        const TransitionSettings& rSettings = TransitionSettings())
{
    return makeSimpleTransition(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives),
                                Operations_t(), SceneObjects_t(), rSettings);
}

}

std::shared_ptr<OGLTransitionImpl> makeOutsideCubeFaceToLeft()
{
    Primitive Slide;

    Slide.pushTriangle(glm::vec2(0,0),glm::vec2(1,0),glm::vec2(0,1));
    Slide.pushTriangle(glm::vec2(1,0),glm::vec2(0,1),glm::vec2(1,1));

    Primitives_t aLeavingPrimitives;
    aLeavingPrimitives.push_back(Slide);

    Slide.Operations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(0,1,0),glm::vec3(0,0,-1),90,false,false,0.0,1.0));

    Primitives_t aEnteringPrimitives;
    aEnteringPrimitives.push_back(Slide);

    Operations_t aOperations;
    aOperations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(0,1,0),glm::vec3(0,0,-1),-90,false,true,0.0,1.0));

    return makeSimpleTransition(std::move(aLeavingPrimitives), std::move(aEnteringPrimitives), std::move(aOperations));
}

std::shared_ptr<OGLTransitionImpl> makeInsideCubeFaceToLeft()
{
    Primitive Slide;

    Slide.pushTriangle(glm::vec2(0,0),glm::vec2(1,0),glm::vec2(0,1));
    Slide.pushTriangle(glm::vec2(1,0),glm::vec2(0,1),glm::vec2(1,1));

    Primitives_t aLeavingPrimitives;
    aLeavingPrimitives.push_back(Slide);

    Slide.Operations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(0,1,0),glm::vec3(0,0,1),-90,false,false,0.0,1.0));

    Primitives_t aEnteringPrimitives;
    aEnteringPrimitives.push_back(Slide);

    Operations_t aOperations;
    aOperations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(0,1,0),glm::vec3(0,0,1),90,false,true,0.0,1.0));

    return makeSimpleTransition(std::move(aLeavingPrimitives), std::move(aEnteringPrimitives), std::move(aOperations));
}

std::shared_ptr<OGLTransitionImpl> makeFallLeaving()
{
    Primitive Slide;

    Slide.pushTriangle(glm::vec2(0,0),glm::vec2(1,0),glm::vec2(0,1));
    Slide.pushTriangle(glm::vec2(1,0),glm::vec2(0,1),glm::vec2(1,1));

    Primitives_t aEnteringPrimitives;
    aEnteringPrimitives.push_back(Slide);

    Slide.Operations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(1,0,0),glm::vec3(0,-1,0), 90,true,true,0.0,1.0));
    Primitives_t aLeavingPrimitives;
    aLeavingPrimitives.push_back(Slide);

    TransitionSettings aSettings;
    aSettings.mbUseMipMapEntering = false;

    return makeSimpleTransition(std::move(aLeavingPrimitives), std::move(aEnteringPrimitives), aSettings);
}

std::shared_ptr<OGLTransitionImpl> makeTurnAround()
{
    Primitive Slide;
    TransitionSettings aSettings;

    Slide.pushTriangle(glm::vec2(0,0),glm::vec2(1,0),glm::vec2(0,1));
    Slide.pushTriangle(glm::vec2(1,0),glm::vec2(0,1),glm::vec2(1,1));
    Primitives_t aLeavingPrimitives;
    aLeavingPrimitives.push_back(Slide);

    Slide.Operations.push_back(makeSScale(glm::vec3(1, -1, 1), glm::vec3(0, -1.02, 0), false, -1, 0));
    aLeavingPrimitives.push_back(Slide);

    Slide.Operations.clear();
    Slide.Operations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(0,1,0),glm::vec3(0,0,0),-180,true,false,0.0,1.0));
    Primitives_t aEnteringPrimitives;
    aEnteringPrimitives.push_back(Slide);

    Slide.Operations.push_back(makeSScale(glm::vec3(1, -1, 1), glm::vec3(0, -1.02, 0), false, -1, 0));
    aEnteringPrimitives.push_back(Slide);

    Operations_t aOperations;
    aOperations.push_back(makeSTranslate(glm::vec3(0, 0, -1.5),true, 0, 0.5));
    aOperations.push_back(makeSTranslate(glm::vec3(0, 0, 1.5), true, 0.5, 1));
    aOperations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(0, 1, 0),glm::vec3(0, 0, 0), -180, truetrue, 0.0, 1.0));

    return makeReflectionTransition(std::move(aLeavingPrimitives), std::move(aEnteringPrimitives), std::move(aOperations), aSettings);
}

std::shared_ptr<OGLTransitionImpl> makeTurnDown()
{
    Primitive Slide;

    Slide.pushTriangle(glm::vec2(0,0),glm::vec2(1,0),glm::vec2(0,1));
    Slide.pushTriangle(glm::vec2(1,0),glm::vec2(0,1),glm::vec2(1,1));
    Primitives_t aLeavingPrimitives;
    aLeavingPrimitives.push_back(Slide);

    Slide.Operations.push_back(makeSTranslate(glm::vec3(0, 0, 0.0001), false, -1.0, 0.0));
    Slide.Operations.push_back(makeSRotate (glm::vec3(0, 0, 1), glm::vec3(-1, 1, 0), -90, true, 0.0, 1.0));
    Slide.Operations.push_back(makeSRotate (glm::vec3(0, 0, 1), glm::vec3(-1, 1, 0), 90, false, -1.0, 0.0));
    Primitives_t aEnteringPrimitives;
    aEnteringPrimitives.push_back(Slide);

    TransitionSettings aSettings;
    aSettings.mbUseMipMapLeaving = false;

    return makeSimpleTransition(std::move(aLeavingPrimitives), std::move(aEnteringPrimitives), aSettings);
}

std::shared_ptr<OGLTransitionImpl> makeIris()
{
    Primitive Slide;

    Slide.pushTriangle (glm::vec2 (0,0), glm::vec2 (1,0), glm::vec2 (0,1));
    Slide.pushTriangle (glm::vec2 (1,0), glm::vec2 (0,1), glm::vec2 (1,1));
    Primitives_t aEnteringPrimitives;
    aEnteringPrimitives.push_back (Slide);

    Slide.Operations.push_back (makeSTranslate (glm::vec3 (0, 0,  0.000001), false, -1, 0));
    Slide.Operations.push_back (makeSTranslate (glm::vec3 (0, 0, -0.000002), false, 0.5, 1));
    Primitives_t aLeavingPrimitives;
    aLeavingPrimitives.push_back (Slide);


    Primitive irisPart;
    int i, nSteps = 24, nParts = 7;
    double t = 1.0/nSteps, lx = 1, ly = 0, of=2.2, f=1.42;

    for (i=1; i<=nSteps; i++) {
        double x = cos ((3*2*M_PI*t)/nParts);
        double y = -sin ((3*2*M_PI*t)/nParts);
        double cx = (f*x + 1)/2;
        double cy = (f*y + 1)/2;
        double lcx = (f*lx + 1)/2;
        double lcy = (f*ly + 1)/2;
        double cxo = (of*x + 1)/2;
        double cyo = (of*y + 1)/2;
        double lcxo = (of*lx + 1)/2;
        double lcyo = (of*ly + 1)/2;
        irisPart.pushTriangle (glm::vec2 (lcx, lcy),
                               glm::vec2 (lcxo, lcyo),
                               glm::vec2 (cx, cy));
        irisPart.pushTriangle (glm::vec2 (cx, cy),
                               glm::vec2 (lcxo, lcyo),
                               glm::vec2 (cxo, cyo));
        lx = x;
        ly = y;
        t += 1.0/nSteps;
    }

    std::shared_ptr<Iris> pIris = std::make_shared<Iris>();
    double angle = 87;

    for (i = 0; i < nParts; i++) {
        irisPart.Operations.clear ();
        double rx, ry;

        rx = cos ((2*M_PI*i)/nParts);
        ry = sin ((2*M_PI*i)/nParts);
        irisPart.Operations.push_back (makeSRotate (glm::vec3(0, 0, 1), glm::vec3(rx, ry, 0),  angle, true, 0.0, 0.5));
        irisPart.Operations.push_back (makeSRotate (glm::vec3(0, 0, 1), glm::vec3(rx, ry, 0), -angle, true, 0.5, 1));
        if (i > 0) {
            irisPart.Operations.push_back (makeSTranslate (glm::vec3(rx, ry, 0),  false, -1, 0));
            irisPart.Operations.push_back (makeSRotate (glm::vec3(0, 0, 1), glm::vec3(0, 0, 0), i*360.0/nParts, false, -1, 0));
            irisPart.Operations.push_back (makeSTranslate (glm::vec3(-1, 0, 0),  false, -1, 0));
        }
        irisPart.Operations.push_back(makeSTranslate(glm::vec3(0, 0, 1), false, -2, 0.0));
        irisPart.Operations.push_back (makeSRotate (glm::vec3(1, .5, 0), glm::vec3(1, 0, 0), -30false, -1, 0));
        pIris->pushPrimitive (irisPart);
    }

    SceneObjects_t aSceneObjects;
    aSceneObjects.push_back (pIris);

    TransitionSettings aSettings;
    aSettings.mbUseMipMapLeaving = aSettings.mbUseMipMapEntering = false;

    return makeSimpleTransition(std::move(aLeavingPrimitives), std::move(aEnteringPrimitives), std::move(aSceneObjects), aSettings);
}

namespace
{

class RochadeTransition : public ReflectionTransition
{
public:
    RochadeTransition(const TransitionScene& rScene, const TransitionSettings& rSettings)
        : ReflectionTransition(rScene, rSettings)
    {}

private:
    virtual void displaySlides_(double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale, OpenGLContext *pContext) override;
};

void RochadeTransition::displaySlides_( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale, OpenGLContext * )
{
    applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );

    if( nTime > .5) {
        displaySlide( nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale );
        displaySlide( nTime, glEnteringSlideTex, getScene().getEnteringSlide(), SlideWidthScale, SlideHeightScale );
    } else {
        displaySlide( nTime, glEnteringSlideTex, getScene().getEnteringSlide(), SlideWidthScale, SlideHeightScale );
        displaySlide( nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale );
    }
}

std::shared_ptr<OGLTransitionImpl>
makeRochadeTransition(
        Primitives_t&& rLeavingSlidePrimitives,
        Primitives_t&& rEnteringSlidePrimitives,
        const TransitionSettings& rSettings)
{
    return std::make_shared<RochadeTransition>(
            TransitionScene(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives)),
            rSettings)
        ;

}
}

std::shared_ptr<OGLTransitionImpl> makeRochade()
{
    Primitive Slide;
    TransitionSettings aSettings;

    double w, h;

    w = 2.2;
    h = 10;

    Slide.pushTriangle(glm::vec2(0,0),glm::vec2(1,0),glm::vec2(0,1));
    Slide.pushTriangle(glm::vec2(1,0),glm::vec2(0,1),glm::vec2(1,1));

    Slide.Operations.push_back(makeSEllipseTranslate(w, h, 0.25, -0.25, true, 0, 1));
    Slide.Operations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(0,1,0),glm::vec3(0,0,0), -45, truetrue, 0, 1));
    Primitives_t aLeavingSlide;
    aLeavingSlide.push_back(Slide);

    Slide.Operations.push_back(makeSScale(glm::vec3(1, -1, 1), glm::vec3(0, -1.02, 0), false, -1, 0));
    aLeavingSlide.push_back(Slide);

    Slide.Operations.clear();
    Slide.Operations.push_back(makeSEllipseTranslate(w, h, 0.75, 0.25, true, 0, 1));
    Slide.Operations.push_back(makeSTranslate(glm::vec3(0, 0, -h), false, -1, 0));
    Slide.Operations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(0,1,0),glm::vec3(0,0,0), -45, truetrue, 0, 1));
    Slide.Operations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(0,1,0),glm::vec3(0,0,0), 45, truefalse, -1, 0));
    Primitives_t aEnteringSlide;
    aEnteringSlide.push_back(Slide);

    Slide.Operations.push_back(makeSScale(glm::vec3(1, -1, 1), glm::vec3(0, -1.02, 0), false, -1, 0));
    aEnteringSlide.push_back(Slide);

    return makeRochadeTransition(std::move(aLeavingSlide), std::move(aEnteringSlide), aSettings);
}

static double randFromNeg1to1()
{
    return comphelper::rng::uniform_real_distribution(-1.0, std::nextafter(1.0, DBL_MAX));
}

// TODO(Q3): extract to basegfx
static glm::vec3 randNormVectorInXYPlane()
{
    glm::vec3 toReturn(randFromNeg1to1(),randFromNeg1to1(),0.0);
    return glm::normalize(toReturn);
}

template<typename T>
static T clamp(const T& rIn)
{
    return glm::clamp(rIn, T(-1.0), T(1.0));
}

std::shared_ptr<OGLTransitionImpl> makeRevolvingCircles( sal_uInt16 nCircles , sal_uInt16 nPointsOnCircles )
{
    double dAngle(2*M_PI/static_cast<double>( nPointsOnCircles ));
    if(nCircles < 2 || nPointsOnCircles < 4)
        return makeNByMTileFlip(1,1);
    float Radius(1.0/static_cast<double>( nCircles ));
    float dRadius(Radius);
    float LastRadius(0.0);
    float NextRadius(2*Radius);

    /// now we know there is at least two circles
    /// the first will always be a full circle
    /// the last will always be the outer shell of the slide with a circle hole

    //add the full circle
    std::vector<glm::vec2> unScaledTexCoords;
    float TempAngle(0.0);
    for(unsigned int Point(0); Point < nPointsOnCircles; ++Point)
    {
        unScaledTexCoords.emplace_back( cos(TempAngle - M_PI_2) , sin(TempAngle- M_PI_2) );

        TempAngle += dAngle;
    }

    Primitives_t aLeavingSlide;
    Primitives_t aEnteringSlide;
    {
        Primitive EnteringSlide;
        Primitive LeavingSlide;
        for(int Point(0); Point + 1 < nPointsOnCircles; ++Point)
        {
            EnteringSlide.pushTriangle( glm::vec2( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point + 1 ] / 2.0f + glm::vec2( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point ] / 2.0f + glm::vec2( 0.5 , 0.5 ) );
            LeavingSlide.pushTriangle( glm::vec2( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point + 1 ] / 2.0f + glm::vec2( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point ] / 2.0f + glm::vec2( 0.5, 0.5) );
        }
        EnteringSlide.pushTriangle( glm::vec2(0.5,0.5) , Radius * unScaledTexCoords[ 0 ] / 2.0f + glm::vec2( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ nPointsOnCircles - 1 ] / 2.0f + glm::vec2( 0.5 , 0.5 ) );
        LeavingSlide.pushTriangle( glm::vec2(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0f + glm::vec2(0.5,0.5) , Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0f + glm::vec2(0.5,0.5) );

        glm::vec3 axis(randNormVectorInXYPlane());
        EnteringSlide.Operations.push_back( makeSRotate( axis , glm::vec3(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
        LeavingSlide.Operations.push_back( makeSRotate( axis , glm::vec3(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
        EnteringSlide.Operations.push_back( makeSRotate( axis , glm::vec3(0,0,0) , -180, false,0.0,1.0) );

        aEnteringSlide.push_back(EnteringSlide);
        aLeavingSlide.push_back(LeavingSlide);
        LastRadius = Radius;
        Radius = NextRadius;
        NextRadius += dRadius;
    }

    for(int i(1); i < nCircles - 1; ++i)
    {
        Primitive LeavingSlide;
        Primitive EnteringSlide;
        for(int Side(0); Side < nPointsOnCircles - 1; ++Side)
        {
            EnteringSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0f + glm::vec2(0.5,0.5) );
            EnteringSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0f + glm::vec2(0.5,0.5) , Radius*unScaledTexCoords[Side + 1]/2.0f + glm::vec2(0.5,0.5) );

            LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0f + glm::vec2(0.5,0.5) );
            LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0f + glm::vec2(0.5,0.5) , Radius*unScaledTexCoords[Side + 1]/2.0f + glm::vec2(0.5,0.5) );
        }

        EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0f + glm::vec2(0.5,0.5) );
        EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0f + glm::vec2(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0f + glm::vec2(0.5,0.5) );

        LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0f + glm::vec2(0.5,0.5) );
        LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0f + glm::vec2(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0f + glm::vec2(0.5,0.5) );

        glm::vec3 axis(randNormVectorInXYPlane());
        EnteringSlide.Operations.push_back( makeSRotate( axis , glm::vec3(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
        LeavingSlide.Operations.push_back( makeSRotate( axis , glm::vec3(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
        EnteringSlide.Operations.push_back( makeSRotate( axis , glm::vec3(0,0,0) , -180, false,0.0,1.0) );

        aEnteringSlide.push_back(EnteringSlide);
        aLeavingSlide.push_back(LeavingSlide);

        LastRadius = Radius;
        Radius = NextRadius;
        NextRadius += dRadius;
    }
    {
        Radius = sqrt(2.0);
        Primitive LeavingSlide;
        Primitive EnteringSlide;
        for(int Side(0); Side < nPointsOnCircles - 1; ++Side)
        {

            EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0f + glm::vec2(0.5,0.5) );
            EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0f + glm::vec2(0.5,0.5) , clamp(Radius*unScaledTexCoords[Side + 1])/2.0f + glm::vec2(0.5,0.5) );

            LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0f + glm::vec2(0.5,0.5) );
            LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0f + glm::vec2(0.5,0.5) , clamp(Radius*unScaledTexCoords[Side + 1])/2.0f + glm::vec2(0.5,0.5) );
        }

        EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0f + glm::vec2(0.5,0.5) );
        EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0f + glm::vec2(0.5,0.5) , clamp(Radius*unScaledTexCoords[0])/2.0f + glm::vec2(0.5,0.5) );

        LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0f + glm::vec2(0.5,0.5) );
        LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0f + glm::vec2(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0f + glm::vec2(0.5,0.5) , clamp(Radius*unScaledTexCoords[0])/2.0f + glm::vec2(0.5,0.5) );

        glm::vec3 axis(randNormVectorInXYPlane());
        EnteringSlide.Operations.push_back( makeSRotate( axis , glm::vec3(0,0,0) , 180, true, (LastRadius + dRadius)/2.0 , 1.0 ) );
        LeavingSlide.Operations.push_back( makeSRotate( axis , glm::vec3(0,0,0) , 180, true, (LastRadius + dRadius)/2.0 , 1.0 ) );
        EnteringSlide.Operations.push_back( makeSRotate( axis , glm::vec3(0,0,0) , -180, false,0.0,1.0) );

        aEnteringSlide.push_back(EnteringSlide);
        aLeavingSlide.push_back(LeavingSlide);
    }

    return makeSimpleTransition(std::move(aLeavingSlide), std::move(aEnteringSlide));
}

std::shared_ptr<OGLTransitionImpl> makeHelix( sal_uInt16 nRows )
{
    double invN(1.0/static_cast<double>(nRows));
    double iDn = 0.0;
    double iPDn = invN;
    Primitives_t aLeavingSlide;
    Primitives_t aEnteringSlide;
    for(unsigned int i(0); i < nRows; ++i)
    {
        Primitive Tile;

        Tile.pushTriangle(glm::vec2( 1.0 , iDn ) , glm::vec2( 0.0 , iDn ) , glm::vec2( 0.0 , iPDn ));

        Tile.pushTriangle(glm::vec2( 1.0 , iPDn ) , glm::vec2( 1.0 , iDn ) , glm::vec2( 0.0 , iPDn ));

        Tile.Operations.push_back( makeSRotate( glm::vec3( 0 , 1 , 0 ) , ( Tile.getVertex(1) + Tile.getVertex(3) )/2.0f , 180 ,
                                                true, std::min(std::max(static_cast<double>(i - nRows/2.0)*invN/2.0,0.0),1.0),
                                                std::min(std::max(static_cast<double>(i + nRows/2.0)*invN/2.0,0.0),1.0) ) );

        aLeavingSlide.push_back(Tile);

        Tile.Operations.push_back( makeSRotate( glm::vec3( 0 , 1 , 0 ) , ( Tile.getVertex(1) + Tile.getVertex(3) )/2.0f , -180 , false,0.0,1.0) );

        aEnteringSlide.push_back(Tile);

        iDn += invN;
        iPDn += invN;
    }

    return makeSimpleTransition(std::move(aLeavingSlide), std::move(aEnteringSlide));
}

static float fdiv(int a, int b)
{
    return static_cast<float>(a)/b;
}

static glm::vec2 vec(float x, float y, float nx, float ny)
{
    x = x < 0.0 ? 0.0 : x;
    x = std::min(x, nx);
    y = y < 0.0 ? 0.0 : y;
    y = std::min(y, ny);
    return glm::vec2(fdiv(x, nx), fdiv(y, ny));
}

std::shared_ptr<OGLTransitionImpl> makeNByMTileFlip( sal_uInt16 n, sal_uInt16 m )
{
    Primitives_t aLeavingSlide;
    Primitives_t aEnteringSlide;

    for (int x = 0; x < n; x++)
    {
        for (int y = 0; y < n; y++)
        {
            Primitive aTile;
            glm::vec2 x11 = vec(x,   y,   n, m);
            glm::vec2 x12 = vec(x,   y+1, n, m);
            glm::vec2 x21 = vec(x+1, y,   n, m);
            glm::vec2 x22 = vec(x+1, y+1, n, m);

            aTile.pushTriangle(x21, x11, x12);
            aTile.pushTriangle(x22, x21, x12);

            aTile.Operations.push_back(makeSRotate( glm::vec3(0 , 1, 0), (aTile.getVertex(1) + aTile.getVertex(3)) / 2.0f, 180 , true, x11.x * x11.y / 2.0f , ((x22.x * x22.y) + 1.0f) / 2.0f));
            aLeavingSlide.push_back(aTile);

            aTile.Operations.push_back(makeSRotate( glm::vec3(0 , 1, 0), (aTile.getVertex(1) + aTile.getVertex(3)) / 2.0f, -180, false, x11.x * x11.y / 2.0f , ((x22.x * x22.y) + 1.0f) / 2.0f));
            aEnteringSlide.push_back(aTile);
        }
    }

    return makeSimpleTransition(std::move(aLeavingSlide), std::move(aEnteringSlide));
}

Primitive& Primitive::operator=(const Primitive& rvalue)
{
    Primitive aTmp(rvalue);
    swap(aTmp);
    return *this;
}

Primitive::Primitive(const Primitive& rvalue)
    : Operations(rvalue.Operations)
    , Vertices(rvalue.Vertices)
{
}

void Primitive::swap(Primitive& rOther)
{
    using std::swap;

    swap(Operations, rOther.Operations);
    swap(Vertices, rOther.Vertices);
}

void Primitive::pushTriangle(const glm::vec2& SlideLocation0,const glm::vec2& ;SlideLocation1,const glm::vec2& SlideLocation2)
{
    std::vector<glm::vec3> Verts;
    std::vector<glm::vec2> Texs;
    Verts.reserve(3);
    Texs.reserve(3);

    Verts.emplace_back( 2*SlideLocation0.x - 1, -2*SlideLocation0.y + 1 , 0.0 );
    Verts.emplace_back( 2*SlideLocation1.x - 1, -2*SlideLocation1.y + 1 , 0.0 );
    Verts.emplace_back( 2*SlideLocation2.x - 1, -2*SlideLocation2.y + 1 , 0.0 );

    //figure out if they're facing the correct way, and make them face the correct way.
    glm::vec3 Normal( glm::cross( Verts[0] - Verts[1] , Verts[1] - Verts[2] ) );
    if(Normal.z >= 0.0)//if the normal is facing us
    {
        Texs.push_back(SlideLocation0);
        Texs.push_back(SlideLocation1);
        Texs.push_back(SlideLocation2);
    }
    else // if the normal is facing away from us, make it face us
    {
        Texs.push_back(SlideLocation0);
        Texs.push_back(SlideLocation2);
        Texs.push_back(SlideLocation1);
        Verts.clear();
        Verts.emplace_back( 2*SlideLocation0.x - 1, -2*SlideLocation0.y + 1 , 0.0 );
        Verts.emplace_back( 2*SlideLocation2.x - 1, -2*SlideLocation2.y + 1 , 0.0 );
        Verts.emplace_back( 2*SlideLocation1.x - 1, -2*SlideLocation1.y + 1 , 0.0 );
    }

    Vertices.push_back({Verts[0], glm::vec3(0, 0, 1), Texs[0]}); //all normals always face the screen when untransformed.
    Vertices.push_back({Verts[1], glm::vec3(0, 0, 1), Texs[1]}); //all normals always face the screen when untransformed.
    Vertices.push_back({Verts[2], glm::vec3(0, 0, 1), Texs[2]}); //all normals always face the screen when untransformed.
}

namespace
{

class DiamondTransition : public SimpleTransition
{
public:
    DiamondTransition(const TransitionScene& rScene, const TransitionSettings& rSettings)
        : SimpleTransition(rScene, rSettings)
        {}

private:
    virtual void displaySlides_( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale, OpenGLContext *pContext ) override;
};

Primitives_t makeLeavingSlide(double nTime)
{
    Primitive Slide2;
    if( nTime >= 0.5 ) {
        double m = 1 - nTime;

        Slide2.pushTriangle (glm::vec2 (0,0), glm::vec2 (m,0), glm::vec2 (0,m));
        Slide2.pushTriangle (glm::vec2 (nTime,0), glm::vec2 (1,0), glm::vec2 (1,m));
        Slide2.pushTriangle (glm::vec2 (1,nTime), glm::vec2 (1,1), glm::vec2 (nTime,1));
        Slide2.pushTriangle (glm::vec2 (0,nTime), glm::vec2 (m,1), glm::vec2 (0,1));
    } else {
        double l = 0.5 - nTime;
        double h = 0.5 + nTime;

        Slide2.pushTriangle (glm::vec2 (0,0), glm::vec2 (1,0), glm::vec2 (0.5,l));
        Slide2.pushTriangle (glm::vec2 (0.5,l), glm::vec2 (1,0), glm::vec2 (h,0.5));
        Slide2.pushTriangle (glm::vec2 (1,0), glm::vec2 (1,1), glm::vec2 (h,0.5));
        Slide2.pushTriangle (glm::vec2 (h,0.5), glm::vec2 (1,1), glm::vec2 (0.5,h));
        Slide2.pushTriangle (glm::vec2 (0.5,h), glm::vec2 (1,1), glm::vec2 (0,1));
        Slide2.pushTriangle (glm::vec2 (l,0.5), glm::vec2 (0.5,h), glm::vec2 (0,1));
        Slide2.pushTriangle (glm::vec2 (0,0), glm::vec2 (l,0.5), glm::vec2 (0,1));
        Slide2.pushTriangle (glm::vec2 (0,0), glm::vec2 (0.5,l), glm::vec2 (l,0.5));
    }
    Slide2.Operations.push_back (makeSTranslate (glm::vec3 (0, 0, 0.00000001), false, -1, 0));
    Primitives_t aLeavingSlidePrimitives;
    aLeavingSlidePrimitives.push_back (Slide2);

    return aLeavingSlidePrimitives;
}

void DiamondTransition::displaySlides_( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex,
                                        double SlideWidthScale, double SlideHeightScale, OpenGLContext * )
{
    CHECK_GL_ERROR();
    applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );

    CHECK_GL_ERROR();
    displayUnbufferedSlide( nTime, glLeavingSlideTex, makeLeavingSlide(nTime), SlideWidthScale, SlideHeightScale );
    displaySlide( nTime, glEnteringSlideTex, getScene().getEnteringSlide(), SlideWidthScale, SlideHeightScale );
    CHECK_GL_ERROR();
}

std::shared_ptr<OGLTransitionImpl>
makeDiamondTransition(const TransitionSettings& rSettings)
{
    Primitive Slide1;
    Slide1.pushTriangle (glm::vec2 (0,0), glm::vec2 (1,0), glm::vec2 (0,1));
    Slide1.pushTriangle (glm::vec2 (1,0), glm::vec2 (0,1), glm::vec2 (1,1));
    Primitives_t aEnteringSlidePrimitives;
    aEnteringSlidePrimitives.push_back (Slide1);
    Primitives_t aLeavingSlidePrimitives;
    aLeavingSlidePrimitives.push_back (Slide1);
    return std::make_shared<DiamondTransition>(TransitionScene(std::move(aLeavingSlidePrimitives), std::move(aEnteringSlidePrimitives)), rSettings);
}

}

std::shared_ptr<OGLTransitionImpl> makeDiamond()
{
    TransitionSettings aSettings;
    aSettings.mbUseMipMapLeaving = aSettings.mbUseMipMapEntering = false;

    return makeDiamondTransition(aSettings);
}

std::shared_ptr<OGLTransitionImpl> makeVenetianBlinds( bool vertical, int parts )
{
    static double t30 = tan( M_PI/6.0 );
    double ln = 0;
    double p = 1.0/parts;

    Primitives_t aLeavingSlide;
    Primitives_t aEnteringSlide;
    forint i=0; i<parts; i++ ) {
        Primitive Slide;
        double n = (i + 1)/static_cast<double>(parts);
        if( vertical ) {
            Slide.pushTriangle (glm::vec2 (ln,0), glm::vec2 (n,0), glm::vec2 (ln,1));
            Slide.pushTriangle (glm::vec2 (n,0), glm::vec2 (ln,1), glm::vec2 (n,1));
            Slide.Operations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(0, 1, 0), glm::vec3(n + ln - 1, 0, -t30*p), -120, truetrue, 0.0, 1.0));
        } else {
            Slide.pushTriangle (glm::vec2 (0,ln), glm::vec2 (1,ln), glm::vec2 (0,n));
            Slide.pushTriangle (glm::vec2 (1,ln), glm::vec2 (0,n), glm::vec2 (1,n));
            Slide.Operations.push_back(makeRotateAndScaleDepthByHeight(glm::vec3(1, 0, 0), glm::vec3(0, 1 - n - ln, -t30*p), -120, truetrue, 0.0, 1.0));
        }
        aLeavingSlide.push_back (Slide);

        if( vertical ) {
            Slide.Operations.push_back(makeSRotate(glm::vec3(0, 1, 0), glm::vec3(2*n - 1, 0, 0), -60false, -1, 0));
            Slide.Operations.push_back(makeSRotate(glm::vec3(0, 1, 0), glm::vec3(n + ln - 1, 0, 0), 180, false, -1, 0));
        } else {
            Slide.Operations.push_back(makeSRotate(glm::vec3(1, 0, 0), glm::vec3(0, 1 - 2*n, 0), -60false, -1, 0));
            Slide.Operations.push_back(makeSRotate(glm::vec3(1, 0, 0), glm::vec3(0, 1 - n - ln, 0), 180, false, -1, 0));
        }
        aEnteringSlide.push_back (Slide);
        ln = n;
    }

    return makeSimpleTransition(std::move(aLeavingSlide), std::move(aEnteringSlide));
}

namespace
{

class FadeSmoothlyTransition : public OGLTransitionImpl
{
public:
    FadeSmoothlyTransition(const TransitionScene& rScene, const TransitionSettings&&nbsp;rSettings)
        : OGLTransitionImpl(rScene, rSettings)
    {}

private:
    virtual GLuint makeShader() const override;
};

GLuint FadeSmoothlyTransition::makeShader() const
{
    return OpenGLHelper::LoadShaders( u"basicVertexShader"_ustr, u"fadeFragmentShader"_ustr );
}

std::shared_ptr<OGLTransitionImpl>
makeFadeSmoothlyTransition(
        Primitives_t&& rLeavingSlidePrimitives,
        Primitives_t&& rEnteringSlidePrimitives,
        const TransitionSettings& rSettings)
{
    return std::make_shared<FadeSmoothlyTransition>(
            TransitionScene(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives)),
            rSettings)
        ;
}

}

std::shared_ptr<OGLTransitionImpl> makeFadeSmoothly()
{
    Primitive Slide;

    Slide.pushTriangle (glm::vec2 (0,0), glm::vec2 (1,0), glm::vec2 (0,1));
    Slide.pushTriangle (glm::vec2 (1,0), glm::vec2 (0,1), glm::vec2 (1,1));
    Primitives_t aLeavingSlide;
    aLeavingSlide.push_back (Slide);
    Primitives_t aEnteringSlide;
    aEnteringSlide.push_back (Slide);

    TransitionSettings aSettings;
    aSettings.mbUseMipMapLeaving = aSettings.mbUseMipMapEntering = false;

    return makeFadeSmoothlyTransition(std::move(aLeavingSlide), std::move(aEnteringSlide), aSettings);
}

namespace
{

class FadeThroughColorTransition : public OGLTransitionImpl
{
public:
    FadeThroughColorTransition(const TransitionScene& rScene, const TransitionSettings& rSettings, bool white)
        : OGLTransitionImpl(rScene, rSettings), useWhite( white )
    {}

private:
    virtual GLuint makeShader() const override;
    bool useWhite;
};

GLuint FadeThroughColorTransition::makeShader() const
{
    return OpenGLHelper::LoadShaders( u"basicVertexShader"_ustr, u"fadeBlackFragmentShader"_ustr,
        useWhite ? "#define use_white" : """" );
}

std::shared_ptr<OGLTransitionImpl>
makeFadeThroughColorTransition(
        Primitives_t&& rLeavingSlidePrimitives,
        Primitives_t&& rEnteringSlidePrimitives,
        const TransitionSettings& rSettings,
        bool white)
{
    return std::make_shared<FadeThroughColorTransition>(
            TransitionScene(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives)),
            rSettings, white)
        ;
}

}

std::shared_ptr<OGLTransitionImpl> makeFadeThroughColor( bool white )
{
    Primitive Slide;

    Slide.pushTriangle (glm::vec2 (0,0), glm::vec2 (1,0), glm::vec2 (0,1));
    Slide.pushTriangle (glm::vec2 (1,0), glm::vec2 (0,1), glm::vec2 (1,1));
    Primitives_t aLeavingSlide;
    aLeavingSlide.push_back (Slide);
    Primitives_t aEnteringSlide;
    aEnteringSlide.push_back (Slide);

    TransitionSettings aSettings;
    aSettings.mbUseMipMapLeaving = aSettings.mbUseMipMapEntering = false;

    return makeFadeThroughColorTransition(std::move(aLeavingSlide), std::move(aEnteringSlide), aSettings, white);
}

namespace
{

class PermTextureTransition : public OGLTransitionImpl
{
protected:
    PermTextureTransition(const TransitionScene& rScene, const TransitionSettings&&nbsp;rSettings)
        : OGLTransitionImpl(rScene, rSettings)
        , m_nHelperTexture(0)
    {}

    virtual void finishTransition() override;
    virtual void prepareTransition( sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, OpenGLContext *pContext ) override;

private:
    /** various data */
    GLuint m_nHelperTexture;
};

void PermTextureTransition::finishTransition()
{
    CHECK_GL_ERROR();
    if ( m_nHelperTexture )
    {
        glDeleteTextures( 1, &m_nHelperTexture );
        m_nHelperTexture = 0;
    }
    CHECK_GL_ERROR();
}

constexpr auto permutation2D = []() constexpr {
    int permutation256 [256]= {
    215, 100, 200, 204, 233,  50,  85, 196,
     71, 141, 122, 160,  93, 131, 243, 234,
    162, 183,  36, 155,   4,  62,  35, 205,
     40, 102,  33,  27, 255,  55, 214, 156,
     75, 163, 134, 126, 249,  74, 197, 228,
     72,  90, 206, 235,  17,  22,  49, 169,
    227,  89,  16,   5, 117,  60, 248, 230,
    217,  68, 138,  96, 194, 170, 136,  10,
    112, 238, 184, 189, 176,  42, 225, 212,
     84,  58, 175, 244, 150, 168, 219, 236,
    101, 208, 123,  37, 164, 110, 158, 201,
     78, 114,  57,  48,  70, 142, 106,  43,
    232,  26,  32, 252, 239,  98, 191,  94,
     59, 149,  39, 187, 203, 190,  19,  13,
    133,  45,  61, 247,  23,  34,  20,  52,
    118, 209, 146, 193, 222,  18,   1, 152,
     46,  41,  91, 148, 115,  25, 135,  77,
    254, 147, 224, 161,   9, 213, 223, 250,
    231, 251, 127, 166,  63, 179,  81, 130,
    139,  28, 120, 151, 241,  86, 111,   0,
     88, 153, 172, 182, 159, 105, 178,  47,
     51, 167,  65,  66,  92,  73, 198, 211,
    245, 195,  31, 220, 140,  76, 221, 186,
    154, 185,  56,  83,  38, 165, 109,  67,
    124, 226, 132,  53, 229,  29,  12, 181,
    121,  24, 207, 199, 177, 113,  30,  80,
      3,  97, 188,  79, 216, 173,   8, 145,
     87, 128, 180, 237, 240, 137, 125, 104,
     15, 242, 119, 246, 103, 143,  95, 144,
      2,  44,  69, 157, 192, 174,  14,  54,
    218,  82,  64, 210,  11,   6, 129,  21,
    116, 171,  99, 202,   7, 107, 253, 108
    };
    std::array<unsigned char, 256 * 256> a{};
    for (int y = 0; y < 256; y++)
        for (int x = 0; x < 256; x++)
            a[x + y * 256] = permutation256[(y + permutation256[x]) & 0xff];
    return a;
}();

void initPermTexture(GLuint *texID)
{
    CHECK_GL_ERROR();
    glGenTextures(1, texID);
    glBindTexture(GL_TEXTURE_2D, *texID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RED, GL_UNSIGNED_BYTE,
                 permutation2D.data());
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    CHECK_GL_ERROR();
}

void PermTextureTransition::prepareTransition( sal_Int32, sal_Int32, OpenGLContext* )
{
    CHECK_GL_ERROR();
    GLint location = glGetUniformLocation( m_nProgramObject, "permTexture" );
    if( location != -1 ) {
        glActiveTexture(GL_TEXTURE1);
        CHECK_GL_ERROR();
        if( !m_nHelperTexture )
            initPermTexture( &m_nHelperTexture );

        glActiveTexture(GL_TEXTURE0);
        CHECK_GL_ERROR();

        glUniform1i( location, 1 );  // texture unit 1
        CHECK_GL_ERROR();
    }
    CHECK_GL_ERROR();
}

}

namespace
{

class StaticNoiseTransition : public PermTextureTransition
{
public:
    StaticNoiseTransition(const TransitionScene& rScene, const TransitionSettings&&nbsp;rSettings)
        : PermTextureTransition(rScene, rSettings)
    {}

private:
    virtual GLuint makeShader() const override;
};

GLuint StaticNoiseTransition::makeShader() const
{
    return OpenGLHelper::LoadShaders( u"basicVertexShader"_ustr, u"staticFragmentShader"_ustr );
}

std::shared_ptr<OGLTransitionImpl>
makeStaticNoiseTransition(
        Primitives_t&& rLeavingSlidePrimitives,
        Primitives_t&& rEnteringSlidePrimitives,
        const TransitionSettings& rSettings)
{
    return std::make_shared<StaticNoiseTransition>(
            TransitionScene(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives)),
            rSettings)
        ;
}

}

std::shared_ptr<OGLTransitionImpl> makeStatic()
{
    Primitive Slide;

    Slide.pushTriangle (glm::vec2 (0,0), glm::vec2 (1,0), glm::vec2 (0,1));
    Slide.pushTriangle (glm::vec2 (1,0), glm::vec2 (0,1), glm::vec2 (1,1));
    Primitives_t aLeavingSlide;
    aLeavingSlide.push_back (Slide);
    Primitives_t aEnteringSlide;
    aEnteringSlide.push_back (Slide);

    TransitionSettings aSettings;
    aSettings.mbUseMipMapLeaving = aSettings.mbUseMipMapEntering = false;

    return makeStaticNoiseTransition(std::move(aLeavingSlide), std::move(aEnteringSlide), aSettings);
}

namespace
{

class DissolveTransition : public PermTextureTransition
{
public:
    DissolveTransition(const TransitionScene& rScene, const TransitionSettings& rSettings)
        : PermTextureTransition(rScene, rSettings)
    {}

private:
    virtual GLuint makeShader() const override;
};

GLuint DissolveTransition::makeShader() const
{
    return OpenGLHelper::LoadShaders( u"basicVertexShader"_ustr, u"dissolveFragmentShader"_ustr );
}

std::shared_ptr<OGLTransitionImpl>
makeDissolveTransition(
        Primitives_t&& rLeavingSlidePrimitives,
        Primitives_t&& rEnteringSlidePrimitives,
        const TransitionSettings& rSettings)
{
    return std::make_shared<DissolveTransition>(
            TransitionScene(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives)),
            rSettings)
        ;
}

}

std::shared_ptr<OGLTransitionImpl> makeDissolve()
{
    Primitive Slide;

    Slide.pushTriangle (glm::vec2 (0,0), glm::vec2 (1,0), glm::vec2 (0,1));
    Slide.pushTriangle (glm::vec2 (1,0), glm::vec2 (0,1), glm::vec2 (1,1));
    Primitives_t aLeavingSlide;
    aLeavingSlide.push_back (Slide);
    Primitives_t aEnteringSlide;
    aEnteringSlide.push_back (Slide);

    TransitionSettings aSettings;
    aSettings.mbUseMipMapLeaving = aSettings.mbUseMipMapEntering = false;

    return makeDissolveTransition(std::move(aLeavingSlide), std::move(aEnteringSlide), aSettings);
}

namespace
{

class VortexTransition : public PermTextureTransition
{
public:
    VortexTransition(const TransitionScene& rScene, const TransitionSettings& rSettings, int nNX, int nNY)
        : PermTextureTransition(rScene, rSettings)
        , maNumTiles(nNX,nNY)
    {
        mvTileInfo.resize(6*maNumTiles.x*maNumTiles.y);
        mnFramebuffers[0] = 0;
        mnFramebuffers[1] = 0;
        mnDepthTextures[0] = 0;
        mnDepthTextures[1] = 0;
    }

private:
    virtual void finishTransition() override;
    virtual GLuint makeShader() const override;
    virtual void prepareTransition( sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, OpenGLContext *pContext ) override;
    virtual void displaySlides_( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale, OpenGLContext *pContext ) override;

    GLint mnSlideLocation = -1;
    GLint mnTileInfoLocation = -1;
    GLuint mnTileInfoBuffer = 0u;
    GLint mnShadowLocation = -1;
    std::array<GLuint, 2> mnFramebuffers;
    std::array<GLuint, 2> mnDepthTextures;

    glm::ivec2 maNumTiles;

    std::vector<GLfloat> mvTileInfo;
};

void VortexTransition::finishTransition()
{
    PermTextureTransition::finishTransition();

    CHECK_GL_ERROR();
    glDeleteTextures(2, mnDepthTextures.data());
    mnDepthTextures = {0u, 0u};
    CHECK_GL_ERROR();
    glDeleteFramebuffers(2, mnFramebuffers.data());
    mnFramebuffers = {0u, 0u};
    glDeleteBuffers(1, &mnTileInfoBuffer);
    mnTileInfoBuffer = 0u;
    mnSlideLocation = -1;
    mnTileInfoLocation = -1;
    mnShadowLocation = -1;
    CHECK_GL_ERROR();
}

GLuint VortexTransition::makeShader() const
{
    return OpenGLHelper::LoadShaders( u"vortexVertexShader"_ustr, u"vortexFragmentShader"_ustr, u"vortexGeometryShader"_ustr );
}

glm::mat4 lookAt(const glm::vec3& eye, const glm::vec3& center, const glm::vec3&&nbsp;up) {
    glm::vec3 f = glm::normalize(center - eye);
    glm::vec3 u = glm::normalize(up);
    glm::vec3 s = glm::normalize(glm::cross(f, u));
    u = glm::cross(s, f);

    return glm::mat4(s.x, u.x, -f.x, 0,
                     s.y, u.y, -f.y, 0,
                     s.z, u.z, -f.z, 0,
                     -glm::dot(s, eye), -glm::dot(u, eye), glm::dot(f, eye), 1);
}

void VortexTransition::prepareTransition( sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, OpenGLContext *pContext )
{
    CHECK_GL_ERROR();
    PermTextureTransition::prepareTransition( glLeavingSlideTex, glEnteringSlideTex, pContext );
    CHECK_GL_ERROR();

    mnSlideLocation = glGetUniformLocation(m_nProgramObject, "slide");
    mnTileInfoLocation = glGetAttribLocation(m_nProgramObject, "tileInfo");
    GLint nNumTilesLocation = glGetUniformLocation(m_nProgramObject, "numTiles");
    mnShadowLocation = glGetUniformLocation(m_nProgramObject, "shadow");
    GLint nOrthoProjectionMatrix = glGetUniformLocation(m_nProgramObject, "orthoProjectionMatrix");
    GLint nOrthoViewMatrix = glGetUniformLocation(m_nProgramObject, "orthoViewMatrix");
    GLint location = glGetUniformLocation(m_nProgramObject, "leavingShadowTexture");
    glUniform1i(location, 2);
    location = glGetUniformLocation(m_nProgramObject, "enteringShadowTexture");
    glUniform1i(location, 3);
    CHECK_GL_ERROR();

    glUniform2iv(nNumTilesLocation, 1, glm::value_ptr(maNumTiles));
    CHECK_GL_ERROR();

    glGenBuffers(1, &mnTileInfoBuffer);
    CHECK_GL_ERROR();

    // We store the (x,y) indexes of the tile each vertex belongs to in a float, so they must fit.
    assert(maNumTiles.x < 256);
    assert(maNumTiles.y < 256);

    // Two triangles, i.e. six vertices, per tile
    {
        int n = 0;
        for (int x = 0; x < maNumTiles.x; x++)
        {
            for (int y = 0; y < maNumTiles.y; y++)
            {
                for (int v = 0; v < 6; v++)
                {
                    mvTileInfo[n] = x + (y << 8) + (v << 16);
                    n++;
                }
            }
        }
    }

    glBindBuffer(GL_ARRAY_BUFFER, mnTileInfoBuffer);
    CHECK_GL_ERROR();
    glEnableVertexAttribArray(mnTileInfoLocation);
    CHECK_GL_ERROR();
    glVertexAttribPointer(mnTileInfoLocation, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
    CHECK_GL_ERROR();
    glBufferData(GL_ARRAY_BUFFER, mvTileInfo.size()*sizeof(GLfloat), mvTileInfo.data(), GL_STATIC_DRAW);
    CHECK_GL_ERROR();

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=98 H=93 G=95

[ Dauer der Verarbeitung: 0.26 Sekunden  (vorverarbeitet)  ]