using texture for blurring
This commit is contained in:
parent
c4000eb44b
commit
3e685a21d7
|
|
@ -0,0 +1,77 @@
|
|||
#include "BlurredBox.h"
|
||||
#include "BlurredBoxSkinlet.h"
|
||||
#include "BlurredBoxTextureProvider.h"
|
||||
|
||||
#include <QQuickWindow>
|
||||
#include <limits>
|
||||
|
||||
QSK_SUBCONTROL( BlurredBox, Panel )
|
||||
|
||||
class BlurredBoxSkinlet;
|
||||
|
||||
BlurredBox::BlurredBox( QQuickItem* parentItem )
|
||||
: QskBox( parentItem )
|
||||
{
|
||||
setPolishOnResize( true );
|
||||
}
|
||||
|
||||
BlurredBox::~BlurredBox() = default;
|
||||
|
||||
void BlurredBox::geometryChangeEvent( QskGeometryChangeEvent* e )
|
||||
{
|
||||
Inherited::geometryChangeEvent( e );
|
||||
update();
|
||||
}
|
||||
|
||||
float BlurredBox::blurDirections() const
|
||||
{
|
||||
return m_blurDirections;
|
||||
}
|
||||
|
||||
void BlurredBox::setBlurDirections( float newBlurDirections )
|
||||
{
|
||||
if ( qFuzzyCompare( m_blurDirections, newBlurDirections ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_blurDirections = std::max(newBlurDirections, std::numeric_limits<float>::min());
|
||||
update();
|
||||
Q_EMIT blurDirectionsChanged( m_blurDirections );
|
||||
}
|
||||
|
||||
float BlurredBox::blurQuality() const
|
||||
{
|
||||
return m_blurQuality;
|
||||
}
|
||||
|
||||
void BlurredBox::setBlurQuality( float newBlurQuality )
|
||||
{
|
||||
if ( qFuzzyCompare( m_blurQuality, newBlurQuality ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_blurQuality = std::max(newBlurQuality, std::numeric_limits<float>::min());
|
||||
update();
|
||||
Q_EMIT blurQualityChanged( m_blurQuality );
|
||||
}
|
||||
|
||||
float BlurredBox::blurSize() const
|
||||
{
|
||||
return m_blurSize;
|
||||
}
|
||||
|
||||
void BlurredBox::setBlurSize( float newBlurSize )
|
||||
{
|
||||
if ( qFuzzyCompare( m_blurSize, newBlurSize ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_blurSize = newBlurSize;
|
||||
update();
|
||||
Q_EMIT blurSizeChanged( m_blurSize );
|
||||
}
|
||||
|
||||
#include "moc_BlurredBox.cpp"
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <QskBox.h>
|
||||
|
||||
class QskGradient;
|
||||
class QSGTexture;
|
||||
|
||||
class BlurredBox final : public QskBox
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( float blurDirections READ blurDirections WRITE setBlurDirections NOTIFY
|
||||
blurDirectionsChanged )
|
||||
Q_PROPERTY( float blurQuality READ blurQuality WRITE setBlurQuality NOTIFY blurQualityChanged )
|
||||
Q_PROPERTY( float blurSize READ blurSize WRITE setBlurSize NOTIFY blurSizeChanged )
|
||||
using Inherited = QskBox;
|
||||
|
||||
public:
|
||||
QSK_SUBCONTROLS( Panel )
|
||||
|
||||
BlurredBox( QQuickItem* parent = nullptr );
|
||||
~BlurredBox() override;
|
||||
|
||||
void geometryChangeEvent( QskGeometryChangeEvent* ) override;
|
||||
|
||||
float blurDirections() const;
|
||||
void setBlurDirections( float newBlurDirections );
|
||||
|
||||
float blurQuality() const;
|
||||
void setBlurQuality( float newBlurQuality );
|
||||
|
||||
float blurSize() const;
|
||||
void setBlurSize( float newBlurSize );
|
||||
|
||||
Q_SIGNALS:
|
||||
void blurDirectionsChanged( float );
|
||||
void blurQualityChanged( float );
|
||||
void blurSizeChanged( float );
|
||||
|
||||
private:
|
||||
float m_blurDirections = 32.0;
|
||||
float m_blurQuality = 8.0;
|
||||
float m_blurSize = 8.0;
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#include "BlurredBoxMaterial.h"
|
||||
#include "BlurredBoxMaterialShader.h"
|
||||
|
||||
BlurredBoxMaterial::BlurredBoxMaterial()
|
||||
{
|
||||
setFlag( QSGMaterial::Blending, true );
|
||||
}
|
||||
|
||||
QSGMaterialShader* BlurredBoxMaterial::createShader() const
|
||||
{
|
||||
return new BlurredBoxMaterialShader();
|
||||
}
|
||||
|
||||
QSGMaterialType* BlurredBoxMaterial::type() const
|
||||
{
|
||||
static QSGMaterialType staticType;
|
||||
return &staticType;
|
||||
}
|
||||
|
||||
int BlurredBoxMaterial::compare( const QSGMaterial* other ) const
|
||||
{
|
||||
const auto* const material = dynamic_cast< const BlurredBoxMaterial* >( other );
|
||||
|
||||
if ( material->m_rectCornerRadii != m_rectCornerRadii ||
|
||||
material->m_rectAspect != m_rectAspect ||
|
||||
material->m_opacity != m_opacity ||
|
||||
material->m_blurDirections != m_blurDirections ||
|
||||
material->m_blurQuality != m_blurQuality ||
|
||||
material->m_blurRadius != m_blurRadius ||
|
||||
material->m_edgeSoftness != m_edgeSoftness ||
|
||||
material->m_texture.get() != m_texture.get())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return QSGMaterial::compare( other );
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <QSGMaterial>
|
||||
#include <QSGTexture>
|
||||
#include <memory>
|
||||
|
||||
class BlurredBoxMaterial final : public QSGMaterial
|
||||
{
|
||||
public:
|
||||
BlurredBoxMaterial();
|
||||
|
||||
QSGMaterialShader* createShader() const override;
|
||||
QSGMaterialType* type() const override;
|
||||
|
||||
int compare( const QSGMaterial* other ) const override;
|
||||
|
||||
QVector4D m_rectCornerRadii{ 0, 0, 0, 0 };
|
||||
QVector2D m_rectAspect {1,1};
|
||||
float m_opacity = 1.0;
|
||||
float m_blurDirections = 32.0;
|
||||
float m_blurQuality = 8.0;
|
||||
QVector2D m_blurRadius = {1.0,1.0};
|
||||
float m_edgeSoftness = 1.0;
|
||||
std::unique_ptr<QSGTexture> m_texture;
|
||||
};
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
#include <QOpenGLContext>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QImage>
|
||||
#include <QSGTexture>
|
||||
|
||||
#include "BlurredBoxMaterialShader.h"
|
||||
#include "BlurredBoxMaterial.h"
|
||||
|
||||
BlurredBoxMaterialShader::BlurredBoxMaterialShader()
|
||||
{
|
||||
setShaderSourceFile( QOpenGLShader::Vertex, ":/shaders/blurredbox.vert" );
|
||||
setShaderSourceFile( QOpenGLShader::Fragment, ":/shaders/blurredbox.frag" );
|
||||
}
|
||||
|
||||
const char* const* BlurredBoxMaterialShader::attributeNames() const
|
||||
{
|
||||
static char const* const names[] = { "in_vertex", "in_coord", nullptr };
|
||||
return names;
|
||||
}
|
||||
|
||||
void BlurredBoxMaterialShader::initialize()
|
||||
{
|
||||
QSGMaterialShader::initialize();
|
||||
|
||||
auto p = program();
|
||||
|
||||
m_matrixId = p->uniformLocation( "matrix" );
|
||||
m_rectOpacityId = p->uniformLocation( "rectOpacity" );
|
||||
m_rectCornerRadiiId = p->uniformLocation( "rectCornerRadii" );
|
||||
m_rectAspect = p->uniformLocation( "rectAspect" );
|
||||
m_blurDirectionsId = p->uniformLocation( "blurDirections" );
|
||||
m_blurQualityId = p->uniformLocation( "blurQuality" );
|
||||
m_blurRadiusId = p->uniformLocation( "blurRadius" );
|
||||
m_textureId = p->uniformLocation( "txr" );
|
||||
m_edgeSoftnessId = p->uniformLocation( "edgeSoftness" );
|
||||
}
|
||||
|
||||
void BlurredBoxMaterialShader::updateState(
|
||||
const RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial )
|
||||
{
|
||||
auto p = program();
|
||||
|
||||
if ( state.isMatrixDirty() )
|
||||
{
|
||||
p->setUniformValue( m_matrixId, state.combinedMatrix() );
|
||||
}
|
||||
|
||||
if ( state.isOpacityDirty() )
|
||||
{
|
||||
p->setUniformValue( m_rectOpacityId, state.opacity() );
|
||||
}
|
||||
|
||||
bool updateMaterial = ( oldMaterial == nullptr ) || newMaterial->compare( oldMaterial ) != 0;
|
||||
updateMaterial |= state.isCachedMaterialDataDirty();
|
||||
|
||||
if ( !updateMaterial )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(const auto* const material = dynamic_cast< const BlurredBoxMaterial* >( newMaterial ))
|
||||
{
|
||||
p->setUniformValue( m_rectCornerRadiiId, material->m_rectCornerRadii );
|
||||
p->setUniformValue( m_rectAspect, material->m_rectAspect );
|
||||
p->setUniformValue( m_blurDirectionsId, material->m_blurDirections );
|
||||
p->setUniformValue( m_blurQualityId, material->m_blurQuality );
|
||||
p->setUniformValue( m_blurRadiusId, material->m_blurRadius );
|
||||
p->setUniformValue( m_edgeSoftnessId, material->m_edgeSoftness );
|
||||
p->setUniformValue( m_textureId, 0 /* GL_TEXTURE0 */);
|
||||
|
||||
auto* const f = QOpenGLContext::currentContext()->functions();
|
||||
f->glActiveTexture(GL_TEXTURE0);
|
||||
material->m_texture->bind();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <QSGMaterialShader>
|
||||
|
||||
class BlurredBoxMaterialShader final : public QSGMaterialShader
|
||||
{
|
||||
public:
|
||||
BlurredBoxMaterialShader();
|
||||
char const* const* attributeNames() const override;
|
||||
void initialize() override;
|
||||
void updateState( const QSGMaterialShader::RenderState& state, QSGMaterial* newMaterial,
|
||||
QSGMaterial* oldMaterial ) override;
|
||||
|
||||
private:
|
||||
int m_matrixId = -1;
|
||||
int m_rectOpacityId = -1;
|
||||
int m_rectCornerRadiiId = -1;
|
||||
int m_rectAspect = -1;
|
||||
int m_blurDirectionsId = -1;
|
||||
int m_blurQualityId = -1;
|
||||
int m_blurRadiusId = -1;
|
||||
int m_textureId = -1;
|
||||
int m_edgeSoftnessId = -1;
|
||||
};
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
#include "BlurredBoxNode.h"
|
||||
#include "BlurredBoxMaterial.h"
|
||||
#include "BlurredBoxTextureProvider.h"
|
||||
|
||||
#include <QskBoxShapeMetrics.h>
|
||||
|
||||
#include <qcolor.h>
|
||||
#include <qsgmaterial.h>
|
||||
#include <qsgmaterialshader.h>
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QQuickWindow>
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qsgnode_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
#include <limits>
|
||||
|
||||
class BlurredBoxNodePrivate final : public QSGGeometryNodePrivate
|
||||
{
|
||||
public:
|
||||
BlurredBoxNodePrivate()
|
||||
: geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 )
|
||||
{
|
||||
}
|
||||
|
||||
QSGGeometry geometry;
|
||||
BlurredBoxMaterial material;
|
||||
QRectF rect;
|
||||
};
|
||||
|
||||
BlurredBoxNode::BlurredBoxNode()
|
||||
: QSGGeometryNode( *new BlurredBoxNodePrivate )
|
||||
{
|
||||
Q_D( BlurredBoxNode );
|
||||
|
||||
setGeometry( &d->geometry );
|
||||
setMaterial( &d->material );
|
||||
setFlag(QSGNode::UsePreprocess);
|
||||
}
|
||||
|
||||
void BlurredBoxNode::preprocess()
|
||||
{
|
||||
Q_D( BlurredBoxNode );
|
||||
if(d->material.m_texture)
|
||||
{
|
||||
if (auto* dynamicTexture = qobject_cast<QSGDynamicTexture*>(d->material.m_texture.get() ))
|
||||
{
|
||||
dynamicTexture->updateTexture();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlurredBoxNode::setBlurData( const QRectF& rect, const QskBoxShapeMetrics& shape,
|
||||
const QRectF& rectOnScreen, float opacity, float blurDirections,
|
||||
float blurQuality, float blurSize, BlurredBoxTextureProvider* textureProvider)
|
||||
{
|
||||
Q_D( BlurredBoxNode );
|
||||
|
||||
d->rect = rect;
|
||||
|
||||
if(!d->material.m_texture)
|
||||
{
|
||||
d->material.m_texture = std::unique_ptr<QSGTexture>(textureProvider->texture(rectOnScreen.toRect()));
|
||||
}
|
||||
|
||||
QSGGeometry::updateTexturedRectGeometry( &d->geometry, d->rect, {0.0,0.0,1.0,1.0} /* texture coordinates */);
|
||||
|
||||
// update all four corner radii
|
||||
const auto size = std::min( d->rect.width(), d->rect.height() );
|
||||
d->material.m_rectCornerRadii = {
|
||||
static_cast< float >( std::min( 1.0, shape.radius( Qt::TopLeftCorner ).width() / size)),
|
||||
static_cast< float >( std::min( 1.0, shape.radius( Qt::TopRightCorner ).width() / size)),
|
||||
static_cast< float >( std::min( 1.0, shape.radius( Qt::BottomRightCorner ).width() / size)),
|
||||
static_cast< float >( std::min( 1.0, shape.radius( Qt::BottomLeftCorner ).width() / size))
|
||||
};
|
||||
|
||||
// update the blurring radii
|
||||
d->material.m_blurRadius = {
|
||||
static_cast< float >( blurSize / rectOnScreen.width()),
|
||||
static_cast< float >( blurSize / rectOnScreen.height())
|
||||
};
|
||||
|
||||
// updated rectangle's aspect ratio
|
||||
const auto cond = rect.width() >= rect.height();
|
||||
d->material.m_rectAspect = {
|
||||
static_cast<float>(cond ? rect.width() / rect.height() : 1.0),
|
||||
static_cast<float>(cond ? 1.0 : rect.height() / rect.width())
|
||||
};
|
||||
|
||||
d->material.m_opacity = opacity;
|
||||
d->material.m_blurDirections = std::max(blurDirections, std::numeric_limits<float>::min());
|
||||
d->material.m_blurQuality = std::max(blurQuality, std::numeric_limits<float>::min());
|
||||
d->material.m_edgeSoftness = static_cast<float>(1.0f / std::max(1.0, rect.width()));
|
||||
|
||||
markDirty( QSGNode::DirtyGeometry );
|
||||
markDirty( QSGNode::DirtyMaterial );
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <QSGGeometryNode>
|
||||
#include "BlurredBoxTextureProvider.h"
|
||||
|
||||
class QskBoxShapeMetrics;
|
||||
class BlurredBoxNodePrivate;
|
||||
|
||||
class BlurredBoxNode final : public QSGGeometryNode
|
||||
{
|
||||
public:
|
||||
BlurredBoxNode();
|
||||
|
||||
void preprocess() override;
|
||||
|
||||
void setBlurData( const QRectF&, const QskBoxShapeMetrics&, const QRectF& rectOnScreen, float opacity, float blurDirections, float blurQuality,
|
||||
float blurSize , BlurredBoxTextureProvider* textureProvider);
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE( BlurredBoxNode )
|
||||
};
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#include "BlurredBoxSkinlet.h"
|
||||
#include "BlurredBox.h"
|
||||
#include "BlurredBoxNode.h"
|
||||
#include "BlurredBoxTextureProvider.h"
|
||||
|
||||
#include <QskSGNode.h>
|
||||
#include <QskBoxShapeMetrics.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
BlurredBoxSkinlet::BlurredBoxSkinlet(std::shared_ptr<BlurredBoxTextureProvider> textureProvider) : m_textureProvider(std::move(textureProvider))
|
||||
{
|
||||
setNodeRoles( { PanelRole } );
|
||||
}
|
||||
|
||||
BlurredBoxSkinlet::~BlurredBoxSkinlet()
|
||||
{
|
||||
m_textureProvider = nullptr;
|
||||
}
|
||||
|
||||
QRectF BlurredBoxSkinlet::subControlRect(
|
||||
const QskSkinnable*, const QRectF& contentsRect, QskAspect::Subcontrol ) const
|
||||
{
|
||||
return contentsRect;
|
||||
}
|
||||
|
||||
QSGNode* BlurredBoxSkinlet::updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
const auto box = dynamic_cast< const BlurredBox* >( skinnable );
|
||||
const auto r = box->subControlRect( BlurredBox::Panel );
|
||||
|
||||
if ( r.isEmpty() )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto result = QskSkinlet::updateSubNode( skinnable, nodeRole, node );
|
||||
|
||||
switch ( nodeRole )
|
||||
{
|
||||
case PanelRole:
|
||||
auto* const blurred = QskSGNode::ensureNode< BlurredBoxNode >( node );
|
||||
const auto boxShapeHint = box->boxShapeHint(BlurredBox::Panel);
|
||||
const auto rectOnScreen = box->mapRectToScene( box->contentsRect() );
|
||||
blurred->setBlurData( r, boxShapeHint, rectOnScreen,
|
||||
static_cast< float >( box->opacity() ), box->blurDirections(), box->blurQuality(),
|
||||
box->blurSize(), m_textureProvider.get());
|
||||
return blurred;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <QskSkinlet.h>
|
||||
#include <memory>
|
||||
#include "BlurredBoxTextureProvider.h"
|
||||
|
||||
class BlurredBoxSkinlet final : public QskSkinlet
|
||||
{
|
||||
public:
|
||||
enum NodeRole
|
||||
{
|
||||
PanelRole
|
||||
};
|
||||
|
||||
BlurredBoxSkinlet(std::shared_ptr<BlurredBoxTextureProvider> textureProvider);
|
||||
~BlurredBoxSkinlet() override;
|
||||
QRectF subControlRect(
|
||||
const QskSkinnable*, const QRectF& contentsRect, QskAspect::Subcontrol ) const override;
|
||||
QSGNode* updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const override;
|
||||
private:
|
||||
std::shared_ptr<BlurredBoxTextureProvider> m_textureProvider;
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#include "BlurredBoxTextureProvider.h"
|
||||
|
||||
#include <QQuickWindow>
|
||||
#include <QSGTexture>
|
||||
|
||||
#include <memory>
|
||||
|
||||
BlurredBoxTextureProvider::BlurredBoxTextureProvider(QQuickWindow *window) : m_window(window), m_image(window->grabWindow())
|
||||
{
|
||||
}
|
||||
|
||||
BlurredBoxTextureProvider::~BlurredBoxTextureProvider()
|
||||
{
|
||||
m_window = nullptr;
|
||||
}
|
||||
|
||||
QSGTexture* BlurredBoxTextureProvider::texture() const
|
||||
{
|
||||
return m_window->createTextureFromImage(m_image);
|
||||
}
|
||||
|
||||
QSGTexture *BlurredBoxTextureProvider::texture(QRect roi) const
|
||||
{
|
||||
if (!m_image.rect().contains(roi))
|
||||
{
|
||||
QImage black(roi.width(), roi.height(), QImage::Format_RGBA8888);
|
||||
black.fill(Qt::black);
|
||||
return m_window->createTextureFromImage(black);
|
||||
}
|
||||
const auto image = m_image.copy(roi);
|
||||
return m_window->createTextureFromImage(image);
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <QSGTextureProvider>
|
||||
#include <QImage>
|
||||
|
||||
class QSGTexture;
|
||||
class QQuickWindow;
|
||||
|
||||
class BlurredBoxTextureProvider final : public QSGTextureProvider
|
||||
{
|
||||
public:
|
||||
BlurredBoxTextureProvider(QQuickWindow* window);
|
||||
BlurredBoxTextureProvider(QQuickWindow* window, QImage image);
|
||||
~BlurredBoxTextureProvider() override;
|
||||
QSGTexture* texture() const override;
|
||||
QSGTexture* texture(QRect roi) const;
|
||||
private:
|
||||
QQuickWindow* m_window = nullptr;
|
||||
QImage m_image;
|
||||
};
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
#include "MainWindow.h"
|
||||
#include "BlurredBox.h"
|
||||
#include "BlurredBoxTextureProvider.h"
|
||||
#include "BlurredBoxSkinlet.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QskLinearBox.h>
|
||||
#include <QskStackBox.h>
|
||||
|
||||
#include <QskGraphic.h>
|
||||
#include <QskGraphicLabel.h>
|
||||
#include <QskGridBox.h>
|
||||
#include <QskSegmentedBar.h>
|
||||
#include <QskShortcutMap.h>
|
||||
#include <QskSkin.h>
|
||||
#include <QskSlider.h>
|
||||
#include <QskTextInput.h>
|
||||
#include <QskTextLabel.h>
|
||||
#include <QQuickItemGrabResult>
|
||||
#include <QSGTextureProvider>
|
||||
#include <QskAnimator.h>
|
||||
#include <QskBoxShapeMetrics.h>
|
||||
#include <QskPushButton.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class BlurredBoxAnimator : public QskAnimator{
|
||||
public:
|
||||
BlurredBoxAnimator(BlurredBox& blurred): m_blurred(blurred) {
|
||||
|
||||
}
|
||||
void advance(qreal value) override
|
||||
{
|
||||
m_blurred.setOpacity(value);
|
||||
}
|
||||
|
||||
void done() override {
|
||||
delete this;
|
||||
}
|
||||
private:
|
||||
BlurredBox& m_blurred;
|
||||
};
|
||||
|
||||
enum Layers : int { BACKGROUND = 1, BLURRED = 2, CONTROLS = 3 };
|
||||
|
||||
MainWindow::MainWindow() : m_stack(new QskStackBox(contentItem()))
|
||||
{
|
||||
constexpr auto width = 1280;
|
||||
constexpr auto height = 720;
|
||||
constexpr QSize size = { width, height };
|
||||
setMinimumSize( size );
|
||||
setMaximumSize( size );
|
||||
setTitle( tr( "Blurring" ) );
|
||||
|
||||
m_stack->setAutoLayoutChildren(true);
|
||||
createBackground();
|
||||
|
||||
QskShortcutMap::addShortcut( Qt::CTRL | Qt::Key_O, false, contentItem(), [this](){
|
||||
createOverlay();
|
||||
});
|
||||
}
|
||||
|
||||
void MainWindow::createBackground()
|
||||
{
|
||||
// create a brackground image
|
||||
auto* const graphic = new QskGraphicLabel( m_stack );
|
||||
graphic->setZ(BACKGROUND);
|
||||
graphic->setFillMode( QskGraphicLabel::FillMode::Stretch );
|
||||
graphic->setAlignment( Qt::AlignCenter );
|
||||
|
||||
static int index = 0;
|
||||
const QImage image( QString( ":/backgrounds/background%1.jpg" ).arg( 1 + index++ ) );
|
||||
graphic->setGraphic( QskGraphic::fromImage( image ) );
|
||||
m_stack->addItem(graphic);
|
||||
update();
|
||||
}
|
||||
|
||||
void MainWindow::createBlurDirectionsControls( BlurredBox* blurred, QskLinearBox* layout )
|
||||
{
|
||||
auto* const label = new QskTextLabel( layout );
|
||||
label->setTextColor( Qt::white );
|
||||
label->setFontRole( QskSkin::MediumFont );
|
||||
auto* const slider = new QskSlider( Qt::Horizontal, layout );
|
||||
slider->setMinimum( 16.0 );
|
||||
slider->setMaximum( 32.0 );
|
||||
connect( slider, &QskSlider::valueChanged, slider, [ blurred, label ]( qreal value ) {
|
||||
blurred->setBlurDirections( static_cast< float >( value ) );
|
||||
label->setText( QString( tr( "Blur Directions" ) + " ( %1 )" ).arg( value ) );
|
||||
} );
|
||||
slider->setValue( blurred->blurDirections() );
|
||||
}
|
||||
|
||||
void MainWindow::createBlurQualityControls( BlurredBox* blurred, QskLinearBox* layout )
|
||||
{
|
||||
auto* const label = new QskTextLabel( layout );
|
||||
label->setTextColor( Qt::white );
|
||||
label->setFontRole( QskSkin::MediumFont );
|
||||
auto* const slider = new QskSlider( Qt::Horizontal, layout );
|
||||
slider->setMinimum( 4.0 );
|
||||
slider->setMaximum( 16.0 );
|
||||
connect( slider, &QskSlider::valueChanged, slider, [ blurred, label ]( qreal value ) {
|
||||
blurred->setBlurQuality( static_cast< float >( value ) );
|
||||
label->setText( QString( tr( "Blur Quality" ) + " ( %1 )" ).arg( value ) );
|
||||
} );
|
||||
slider->setValue( blurred->blurQuality() );
|
||||
}
|
||||
|
||||
void MainWindow::createBlurSizeControls( BlurredBox* blurred, QskLinearBox* layout )
|
||||
{
|
||||
auto* const label = new QskTextLabel( layout );
|
||||
label->setTextColor( Qt::white );
|
||||
label->setFontRole( QskSkin::MediumFont );
|
||||
auto* const slider = new QskSlider( Qt::Horizontal, layout );
|
||||
slider->setMinimum( 0.0 );
|
||||
slider->setMaximum( 32.0 );
|
||||
connect( slider, &QskSlider::valueChanged, slider, [ blurred, label ]( qreal value ) {
|
||||
blurred->setBlurSize( static_cast< float >( value ) );
|
||||
label->setText( QString( tr( "Blur Size" ) + " ( %1 )" ).arg( value ) );
|
||||
} );
|
||||
slider->setValue( blurred->blurSize() );
|
||||
}
|
||||
|
||||
void MainWindow::createBlurOpacityControls( BlurredBox* blurred, QskLinearBox* layout )
|
||||
{
|
||||
auto* const label = new QskTextLabel( layout );
|
||||
label->setTextColor( Qt::white );
|
||||
label->setFontRole( QskSkin::MediumFont );
|
||||
auto* const slider = new QskSlider( Qt::Horizontal, layout );
|
||||
slider->setMinimum( 0.0 );
|
||||
slider->setMaximum( 1.0 );
|
||||
connect( slider, &QskSlider::valueChanged, slider, [ blurred, label ]( qreal value ) {
|
||||
blurred->setOpacity( value );
|
||||
label->setText( QString( tr( "Blur Opacity" ) + " ( %1 )" ).arg( value ) );
|
||||
} );
|
||||
slider->setValue( blurred->opacity() );
|
||||
}
|
||||
|
||||
void MainWindow::createBlurCornerRadiiControls( BlurredBox* blurred, QskLinearBox* layout )
|
||||
{
|
||||
auto* const label = new QskTextLabel( layout );
|
||||
label->setTextColor( Qt::white );
|
||||
label->setFontRole( QskSkin::MediumFont );
|
||||
auto* const bar = new QskSegmentedBar( Qt::Horizontal, layout );
|
||||
enum
|
||||
{
|
||||
TL = 0,
|
||||
TR = 1,
|
||||
BR = 2,
|
||||
BL = 3
|
||||
};
|
||||
bar->addText( "TL" );
|
||||
bar->addText( "TR" );
|
||||
bar->addText( "BR" );
|
||||
bar->addText( "BL" );
|
||||
auto* const slider = new QskSlider( Qt::Horizontal, layout );
|
||||
slider->setMinimum( 0.0 );
|
||||
slider->setMaximum( 80.0 );
|
||||
connect( slider, &QskSlider::valueChanged, slider, [ blurred, bar, label ]( qreal value ) {
|
||||
auto shape = blurred->boxShapeHint(BlurredBox::Panel);
|
||||
const auto format = tr( "Corner Radius" ) + " ( %1 )";
|
||||
|
||||
switch ( bar->currentIndex() )
|
||||
{
|
||||
case TL:
|
||||
shape.setTopLeft( { value, value } );
|
||||
break;
|
||||
case TR:
|
||||
shape.setTopRight( { value, value } );
|
||||
break;
|
||||
case BR:
|
||||
shape.setBottomRight( { value, value } );
|
||||
break;
|
||||
case BL:
|
||||
shape.setBottomLeft( { value, value } );
|
||||
break;
|
||||
}
|
||||
|
||||
label->setText( format.arg( value ) );
|
||||
blurred->setBoxShapeHint(BlurredBox::Panel, shape );
|
||||
blurred->update();
|
||||
} );
|
||||
connect( bar, &QskSegmentedBar::currentIndexChanged, slider, [ blurred, slider ]( int index ) {
|
||||
const auto shape = blurred->boxShapeHint(BlurredBox::Panel);
|
||||
|
||||
switch ( index )
|
||||
{
|
||||
case TL:
|
||||
slider->setValue( shape.topLeft().width() );
|
||||
break;
|
||||
case TR:
|
||||
slider->setValue( shape.topRight().width() );
|
||||
break;
|
||||
case BR:
|
||||
slider->setValue( shape.bottomRight().width() );
|
||||
break;
|
||||
case BL:
|
||||
slider->setValue( shape.bottomLeft().width() );
|
||||
break;
|
||||
}
|
||||
} );
|
||||
slider->setValue( blurred->boxShapeHint(BlurredBox::Panel).topLeft().width() );
|
||||
bar->setSelectedIndex( TL );
|
||||
bar->setCurrentIndex( TL );
|
||||
}
|
||||
|
||||
void MainWindow::createShortcutNote( QskLinearBox* layout )
|
||||
{
|
||||
const auto text = tr( "Press 'Ctrl + Space' to change the background" );
|
||||
auto* const label = new QskTextLabel( text, layout );
|
||||
label->setTextColor( Qt::white );
|
||||
label->setFontRole( QskSkin::LargeFont );
|
||||
}
|
||||
|
||||
void MainWindow::createOverlay()
|
||||
{
|
||||
auto* const skinlet = new BlurredBoxSkinlet(std::make_shared<BlurredBoxTextureProvider>(this));
|
||||
skinlet->setOwnedBySkinnable(true);
|
||||
|
||||
auto* blurredLayout = new QskLinearBox(m_stack);
|
||||
blurredLayout->setZ(BLURRED);
|
||||
|
||||
auto* const blurred = new BlurredBox(blurredLayout);
|
||||
blurred->setBoxShapeHint(BlurredBox::Panel, { 40, 40, 40, 40 });
|
||||
blurred->setBlurQuality(20);
|
||||
blurred->setBlurDirections(32);
|
||||
blurred->setBlurSize(16);
|
||||
blurred->setSkinlet(skinlet);
|
||||
blurred->setMargins(80);
|
||||
|
||||
auto* const animator = new BlurredBoxAnimator(*blurred);
|
||||
animator->setDuration(200);
|
||||
animator->setWindow(this);
|
||||
animator->start();
|
||||
|
||||
auto* const controlsLayout = new QskLinearBox( Qt::Vertical, m_stack );
|
||||
controlsLayout->setZ(CONTROLS);
|
||||
controlsLayout->setMargins(80);
|
||||
|
||||
// create controls to change the rectangle
|
||||
controlsLayout->addSpacer( 10, 1 );
|
||||
createBlurDirectionsControls( blurred, controlsLayout );
|
||||
createBlurQualityControls( blurred, controlsLayout );
|
||||
createBlurSizeControls( blurred, controlsLayout );
|
||||
createBlurOpacityControls( blurred, controlsLayout );
|
||||
createBlurCornerRadiiControls( blurred, controlsLayout );
|
||||
controlsLayout->addSpacer( 10, 1 );
|
||||
createShortcutNote( controlsLayout );
|
||||
controlsLayout->addSpacer( 10, 1 );
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
#include "moc_MainWindow.cpp"
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <QskWindow.h>
|
||||
#include <QskStackBox.h>
|
||||
|
||||
class BlurredBox;
|
||||
class QskLinearBox;
|
||||
|
||||
class MainWindow : public QskWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow();
|
||||
|
||||
private:
|
||||
void createBackground();
|
||||
void createBlurDirectionsControls( BlurredBox* blurred, QskLinearBox* layout );
|
||||
void createBlurQualityControls( BlurredBox* blurred, QskLinearBox* layout );
|
||||
void createBlurSizeControls( BlurredBox* blurred, QskLinearBox* layout );
|
||||
void createBlurOpacityControls( BlurredBox* blurred, QskLinearBox* layout );
|
||||
void createBlurCornerRadiiControls( BlurredBox* blurred, QskLinearBox* layout );
|
||||
void createShortcutNote( QskLinearBox* layout );
|
||||
void createOverlay();
|
||||
|
||||
QskStackBox* m_stack = nullptr;
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 616 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 112 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 236 KiB |
|
|
@ -0,0 +1,26 @@
|
|||
CONFIG += qskexample
|
||||
CONFIG += opengl
|
||||
|
||||
QT += quick_private opengl-private # TODO: examples should not use private headers
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
MainWindow.cpp \
|
||||
BlurredBox.cpp \
|
||||
BlurredBoxMaterial.cpp \
|
||||
BlurredBoxMaterialShader.cpp \
|
||||
BlurredBoxNode.cpp \
|
||||
BlurredBoxSkinlet.cpp \
|
||||
BlurredBoxTextureProvider.cpp
|
||||
|
||||
HEADERS += \
|
||||
MainWindow.h \
|
||||
BlurredBox.h \
|
||||
BlurredBoxMaterial.h \
|
||||
BlurredBoxMaterialShader.h \
|
||||
BlurredBoxNode.h \
|
||||
BlurredBoxSkinlet.h \
|
||||
BlurredBoxTextureProvider.h
|
||||
|
||||
RESOURCES += \
|
||||
blurringshaders.qrc
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>shaders/blurredbox.vert</file>
|
||||
<file>shaders/blurredbox.frag</file>
|
||||
<file>backgrounds/background1.jpg</file>
|
||||
<file>backgrounds/background2.jpg</file>
|
||||
<file>backgrounds/background3.jpg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#include <SkinnyShortcut.h>
|
||||
|
||||
#include <QskObjectCounter.h>
|
||||
#include <QskSetup.h>
|
||||
#include <QskShortcutMap.h>
|
||||
#include <QskSkinFactory.h>
|
||||
#include <QskSkinManager.h>
|
||||
#include <QskWindow.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
|
||||
#include "MainWindow.h"
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
#ifdef ITEM_STATISTICS
|
||||
QskObjectCounter counter( true );
|
||||
#endif
|
||||
|
||||
QGuiApplication app( argc, argv );
|
||||
|
||||
// disable default skins
|
||||
qskSkinManager->setPluginPaths( QStringList() ); // no plugins
|
||||
|
||||
// With CTRL-B you can rotate a couple of visual debug modes
|
||||
SkinnyShortcut::enable( SkinnyShortcut::RotateSkin | SkinnyShortcut::DebugBackground |
|
||||
SkinnyShortcut::DebugStatistics | SkinnyShortcut::Quit );
|
||||
|
||||
MainWindow window;
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
// opacity of the rectangle
|
||||
uniform lowp float rectOpacity;
|
||||
// x = top left, y = top right, z = bottom right, w = bottom left
|
||||
uniform lowp vec4 rectCornerRadii;
|
||||
// the rectangle's aspect ratio
|
||||
uniform lowp vec2 rectAspect;
|
||||
|
||||
// must be greater than 0.0!
|
||||
uniform lowp float blurDirections;
|
||||
// must be greater than 0.0!
|
||||
uniform lowp float blurQuality;
|
||||
// the radius for blurring
|
||||
uniform lowp vec2 blurRadius;
|
||||
|
||||
// normalized position of the fragment
|
||||
varying lowp vec2 coord;
|
||||
|
||||
// the texture with coordinates from top left (0.0,0.0) to bottom right (1.0,1.0)
|
||||
uniform sampler2D txr;
|
||||
|
||||
uniform lowp float edgeSoftness;
|
||||
|
||||
lowp float effectiveRadius( in lowp vec4 radii, in lowp vec2 point )
|
||||
{
|
||||
if ( point.y < 0.5 )
|
||||
return ( point.x < 0.5) ? radii.x : radii.y;
|
||||
else
|
||||
return ( point.x < 0.5) ? radii.z : radii.w;
|
||||
}
|
||||
|
||||
lowp float roundedBoxSDF(lowp vec2 centerPosition, lowp vec2 size, lowp float radius)
|
||||
{
|
||||
return length( max( abs(centerPosition) - size + radius, 0.0) ) - radius;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
if(rectOpacity == 0.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lowp vec2 rectAspectHalf = rectAspect / 2.0;
|
||||
|
||||
// Pixel color
|
||||
lowp vec4 fragColorOrig = texture2D(txr, coord);
|
||||
lowp vec4 fragColor = fragColorOrig;
|
||||
|
||||
// Blur calculations
|
||||
const lowp float Pi = 6.28318530718; // constant for Pi*2
|
||||
for(lowp float d = 0.0; d < Pi; d += Pi / blurDirections)
|
||||
{
|
||||
lowp vec2 offset = vec2(cos(d), sin(d));
|
||||
for(lowp float i = 1.0 / blurQuality; i <= 1.0; i += 1.0 / blurQuality)
|
||||
{
|
||||
fragColor += texture2D( txr, coord + offset * blurRadius * i);
|
||||
}
|
||||
}
|
||||
|
||||
// Current corner radius
|
||||
lowp float cornerRadius = effectiveRadius(rectCornerRadii, coord);
|
||||
|
||||
// Calculate distance to edge.
|
||||
lowp float distance = roundedBoxSDF(coord * rectAspect - rectAspectHalf, rectAspectHalf, cornerRadius);
|
||||
|
||||
// Smooth the result (free antialiasing).
|
||||
lowp float smoothedAlpha = 1.0 - smoothstep(0.0, 2.0 * edgeSoftness, distance);
|
||||
|
||||
// Output to screen
|
||||
fragColor /= blurQuality * blurDirections - 15.0;
|
||||
|
||||
// Mix the original pixel coolor with the blurred
|
||||
gl_FragColor = mix(fragColorOrig, vec4(fragColor.xyz, 1.0), smoothedAlpha) * rectOpacity;
|
||||
}
|
||||
|
||||
// further reading
|
||||
// - https://iquilezles.org/articles/distfunctions
|
||||
// - https://www.shadertoy.com/view/Xltfzj
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
uniform highp mat4 matrix;
|
||||
|
||||
attribute highp vec4 in_vertex;
|
||||
attribute mediump vec2 in_coord;
|
||||
|
||||
varying mediump vec2 coord;
|
||||
|
||||
void main()
|
||||
{
|
||||
coord = in_coord;
|
||||
gl_Position = matrix * in_vertex;
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ TEMPLATE = subdirs
|
|||
|
||||
# c++
|
||||
SUBDIRS += \
|
||||
blurredbox \
|
||||
desktop \
|
||||
gallery \
|
||||
layouts \
|
||||
|
|
|
|||
Loading…
Reference in New Issue