/* -*- 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) / (C
lipR - 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 .0 f + glm::vec2( 0 .5 , 0 .5 ) , Radius * unScaledTexCoords[ Point ] / 2 .0 f + glm::vec2( 0 .5 , 0 .5 ) );
LeavingSlide.pushTriangle( glm::vec2( 0 .5 , 0 .5 ) , Radius * unScaledTexCoords[ Point + 1 ] / 2 .0 f + glm::vec2( 0 .5 , 0 .5 ) , Radius * unScaledTexCoords[ Point ] / 2 .0 f + glm::vec2( 0 .5 , 0 .5 ) );
}
EnteringSlide.pushTriangle( glm::vec2(0 .5 ,0 .5 ) , Radius * unScaledTexCoords[ 0 ] / 2 .0 f + glm::vec2( 0 .5 , 0 .5 ) , Radius * unScaledTexCoords[ nPointsOnCircles - 1 ] / 2 .0 f + glm::vec2( 0 .5 , 0 .5 ) );
LeavingSlide.pushTriangle( glm::vec2(0 .5 ,0 .5 ) , Radius*unScaledTexCoords[0 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , Radius*unScaledTexCoords[nPointsOnCircles - 1 ]/2 .0 f + 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 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side + 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
EnteringSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side + 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , Radius*unScaledTexCoords[Side + 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side + 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side + 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , Radius*unScaledTexCoords[Side + 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
}
EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[0 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[0 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , Radius*unScaledTexCoords[0 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[0 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[0 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , Radius*unScaledTexCoords[0 ]/2 .0 f + 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 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side + 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side + 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , clamp(Radius*unScaledTexCoords[Side + 1 ])/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side + 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[Side + 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , clamp(Radius*unScaledTexCoords[Side + 1 ])/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
}
EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1 ])/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[0 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1 ])/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[0 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , clamp(Radius*unScaledTexCoords[0 ])/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1 ])/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[0 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) );
LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1 ])/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , LastRadius*unScaledTexCoords[0 ]/2 .0 f + glm::vec2(0 .5 ,0 .5 ) , clamp(Radius*unScaledTexCoords[0 ])/2 .0 f + 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 .0 f , 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 .0 f , -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 .0 f, 180 , true , x11.x * x11.y / 2 .0 f , ((x22.x * x22.y) + 1 .0 f) / 2 .0 f));
aLeavingSlide.push_back(aTile);
aTile.Operations.push_back(makeSRotate( glm::vec3(0 , 1 , 0 ), (aTile.getVertex(1 ) + aTile.getVertex(3 )) / 2 .0 f, -180 , false , x11.x * x11.y / 2 .0 f , ((x22.x * x22.y) + 1 .0 f) / 2 .0 f));
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]) & 0 xff];
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 = 0 u;
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 = {0 u, 0 u};
CHECK_GL_ERROR();
glDeleteFramebuffers(2 , mnFramebuffers.data());
mnFramebuffers = {0 u, 0 u};
glDeleteBuffers(1 , &mnTileInfoBuffer);
mnTileInfoBuffer = 0 u;
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 .2 f;
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 = 0 u;
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 = {0 u, 0 u};
CHECK_GL_ERROR();
glDeleteFramebuffers(1 , &mnFramebuffer);
mnFramebuffer = 0 u;
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 .15 f;
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 .0 f - borderSize);
displaySlide(nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale);
glUniform1f(maHexagonSizeLocation, 1 .0 f + 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 .0 f - borderSize);
displaySlide(nTime, glEnteringSlideTex, getScene().getEnteringSlide(), SlideWidthScale, SlideHeightScale);
glUniform1f(maHexagonSizeLocation, 1 .0 f + borderSize);
displaySlide(nTime, glEnteringSlideTex, getScene().getEnteringSlide(), SlideWidthScale, SlideHeightScale);
glUniform1f(maSelectedTextureLocation, 1 .0 );
glUniform1f(maHexagonSizeLocation, 1 .0 f - borderSize);
displaySlide(nTime, glLeavingSlideTex, getScene().getLeavingSlide(), SlideWidthScale, SlideHeightScale);
glUniform1f(maHexagonSizeLocation, 1 .0 f + 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 .2 f;
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: */
Messung V0.5 in Prozent C=92 H=97 G=94
¤ Dauer der Verarbeitung: 0.27 Sekunden
(vorverarbeitet am 2026-06-06)
¤
*© Formatika GbR, Deutschland