1
0
Fork 0
libreoffice/slideshow/source/engine/opengl/TransitionImpl.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

2286 lines
86 KiB
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, 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(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( 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(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 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( 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, 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( 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& 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( 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& 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( u"basicVertexShader"_ustr, u"rippleFragmentShader"_ustr );
}
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( u"glitterVertexShader"_ustr, u"glitterFragmentShader"_ustr );
}
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();
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( u"honeycombVertexShader"_ustr, u"honeycombFragmentShader"_ustr, u"honeycombGeometryShader"_ustr );
}
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: */