Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/slideshow/source/engine/opengl/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 85 kB image not shown  

Quelle  TransitionImpl.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 <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  ¤

*© 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.