[libkwineffects] Add support for shaders in AnimationEffect
The animate and set calls are extended for an optional GLShader* to allow specifying a custom shader to use during the animation. To properly support rendering a complete window in the effect the AnimationEffect gets based on the DeformEffect. If a shader is used during the animation the window gets redirected. For the animation with shaders two new enum values are added to the AnimationType enum: * Shader * ShaderUniform The Shader animation type is for specifying that the animation uses a shader. During the animation a uniform "animationProgress" is set on the shader. The ShaderUniform animation type behaves exactly like the Shader type, but also animates a user provided uniform. The meta data of the animation is interpreted as a uniform location for a float uniform and during the animation this uniform is updated with the interpolated animation data.
This commit is contained in:
parent
7dddf3055b
commit
47b330ea23
5 changed files with 55 additions and 12 deletions
|
@ -72,7 +72,7 @@ AniData::AniData()
|
||||||
AniData::AniData(AnimationEffect::Attribute a, int meta_, const FPx2 &to_,
|
AniData::AniData(AnimationEffect::Attribute a, int meta_, const FPx2 &to_,
|
||||||
int delay, const FPx2 &from_, bool waitAtSource_,
|
int delay, const FPx2 &from_, bool waitAtSource_,
|
||||||
FullScreenEffectLockPtr fullScreenEffectLock_, bool keepAlive,
|
FullScreenEffectLockPtr fullScreenEffectLock_, bool keepAlive,
|
||||||
PreviousWindowPixmapLockPtr previousWindowPixmapLock_)
|
PreviousWindowPixmapLockPtr previousWindowPixmapLock_, GLShader *shader)
|
||||||
: attribute(a)
|
: attribute(a)
|
||||||
, from(from_)
|
, from(from_)
|
||||||
, to(to_)
|
, to(to_)
|
||||||
|
@ -84,6 +84,7 @@ AniData::AniData(AnimationEffect::Attribute a, int meta_, const FPx2 &to_,
|
||||||
, keepAlive(keepAlive)
|
, keepAlive(keepAlive)
|
||||||
, previousWindowPixmapLock(std::move(previousWindowPixmapLock_))
|
, previousWindowPixmapLock(std::move(previousWindowPixmapLock_))
|
||||||
, lastPresentTime(std::chrono::milliseconds::zero())
|
, lastPresentTime(std::chrono::milliseconds::zero())
|
||||||
|
, shader(shader)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ public:
|
||||||
AniData(AnimationEffect::Attribute a, int meta, const FPx2 &to,
|
AniData(AnimationEffect::Attribute a, int meta, const FPx2 &to,
|
||||||
int delay, const FPx2 &from, bool waitAtSource,
|
int delay, const FPx2 &from, bool waitAtSource,
|
||||||
FullScreenEffectLockPtr = FullScreenEffectLockPtr(),
|
FullScreenEffectLockPtr = FullScreenEffectLockPtr(),
|
||||||
bool keepAlive = true, PreviousWindowPixmapLockPtr previousWindowPixmapLock = {});
|
bool keepAlive = true, PreviousWindowPixmapLockPtr previousWindowPixmapLock = {}, GLShader *shader = nullptr);
|
||||||
|
|
||||||
bool isActive() const;
|
bool isActive() const;
|
||||||
|
|
||||||
|
@ -94,6 +94,7 @@ public:
|
||||||
PreviousWindowPixmapLockPtr previousWindowPixmapLock;
|
PreviousWindowPixmapLockPtr previousWindowPixmapLock;
|
||||||
AnimationEffect::TerminationFlags terminationFlags;
|
AnimationEffect::TerminationFlags terminationFlags;
|
||||||
std::chrono::milliseconds lastPresentTime;
|
std::chrono::milliseconds lastPresentTime;
|
||||||
|
GLShader *shader{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "kwinanimationeffect.h"
|
#include "kwinanimationeffect.h"
|
||||||
|
#include "kwinglutils.h"
|
||||||
#include "anidata_p.h"
|
#include "anidata_p.h"
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
@ -207,7 +208,7 @@ void AnimationEffect::validate(Attribute a, uint &meta, FPx2 *from, FPx2 *to, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 AnimationEffect::p_animate(EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, const QEasingCurve &curve, int delay, FPx2 from, bool keepAtTarget, bool fullScreenEffect, bool keepAlive)
|
quint64 AnimationEffect::p_animate(EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, const QEasingCurve &curve, int delay, FPx2 from, bool keepAtTarget, bool fullScreenEffect, bool keepAlive, GLShader *shader)
|
||||||
{
|
{
|
||||||
const bool waitAtSource = from.isValid();
|
const bool waitAtSource = from.isValid();
|
||||||
validate(a, meta, &from, &to, w);
|
validate(a, meta, &from, &to, w);
|
||||||
|
@ -249,7 +250,8 @@ quint64 AnimationEffect::p_animate(EffectWindow *w, Attribute a, uint meta, int
|
||||||
waitAtSource, // Whether the animation should be kept at source
|
waitAtSource, // Whether the animation should be kept at source
|
||||||
fullscreen, // Full screen effect lock
|
fullscreen, // Full screen effect lock
|
||||||
keepAlive, // Keep alive flag
|
keepAlive, // Keep alive flag
|
||||||
previousPixmap // Previous window pixmap lock
|
previousPixmap, // Previous window pixmap lock
|
||||||
|
shader
|
||||||
));
|
));
|
||||||
|
|
||||||
const quint64 ret_id = ++d->m_animCounter;
|
const quint64 ret_id = ++d->m_animCounter;
|
||||||
|
@ -280,6 +282,9 @@ quint64 AnimationEffect::p_animate(EffectWindow *w, Attribute a, uint meta, int
|
||||||
} else {
|
} else {
|
||||||
triggerRepaint();
|
triggerRepaint();
|
||||||
}
|
}
|
||||||
|
if (shader) {
|
||||||
|
DeformEffect::redirect(w);
|
||||||
|
}
|
||||||
return ret_id;
|
return ret_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,6 +410,9 @@ bool AnimationEffect::cancel(quint64 animationId)
|
||||||
for (AniMap::iterator entry = d->m_animations.begin(), mapEnd = d->m_animations.end(); entry != mapEnd; ++entry) {
|
for (AniMap::iterator entry = d->m_animations.begin(), mapEnd = d->m_animations.end(); entry != mapEnd; ++entry) {
|
||||||
for (QList<AniData>::iterator anim = entry->first.begin(), animEnd = entry->first.end(); anim != animEnd; ++anim) {
|
for (QList<AniData>::iterator anim = entry->first.begin(), animEnd = entry->first.end(); anim != animEnd; ++anim) {
|
||||||
if (anim->id == animationId) {
|
if (anim->id == animationId) {
|
||||||
|
if (anim->shader && std::none_of(entry->first.begin(), entry->first.end(), [animationId] (const auto &anim) { return anim.id != animationId && anim.shader; })) {
|
||||||
|
unredirect(entry.key());
|
||||||
|
}
|
||||||
entry->first.erase(anim); // remove the animation
|
entry->first.erase(anim); // remove the animation
|
||||||
if (entry->first.isEmpty()) { // no other animations on the window, release it.
|
if (entry->first.isEmpty()) { // no other animations on the window, release it.
|
||||||
d->m_animations.erase(entry);
|
d->m_animations.erase(entry);
|
||||||
|
@ -642,11 +650,27 @@ void AnimationEffect::paintWindow(EffectWindow *w, int mask, QRegion region, Win
|
||||||
case CrossFadePrevious:
|
case CrossFadePrevious:
|
||||||
data.setCrossFadeProgress(progress(*anim));
|
data.setCrossFadeProgress(progress(*anim));
|
||||||
break;
|
break;
|
||||||
|
case Shader:
|
||||||
|
if (anim->shader && anim->shader->isValid()) {
|
||||||
|
ShaderBinder binder{anim->shader};
|
||||||
|
anim->shader->setUniform("animationProgress", progress(*anim));
|
||||||
|
setShader(w, anim->shader);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ShaderUniform:
|
||||||
|
if (anim->shader && anim->shader->isValid()) {
|
||||||
|
ShaderBinder binder{anim->shader};
|
||||||
|
anim->shader->setUniform("animationProgress", progress(*anim));
|
||||||
|
anim->shader->setUniform(anim->meta, interpolated(*anim));
|
||||||
|
setShader(w, anim->shader);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
effects->paintWindow(w, mask, region, data);
|
effects->paintWindow(w, mask, region, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,6 +691,9 @@ void AnimationEffect::postPaintScreen()
|
||||||
}
|
}
|
||||||
EffectWindow *window = entry.key();
|
EffectWindow *window = entry.key();
|
||||||
d->m_justEndedAnimation = anim->id;
|
d->m_justEndedAnimation = anim->id;
|
||||||
|
if (anim->shader && std::none_of(entry->first.begin(), entry->first.end(), [anim] (const auto &other) { return anim->id != other.id && other.shader; })) {
|
||||||
|
unredirect(window);
|
||||||
|
}
|
||||||
animationEnded(window, anim->attribute, anim->meta);
|
animationEnded(window, anim->attribute, anim->meta);
|
||||||
d->m_justEndedAnimation = 0;
|
d->m_justEndedAnimation = 0;
|
||||||
// NOTICE animationEnded is an external call and might have called "::animate"
|
// NOTICE animationEnded is an external call and might have called "::animate"
|
||||||
|
@ -854,6 +881,8 @@ void AnimationEffect::updateLayerRepaints()
|
||||||
case Brightness:
|
case Brightness:
|
||||||
case Saturation:
|
case Saturation:
|
||||||
case CrossFadePrevious:
|
case CrossFadePrevious:
|
||||||
|
case Shader:
|
||||||
|
case ShaderUniform:
|
||||||
createRegion = true;
|
createRegion = true;
|
||||||
break;
|
break;
|
||||||
case Rotation:
|
case Rotation:
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include <QEasingCurve>
|
#include <QEasingCurve>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
#include <kwineffects.h>
|
#include <kwindeformeffect.h>
|
||||||
#include <kwineffects_export.h>
|
#include <kwineffects_export.h>
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
|
@ -191,7 +191,7 @@ class AnimationEffectPrivate;
|
||||||
*
|
*
|
||||||
* @since 4.8
|
* @since 4.8
|
||||||
*/
|
*/
|
||||||
class KWINEFFECTS_EXPORT AnimationEffect : public Effect
|
class KWINEFFECTS_EXPORT AnimationEffect : public DeformEffect
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -217,6 +217,16 @@ public:
|
||||||
Clip,
|
Clip,
|
||||||
Generic,
|
Generic,
|
||||||
CrossFadePrevious,
|
CrossFadePrevious,
|
||||||
|
/**
|
||||||
|
* Performs an animation with a provided shader.
|
||||||
|
* The float uniform @c animationProgress is set to the current progress of the animation.
|
||||||
|
**/
|
||||||
|
Shader,
|
||||||
|
/**
|
||||||
|
* Like Shader, but additionally allows to animate a float uniform passed to the shader.
|
||||||
|
* The uniform location must be provided as metadata.
|
||||||
|
**/
|
||||||
|
ShaderUniform,
|
||||||
NonFloatBase = Position
|
NonFloatBase = Position
|
||||||
};
|
};
|
||||||
Q_ENUM(Attribute)
|
Q_ENUM(Attribute)
|
||||||
|
@ -360,12 +370,13 @@ protected:
|
||||||
* @param fullScreen Sets this effect as the active full screen effect for the
|
* @param fullScreen Sets this effect as the active full screen effect for the
|
||||||
* duration of the animation.
|
* duration of the animation.
|
||||||
* @param keepAlive Whether closed windows should be kept alive during animation.
|
* @param keepAlive Whether closed windows should be kept alive during animation.
|
||||||
|
* @param shader Optional shader to use to render the window.
|
||||||
* @returns An ID that you can use to cancel a running animation.
|
* @returns An ID that you can use to cancel a running animation.
|
||||||
* @since 4.8
|
* @since 4.8
|
||||||
*/
|
*/
|
||||||
quint64 animate(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve = QEasingCurve(), int delay = 0, const FPx2 &from = FPx2(), bool fullScreen = false, bool keepAlive = true)
|
quint64 animate(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve = QEasingCurve(), int delay = 0, const FPx2 &from = FPx2(), bool fullScreen = false, bool keepAlive = true, GLShader *shader = nullptr)
|
||||||
{
|
{
|
||||||
return p_animate(w, a, meta, ms, to, curve, delay, from, false, fullScreen, keepAlive);
|
return p_animate(w, a, meta, ms, to, curve, delay, from, false, fullScreen, keepAlive, shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -392,12 +403,13 @@ protected:
|
||||||
* @param fullScreen Sets this effect as the active full screen effect for the
|
* @param fullScreen Sets this effect as the active full screen effect for the
|
||||||
* duration of the animation.
|
* duration of the animation.
|
||||||
* @param keepAlive Whether closed windows should be kept alive during animation.
|
* @param keepAlive Whether closed windows should be kept alive during animation.
|
||||||
|
* @param shader Optional shader to use to render the window.
|
||||||
* @returns An ID that you need to use to cancel this manipulation.
|
* @returns An ID that you need to use to cancel this manipulation.
|
||||||
* @since 4.11
|
* @since 4.11
|
||||||
*/
|
*/
|
||||||
quint64 set(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve = QEasingCurve(), int delay = 0, const FPx2 &from = FPx2(), bool fullScreen = false, bool keepAlive = true)
|
quint64 set(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve = QEasingCurve(), int delay = 0, const FPx2 &from = FPx2(), bool fullScreen = false, bool keepAlive = true, GLShader *shader = nullptr)
|
||||||
{
|
{
|
||||||
return p_animate(w, a, meta, ms, to, curve, delay, from, true, fullScreen, keepAlive);
|
return p_animate(w, a, meta, ms, to, curve, delay, from, true, fullScreen, keepAlive, shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -506,7 +518,7 @@ protected:
|
||||||
AniMap state() const;
|
AniMap state() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
quint64 p_animate(EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, const QEasingCurve &curve, int delay, FPx2 from, bool keepAtTarget, bool fullScreenEffect, bool keepAlive);
|
quint64 p_animate(EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, const QEasingCurve &curve, int delay, FPx2 from, bool keepAtTarget, bool fullScreenEffect, bool keepAlive, GLShader *shader);
|
||||||
QRect clipRect(const QRect &windowRect, const AniData &) const;
|
QRect clipRect(const QRect &windowRect, const AniData &) const;
|
||||||
float interpolated(const AniData &, int i = 0) const;
|
float interpolated(const AniData &, int i = 0) const;
|
||||||
float progress(const AniData &) const;
|
float progress(const AniData &) const;
|
||||||
|
|
|
@ -180,7 +180,7 @@ X-KDE-Library=kwin4_effect_cooleffect
|
||||||
|
|
||||||
#define KWIN_EFFECT_API_MAKE_VERSION(major, minor) ((major) << 8 | (minor))
|
#define KWIN_EFFECT_API_MAKE_VERSION(major, minor) ((major) << 8 | (minor))
|
||||||
#define KWIN_EFFECT_API_VERSION_MAJOR 0
|
#define KWIN_EFFECT_API_VERSION_MAJOR 0
|
||||||
#define KWIN_EFFECT_API_VERSION_MINOR 233
|
#define KWIN_EFFECT_API_VERSION_MINOR 234
|
||||||
#define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \
|
#define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \
|
||||||
KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR)
|
KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue