diff options
Diffstat (limited to 'slideshow/source/engine/opengl/TransitionImpl.cxx')
-rw-r--r-- | slideshow/source/engine/opengl/TransitionImpl.cxx | 2292 |
1 files changed, 2292 insertions, 0 deletions
diff --git a/slideshow/source/engine/opengl/TransitionImpl.cxx b/slideshow/source/engine/opengl/TransitionImpl.cxx new file mode 100644 index 000000000..ba43acddc --- /dev/null +++ b/slideshow/source/engine/opengl/TransitionImpl.cxx @@ -0,0 +1,2292 @@ +/* -*- 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(size_t i(0); i != rSceneObjects.size(); ++i) { + rSceneObjects[i]->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, false, sizeof(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, false, sizeof(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, false, sizeof(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(size_t i(0); i != rSceneObjects.size(); ++i) { + rSceneObjects[i]->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( double, double ) +{ +} + +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(size_t i(0); i != rOverallOperations.size(); ++i) + rOverallOperations[i]->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(size_t i(0); i != rSceneObjects.size(); ++i) + rSceneObjects[i]->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 WidthScale, double 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, false, sizeof(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, false, sizeof(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, false, sizeof(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( "reflectionVertexShader", "reflectionFragmentShader" ); +} + +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( "basicVertexShader", "basicFragmentShader" ); +} + +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, true, true, 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), -30, false, -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, true, true, 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, true, true, 0, 1)); + Slide.Operations.push_back(makeRotateAndScaleDepthByWidth(glm::vec3(0,1,0),glm::vec3(0,0,0), 45, true, false, -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; + for( int 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, true, true, 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, true, true, 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), -60, false, -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), -60, false, -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& rSettings) + : OGLTransitionImpl(rScene, rSettings) + {} + +private: + virtual GLuint makeShader() const override; +}; + +GLuint FadeSmoothlyTransition::makeShader() const +{ + return OpenGLHelper::LoadShaders( "basicVertexShader", "fadeFragmentShader" ); +} + +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( "basicVertexShader", "fadeBlackFragmentShader", + 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& 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& rSettings) + : PermTextureTransition(rScene, rSettings) + {} + +private: + virtual GLuint makeShader() const override; +}; + +GLuint StaticNoiseTransition::makeShader() const +{ + return OpenGLHelper::LoadShaders( "basicVertexShader", "staticFragmentShader" ); +} + +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( "basicVertexShader", "dissolveFragmentShader" ); +} + +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( "vortexVertexShader", "vortexFragmentShader", "vortexGeometryShader" ); +} + +glm::mat4 lookAt(const glm::vec3& eye, const glm::vec3& center, const glm::vec3& 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(); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + CHECK_GL_ERROR(); + + double EyePos(10.0); + double const RealF(1.0); + double const RealN(-1.0); + double const RealL(-2.0); + double RealR(2.0); + double const RealB(-2.0); + double RealT(2.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::ortho<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); + glUniformMatrix4fv(nOrthoProjectionMatrix, 1, false, glm::value_ptr(projection)); + + glm::mat4 view = lookAt(glm::vec3(-1, 1, EyePos), glm::vec3(-0.5, 0.5, 0), glm::vec3(0, 1, 0)); + glUniformMatrix4fv(nOrthoViewMatrix, 1, false, glm::value_ptr(view)); + + // Generate the framebuffers and textures for the shadows. + glGenTextures(2, mnDepthTextures.data()); + glGenFramebuffers(2, mnFramebuffers.data()); + + for (int i : {0, 1}) { + glBindTexture(GL_TEXTURE_2D, mnDepthTextures[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 2048, 2048, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindFramebuffer(GL_FRAMEBUFFER, mnFramebuffers[i]); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mnDepthTextures[i], 0); + glDrawBuffer(GL_NONE); // No color buffer is drawn to. + + // Always check that our framebuffer is ok + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + SAL_WARN("slideshow.opengl", "Wrong framebuffer!"); + return; + } + } + + pContext->restoreDefaultFramebuffer(); + glBindTexture(GL_TEXTURE_2D, 0); + + glActiveTexture( GL_TEXTURE2 ); + glBindTexture( GL_TEXTURE_2D, mnDepthTextures[0] ); + glActiveTexture( GL_TEXTURE3 ); + glBindTexture( GL_TEXTURE_2D, mnDepthTextures[1] ); + glActiveTexture( GL_TEXTURE0 ); +} + +void VortexTransition::displaySlides_( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale, OpenGLContext * pContext ) +{ + CHECK_GL_ERROR(); + applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale ); + glUniform1f( m_nTimeLocation, nTime ); + glUniform1f( mnShadowLocation, 1.0 ); + + std::array<GLint, 4> viewport; + glGetIntegerv(GL_VIEWPORT, viewport.data()); + glViewport(0, 0, 2048, 2048); + + glBindFramebuffer(GL_FRAMEBUFFER, mnFramebuffers[0]); + glClear(GL_DEPTH_BUFFER_BIT); + glUniform1f( mnSlideLocation, 0.0 ); + displaySlide( nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale ); + + glBindFramebuffer(GL_FRAMEBUFFER, mnFramebuffers[1]); + glClear(GL_DEPTH_BUFFER_BIT); + glUniform1f( mnSlideLocation, 1.0 ); + displaySlide( nTime, glEnteringSlideTex, getScene().getEnteringSlide(), SlideWidthScale, SlideHeightScale ); + + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + pContext->restoreDefaultFramebuffer(); + glUniform1f( mnShadowLocation, 0.0 ); + glUniform1f( mnSlideLocation, 0.0 ); + displaySlide( nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale ); + glUniform1f( mnSlideLocation, 1.0 ); + displaySlide( nTime, glEnteringSlideTex, getScene().getEnteringSlide(), SlideWidthScale, SlideHeightScale ); + CHECK_GL_ERROR(); +} + +std::shared_ptr<OGLTransitionImpl> +makeVortexTransition(Primitives_t&& rLeavingSlidePrimitives, + Primitives_t&& rEnteringSlidePrimitives, + const TransitionSettings& rSettings, + int NX, + int NY) +{ + return std::make_shared<VortexTransition>(TransitionScene(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives)), + rSettings, + NX, NY); +} + +} + +std::shared_ptr<OGLTransitionImpl> makeVortex() +{ + const int NX = 96, NY = 96; + Primitive Slide; + + for (int x = 0; x < NX; x++) + { + for (int y = 0; y < NY; y++) + { + Slide.pushTriangle (glm::vec2 (fdiv(x,NX),fdiv(y,NY)), glm::vec2 (fdiv(x+1,NX),fdiv(y,NY)), glm::vec2 (fdiv(x,NX),fdiv(y+1,NY))); + Slide.pushTriangle (glm::vec2 (fdiv(x+1,NX),fdiv(y,NY)), glm::vec2 (fdiv(x,NX),fdiv(y+1,NY)), glm::vec2 (fdiv(x+1,NX),fdiv(y+1,NY))); + } + } + Primitives_t aLeavingSlide; + aLeavingSlide.push_back (Slide); + Primitives_t aEnteringSlide; + aEnteringSlide.push_back (Slide); + + TransitionSettings aSettings; + aSettings.mbUseMipMapLeaving = aSettings.mbUseMipMapEntering = false; + aSettings.mnRequiredGLVersion = 3.2f; + + return makeVortexTransition(std::move(aLeavingSlide), std::move(aEnteringSlide), aSettings, NX, NY); +} + +namespace +{ + +class RippleTransition : public OGLTransitionImpl +{ +public: + RippleTransition(const TransitionScene& rScene, const TransitionSettings& rSettings, const glm::vec2& rCenter) + : OGLTransitionImpl(rScene, rSettings), + maCenter(rCenter) + { + } + +private: + virtual GLuint makeShader() const override; + virtual void prepareTransition( sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, OpenGLContext *pContext ) override; + virtual void prepare( double SlideWidth, double SlideHeight ) override; + + glm::vec2 maCenter; + GLint maSlideRatioLocation = -1; +}; + +GLuint RippleTransition::makeShader() const +{ + return OpenGLHelper::LoadShaders( "basicVertexShader", "rippleFragmentShader" ); +} + +void RippleTransition::prepareTransition( sal_Int32, sal_Int32, OpenGLContext* ) +{ + GLint nCenterLocation = glGetUniformLocation(m_nProgramObject, "center"); + CHECK_GL_ERROR(); + + glUniform2fv(nCenterLocation, 1, glm::value_ptr(maCenter)); + CHECK_GL_ERROR(); + + maSlideRatioLocation = glGetUniformLocation(m_nProgramObject, "slideRatio"); + CHECK_GL_ERROR(); +} + +void RippleTransition::prepare( double SlideWidth, double SlideHeight ) +{ + if( maSlideRatioLocation != -1 ) + glUniform1f( maSlideRatioLocation, SlideWidth / SlideHeight ); +} + +std::shared_ptr<OGLTransitionImpl> +makeRippleTransition(Primitives_t&& rLeavingSlidePrimitives, + Primitives_t&& rEnteringSlidePrimitives, + const TransitionSettings& rSettings) +{ + // The center point should be adjustable by the user, but we have no way to do that in the UI + return std::make_shared<RippleTransition>(TransitionScene(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives)), + rSettings, + glm::vec2(0.5, 0.5)); +} + +} + +std::shared_ptr<OGLTransitionImpl> makeRipple() +{ + 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 makeRippleTransition(std::move(aLeavingSlide), std::move(aEnteringSlide), aSettings); +} + +static void createHexagon(Primitive& aHexagon, const int x, const int y, const int NX, const int NY) +{ + if (y % 4 == 0) + { + aHexagon.pushTriangle(vec(x-1, y-1, NX, NY), vec(x, y-2, NX, NY), vec(x, y+0.5, NX, NY)); + aHexagon.pushTriangle(vec(x, y-2, NX, NY), vec(x+1, y-1, NX, NY), vec(x, y+0.5, NX, NY)); + aHexagon.pushTriangle(vec(x+1, y-1, NX, NY), vec(x+1, y, NX, NY), vec(x, y+0.5, NX, NY)); + aHexagon.pushTriangle(vec(x+1, y, NX, NY), vec(x, y+1, NX, NY), vec(x, y+0.5, NX, NY)); + aHexagon.pushTriangle(vec(x, y+1, NX, NY), vec(x-1, y, NX, NY), vec(x, y+0.5, NX, NY)); + aHexagon.pushTriangle(vec(x-1, y, NX, NY), vec(x-1, y-1, NX, NY), vec(x, y+0.5, NX, NY)); + } + else + { + aHexagon.pushTriangle(vec(x-2, y-1, NX, NY), vec(x-1, y-2, NX, NY), vec(x, y+0.5, NX, NY)); + aHexagon.pushTriangle(vec(x-1, y-2, NX, NY), vec(x, y-1, NX, NY), vec(x, y+0.5, NX, NY)); + aHexagon.pushTriangle(vec(x, y-1, NX, NY), vec(x, y, NX, NY), vec(x, y+0.5, NX, NY)); + aHexagon.pushTriangle(vec(x, y, NX, NY), vec(x-1, y+1, NX, NY), vec(x, y+0.5, NX, NY)); + aHexagon.pushTriangle(vec(x-1, y+1, NX, NY), vec(x-2, y, NX, NY), vec(x, y+0.5, NX, NY)); + aHexagon.pushTriangle(vec(x-2, y, NX, NY), vec(x-2, y-1, NX, NY), vec(x, y+0.5, NX, NY)); + } +} + +namespace +{ + +class GlitterTransition : public PermTextureTransition +{ +public: + GlitterTransition(const TransitionScene& rScene, const TransitionSettings& rSettings) + : PermTextureTransition(rScene, rSettings) + { + } + +private: + virtual GLuint makeShader() const override; + virtual void prepareTransition( sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, OpenGLContext *pContext ) override; + virtual void cleanup() override; + + GLuint maBuffer = 0; +}; + +GLuint GlitterTransition::makeShader() const +{ + return OpenGLHelper::LoadShaders( "glitterVertexShader", "glitterFragmentShader" ); +} + +struct ThreeFloats +{ + GLfloat x, y, z; +}; + +void GlitterTransition::prepareTransition( sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, OpenGLContext *pContext ) +{ + CHECK_GL_ERROR(); + PermTextureTransition::prepareTransition( glLeavingSlideTex, glEnteringSlideTex, pContext ); + CHECK_GL_ERROR(); + + GLint nNumTilesLocation = glGetUniformLocation(m_nProgramObject, "numTiles"); + if (nNumTilesLocation != -1) { + glUniform2iv(nNumTilesLocation, 1, glm::value_ptr(glm::ivec2(41, 41 * 4 / 3))); + CHECK_GL_ERROR(); + } + + glGenBuffers(1, &maBuffer); + glBindBuffer(GL_ARRAY_BUFFER, maBuffer); + + // Upload the center of each hexagon. + const Primitive& primitive = getScene().getLeavingSlide()[0]; + std::vector<ThreeFloats> vertices; + for (int i = 2; i < primitive.getVerticesCount(); i += 18) { + const glm::vec3& center = primitive.getVertex(i); + for (int j = 0; j < 18; ++j) + vertices.push_back({center.x, center.y, center.z}); + } + glBufferData(GL_ARRAY_BUFFER, vertices.size() * 3 * sizeof(GLfloat), vertices.data(), GL_STATIC_DRAW); + + GLint location = glGetAttribLocation(m_nProgramObject, "center"); + if (location != -1) { + glEnableVertexAttribArray(location); + glVertexAttribPointer( location, 3, GL_FLOAT, false, 0, nullptr ); + CHECK_GL_ERROR(); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void GlitterTransition::cleanup() +{ + CHECK_GL_ERROR(); + glDeleteBuffers(1, &maBuffer); + CHECK_GL_ERROR(); +} + +std::shared_ptr<OGLTransitionImpl> +makeGlitterTransition(Primitives_t&& rLeavingSlidePrimitives, + Primitives_t&& rEnteringSlidePrimitives, + const TransitionSettings& rSettings) +{ + return std::make_shared<GlitterTransition>(TransitionScene(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives)), + rSettings); +} + +} + +std::shared_ptr<OGLTransitionImpl> makeGlitter() +{ + const int NX = 80; + const int NY = NX * 4 / 3; + + Primitives_t aSlide; + Primitives_t aEmptySlide; + Primitive aHexagon; + + for (int y = 0; y < NY+2; y+=2) + for (int x = 0; x < NX+2; x+=2) + createHexagon(aHexagon, x, y, NX, NY); + + aSlide.push_back(aHexagon); + + return makeGlitterTransition(std::move(aSlide), std::move(aEmptySlide), TransitionSettings()); +} + +namespace +{ + +class HoneycombTransition : public PermTextureTransition +{ +public: + HoneycombTransition(const TransitionScene& rScene, const TransitionSettings& rSettings) + : PermTextureTransition(rScene, rSettings) + { + 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 maHexagonSizeLocation = -1; + GLint maSelectedTextureLocation = -1; + GLint mnShadowLocation = -1; + GLuint mnFramebuffer = 0u; + std::array<GLuint, 2> mnDepthTextures; +}; + +void HoneycombTransition::finishTransition() +{ + PermTextureTransition::finishTransition(); + + CHECK_GL_ERROR(); + glActiveTexture( GL_TEXTURE2 ); + glBindTexture( GL_TEXTURE_2D, 0 ); + glActiveTexture( GL_TEXTURE3 ); + glBindTexture( GL_TEXTURE_2D, 0 ); + glActiveTexture( GL_TEXTURE0 ); + CHECK_GL_ERROR(); + glDeleteTextures(2, mnDepthTextures.data()); + mnDepthTextures = {0u, 0u}; + CHECK_GL_ERROR(); + glDeleteFramebuffers(1, &mnFramebuffer); + mnFramebuffer = 0u; + CHECK_GL_ERROR(); +} + +GLuint HoneycombTransition::makeShader() const +{ + return OpenGLHelper::LoadShaders( "honeycombVertexShader", "honeycombFragmentShader", "honeycombGeometryShader" ); +} + +void HoneycombTransition::prepareTransition( sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, OpenGLContext *pContext ) +{ + CHECK_GL_ERROR(); + PermTextureTransition::prepareTransition( glLeavingSlideTex, glEnteringSlideTex, pContext ); + + CHECK_GL_ERROR(); + maHexagonSizeLocation = glGetUniformLocation(m_nProgramObject, "hexagonSize"); + maSelectedTextureLocation = glGetUniformLocation( m_nProgramObject, "selectedTexture" ); + mnShadowLocation = glGetUniformLocation(m_nProgramObject, "shadow"); + GLint nOrthoProjectionMatrix = glGetUniformLocation(m_nProgramObject, "orthoProjectionMatrix"); + GLint nOrthoViewMatrix = glGetUniformLocation(m_nProgramObject, "orthoViewMatrix"); + GLint location = glGetUniformLocation(m_nProgramObject, "colorShadowTexture"); + glUniform1i(location, 2); + location = glGetUniformLocation(m_nProgramObject, "depthShadowTexture"); + glUniform1i(location, 3); + CHECK_GL_ERROR(); + + // We want to see the entering slide behind the leaving one. + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + CHECK_GL_ERROR(); + + double EyePos(10.0); + double const RealF(1.0); + double const RealN(-1.0); + double const RealL(-4.0); + double RealR(4.0); + double const RealB(-4.0); + double RealT(4.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::ortho<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); + glUniformMatrix4fv(nOrthoProjectionMatrix, 1, false, glm::value_ptr(projection)); + + glm::mat4 view = lookAt(glm::vec3(0, 0, EyePos), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); + glUniformMatrix4fv(nOrthoViewMatrix, 1, false, glm::value_ptr(view)); + + // Generate the framebuffer and textures for the shadows. + glGenTextures(2, mnDepthTextures.data()); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, mnDepthTextures[0]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2048, 2048, 0, GL_RGBA, GL_FLOAT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, mnDepthTextures[1]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 2048, 2048, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glActiveTexture(GL_TEXTURE0); + glGenFramebuffers(1, &mnFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, mnFramebuffer); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mnDepthTextures[0], 0); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mnDepthTextures[1], 0); + + // Always check that our framebuffer is ok + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + SAL_WARN("slideshow.opengl", "Wrong framebuffer!"); + return; + } + + pContext->restoreDefaultFramebuffer(); +} + +void HoneycombTransition::displaySlides_( double nTime, sal_Int32 glLeavingSlideTex, sal_Int32 glEnteringSlideTex, + double SlideWidthScale, double SlideHeightScale, OpenGLContext *pContext ) +{ + CHECK_GL_ERROR(); + applyOverallOperations(nTime, SlideWidthScale, SlideHeightScale); + glUniform1f(m_nTimeLocation, nTime); + glUniform1f(mnShadowLocation, 1.0); + CHECK_GL_ERROR(); + + const float borderSize = 0.15f; + + std::array<GLint, 4> viewport; + glGetIntegerv(GL_VIEWPORT, viewport.data()); + glViewport(0, 0, 2048, 2048); + glBindFramebuffer(GL_FRAMEBUFFER, mnFramebuffer); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glUniform1f(mnShadowLocation, 1.0); + glUniform1f(maSelectedTextureLocation, 1.0); + glUniform1f(maHexagonSizeLocation, 1.0f - borderSize); + displaySlide(nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale); + glUniform1f(maHexagonSizeLocation, 1.0f + borderSize); + displaySlide(nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale); + + // The back (entering) slide needs to be drawn before the front (leaving) one in order for blending to work. + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + pContext->restoreDefaultFramebuffer(); + glUniform1f(mnShadowLocation, 0.0); + glUniform1f(maSelectedTextureLocation, 0.0); + glUniform1f(maHexagonSizeLocation, 1.0f - borderSize); + displaySlide(nTime, glEnteringSlideTex, getScene().getEnteringSlide(), SlideWidthScale, SlideHeightScale); + glUniform1f(maHexagonSizeLocation, 1.0f + borderSize); + displaySlide(nTime, glEnteringSlideTex, getScene().getEnteringSlide(), SlideWidthScale, SlideHeightScale); + glUniform1f(maSelectedTextureLocation, 1.0); + glUniform1f(maHexagonSizeLocation, 1.0f - borderSize); + displaySlide(nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale); + glUniform1f(maHexagonSizeLocation, 1.0f + borderSize); + displaySlide(nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale); + CHECK_GL_ERROR(); +} + +std::shared_ptr<OGLTransitionImpl> +makeHoneycombTransition(Primitives_t&& rLeavingSlidePrimitives, + Primitives_t&& rEnteringSlidePrimitives, + const TransitionSettings& rSettings) +{ + // The center point should be adjustable by the user, but we have no way to do that in the UI + return std::make_shared<HoneycombTransition>(TransitionScene(std::move(rLeavingSlidePrimitives), std::move(rEnteringSlidePrimitives)), + rSettings); +} + +} + +std::shared_ptr<OGLTransitionImpl> makeHoneycomb() +{ + const int NX = 21; + const int NY = 21; + + TransitionSettings aSettings; + aSettings.mnRequiredGLVersion = 3.2f; + + Primitives_t aSlide; + Primitive aHexagon; + for (int y = 0; y < NY+2; y+=2) + for (int x = 0; x < NX+2; x+=2) + aHexagon.pushTriangle(glm::vec2((y % 4) ? fdiv(x, NX) : fdiv(x + 1, NX), fdiv(y, NY)), glm::vec2(1, 0), glm::vec2(0, 0)); + aSlide.push_back(aHexagon); + + return makeHoneycombTransition(std::vector(aSlide), std::vector(aSlide), aSettings); +} + +std::shared_ptr<OGLTransitionImpl> makeNewsflash() +{ + 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)); + Slide.Operations.push_back(makeSRotate(glm::vec3(0,0,1),glm::vec3(0,0,0),3000,true,0,0.5)); + Slide.Operations.push_back(makeSScale(glm::vec3(0.01,0.01,0.01),glm::vec3(0,0,0),true,0,0.5)); + Slide.Operations.push_back(makeSTranslate(glm::vec3(-10000, 0, 0),false, 0.5, 2)); + Primitives_t aLeavingSlide; + aLeavingSlide.push_back(Slide); + + Slide.Operations.clear(); + Slide.Operations.push_back(makeSRotate(glm::vec3(0,0,1),glm::vec3(0,0,0),-3000,true,0.5,1)); + Slide.Operations.push_back(makeSTranslate(glm::vec3(-100, 0, 0),false, -1, 1)); + Slide.Operations.push_back(makeSTranslate(glm::vec3(100, 0, 0),false, 0.5, 1)); + Slide.Operations.push_back(makeSScale(glm::vec3(0.01,0.01,0.01),glm::vec3(0,0,0),false,-1,1)); + Slide.Operations.push_back(makeSScale(glm::vec3(100,100,100),glm::vec3(0,0,0),true,0.5,1)); + Primitives_t aEnteringSlide; + aEnteringSlide.push_back(Slide); + + Operations_t aOverallOperations; + aOverallOperations.push_back(makeSRotate(glm::vec3(0,0,1),glm::vec3(0.2,0.2,0),1080,true,0,1)); + + return makeSimpleTransition(std::move(aLeavingSlide), std::move(aEnteringSlide), std::move(aOverallOperations)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |