qskinny/src/nodes/QskTextureNode.cpp

280 lines
6.7 KiB
C++
Raw Normal View History

2017-07-21 16:21:34 +00:00
#include "QskTextureNode.h"
#include "QskTextureRenderer.h"
2017-07-21 16:21:34 +00:00
2018-08-03 06:15:28 +00:00
#include <qopenglfunctions.h>
2018-07-19 12:10:48 +00:00
#include <qsggeometry.h>
#include <qsgmaterial.h>
2020-11-01 14:44:15 +00:00
#include <qquickwindow.h>
2017-07-21 16:21:34 +00:00
2020-11-01 14:44:15 +00:00
QSK_QT_PRIVATE_BEGIN
2017-07-21 16:21:34 +00:00
#include <private/qsgnode_p.h>
2020-11-01 14:44:15 +00:00
QSK_QT_PRIVATE_END
2017-07-21 16:21:34 +00:00
namespace
{
class MaterialShader final : public QSGMaterialShader
{
2018-08-03 06:15:28 +00:00
public:
2017-07-21 16:21:34 +00:00
MaterialShader( bool isOpaque );
2018-07-31 15:32:25 +00:00
char const* const* attributeNames() const override;
void updateState( const RenderState&, QSGMaterial*, QSGMaterial* ) override;
2017-07-21 16:21:34 +00:00
2018-08-03 06:15:28 +00:00
protected:
2018-07-31 15:32:25 +00:00
void initialize() override;
2017-07-21 16:21:34 +00:00
2018-08-03 06:15:28 +00:00
private:
2019-05-16 06:14:32 +00:00
int m_matrixId = -1;
int m_opacityId = -1;
2017-07-21 16:21:34 +00:00
const bool m_isOpaque : 1;
};
class Material final : public QSGMaterial
{
2018-08-03 06:15:28 +00:00
public:
2017-07-21 16:21:34 +00:00
Material( bool isOpaque );
2018-07-31 15:32:25 +00:00
QSGMaterialType* type() const override;
QSGMaterialShader* createShader() const override;
2017-07-21 16:21:34 +00:00
2017-12-07 16:04:05 +00:00
void setTextureId( uint );
uint textureId() const;
2017-07-21 16:21:34 +00:00
2018-08-03 06:15:28 +00:00
int compare( const QSGMaterial* ) const override;
2017-07-21 16:21:34 +00:00
2018-08-03 06:15:28 +00:00
private:
2020-11-01 08:28:20 +00:00
uint m_textureId = 0;
2017-07-21 16:21:34 +00:00
const bool m_isOpaque : 1;
};
2018-08-03 06:15:28 +00:00
MaterialShader::MaterialShader( bool isOpaque )
: m_isOpaque( isOpaque )
2017-07-21 16:21:34 +00:00
{
2018-08-03 06:15:28 +00:00
setShaderSourceFile( QOpenGLShader::Vertex,
QStringLiteral( ":/qt-project.org/scenegraph/shaders/opaquetexture.vert" ) );
2017-07-21 16:21:34 +00:00
2020-11-01 08:28:20 +00:00
const auto fragmentShaderFile = m_isOpaque
? QStringLiteral( ":/qt-project.org/scenegraph/shaders/opaquetexture.frag" )
: QStringLiteral( ":/qt-project.org/scenegraph/shaders/texture.frag" );
setShaderSourceFile( QOpenGLShader::Fragment, fragmentShaderFile );
2017-07-21 16:21:34 +00:00
}
char const* const* MaterialShader::attributeNames() const
{
static char const* const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 };
return attr;
}
2018-08-03 06:15:28 +00:00
void MaterialShader::updateState(
const RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial )
2017-07-21 16:21:34 +00:00
{
if ( !m_isOpaque && state.isOpacityDirty() )
program()->setUniformValue( m_opacityId, state.opacity() );
auto* materialOld = static_cast< Material* >( oldMaterial );
auto* materialNew = static_cast< Material* >( newMaterial );
2018-08-03 06:15:28 +00:00
if ( ( materialOld == nullptr ) ||
2019-01-04 12:42:16 +00:00
( materialOld->textureId() != materialNew->textureId() ) )
2017-07-21 16:21:34 +00:00
{
auto funcs = QOpenGLContext::currentContext()->functions();
funcs->glBindTexture( GL_TEXTURE_2D, materialNew->textureId() );
}
if ( state.isMatrixDirty() )
program()->setUniformValue( m_matrixId, state.combinedMatrix() );
}
void MaterialShader::initialize()
{
2018-08-03 06:15:28 +00:00
m_matrixId = program()->uniformLocation( "qt_Matrix" );
2017-07-21 16:21:34 +00:00
if ( !m_isOpaque )
2018-08-03 06:15:28 +00:00
m_opacityId = program()->uniformLocation( "opacity" );
2017-07-21 16:21:34 +00:00
}
2018-08-03 06:15:28 +00:00
Material::Material( bool isOpaque )
2020-11-01 08:28:20 +00:00
: m_isOpaque( isOpaque )
2017-07-21 16:21:34 +00:00
{
2018-08-03 06:15:28 +00:00
setFlag( Blending, true ); // alpha blending
2017-07-21 16:21:34 +00:00
}
2017-12-07 16:04:05 +00:00
void Material::setTextureId( uint id )
2017-07-21 16:21:34 +00:00
{
m_textureId = id;
}
2017-12-07 16:04:05 +00:00
uint Material::textureId() const
2017-07-21 16:21:34 +00:00
{
return m_textureId;
}
QSGMaterialType* Material::type() const
{
if ( m_isOpaque )
{
static QSGMaterialType typeOpaque;
return &typeOpaque;
}
else
{
static QSGMaterialType type;
return &type;
}
}
QSGMaterialShader* Material::createShader() const
{
return new MaterialShader( m_isOpaque );
}
int Material::compare( const QSGMaterial* other ) const
{
const auto otherMaterial = static_cast< const Material* >( other );
2017-12-07 16:04:05 +00:00
if ( m_textureId == otherMaterial->m_textureId )
return 0;
return ( m_textureId > otherMaterial->m_textureId ) ? 1 : -1;
2017-07-21 16:21:34 +00:00
}
}
2017-12-07 16:04:05 +00:00
class QskTextureNodePrivate final : public QSGGeometryNodePrivate
2017-07-21 16:21:34 +00:00
{
2018-08-03 06:15:28 +00:00
public:
QskTextureNodePrivate()
: geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 )
, opaqueMaterial( true )
, material( false )
2017-07-21 16:21:34 +00:00
{
}
2020-11-01 14:44:15 +00:00
void setTextureId( QQuickWindow*, uint id );
void updateTextureGeometry( const QQuickWindow* window )
2020-10-26 13:13:57 +00:00
{
QRectF r( 0, 0, 1, 1 );
2020-11-01 14:44:15 +00:00
if ( this->mirrored & Qt::Horizontal )
2020-10-26 13:13:57 +00:00
{
r.setLeft( 1 );
r.setRight( 0 );
}
2020-11-01 14:44:15 +00:00
if ( mirrored & Qt::Vertical )
2020-10-26 13:13:57 +00:00
{
r.setTop( 1 );
r.setBottom( 0 );
}
2020-11-01 14:44:15 +00:00
const qreal ratio = window->effectiveDevicePixelRatio();
2020-10-26 13:13:57 +00:00
const QRectF scaledRect( rect.x(), rect.y(),
rect.width() / ratio, rect.height() / ratio );
QSGGeometry::updateTexturedRectGeometry( &geometry, scaledRect, r );
}
2017-07-21 16:21:34 +00:00
QSGGeometry geometry;
Material opaqueMaterial;
Material material;
QRectF rect;
2020-11-01 14:44:15 +00:00
Qt::Orientations mirrored;
2017-07-21 16:21:34 +00:00
};
2018-08-03 06:15:28 +00:00
QskTextureNode::QskTextureNode()
: QSGGeometryNode( *new QskTextureNodePrivate )
2017-07-21 16:21:34 +00:00
{
Q_D( QskTextureNode );
setGeometry( &d->geometry );
setMaterial( &d->material );
setOpaqueMaterial( &d->opaqueMaterial );
}
QskTextureNode::~QskTextureNode()
{
Q_D( QskTextureNode );
if ( d->material.textureId() > 0 )
{
2018-02-06 06:51:33 +00:00
/*
In certain environments we have the effect, that at
program termination the context is already gone
*/
if ( auto context = QOpenGLContext::currentContext() )
{
GLuint id = d->material.textureId();
2017-07-21 16:21:34 +00:00
2018-02-06 06:51:33 +00:00
auto funcs = context->functions();
funcs->glDeleteTextures( 1, &id );
}
2017-07-21 16:21:34 +00:00
}
}
2020-11-01 14:44:15 +00:00
void QskTextureNode::setTexture( QQuickWindow* window,
const QRectF& rect, uint textureId,
Qt::Orientations mirrored )
2017-07-21 16:21:34 +00:00
{
Q_D( QskTextureNode );
2020-11-01 14:44:15 +00:00
if ( d->rect != rect || d->mirrored != mirrored )
2020-10-26 13:13:57 +00:00
{
2020-11-01 14:44:15 +00:00
d->rect = rect;
d->mirrored = mirrored;
d->updateTextureGeometry( window );
2017-07-21 16:21:34 +00:00
2020-10-26 13:13:57 +00:00
markDirty( DirtyGeometry );
}
2017-07-21 16:21:34 +00:00
2020-11-01 14:44:15 +00:00
if ( textureId != this->textureId() )
2017-07-21 16:21:34 +00:00
{
2020-11-01 14:44:15 +00:00
d->setTextureId( window, textureId );
2020-10-26 13:13:57 +00:00
markDirty( DirtyMaterial );
2017-07-21 16:21:34 +00:00
}
}
2020-11-01 14:44:15 +00:00
void QskTextureNodePrivate::setTextureId( QQuickWindow*, uint textureId )
2017-07-21 16:21:34 +00:00
{
2020-11-01 14:44:15 +00:00
if ( this->material.textureId() > 0 )
2017-07-21 16:21:34 +00:00
{
2020-11-01 14:44:15 +00:00
GLuint id = this->material.textureId();
2017-07-21 16:21:34 +00:00
2020-10-26 13:13:57 +00:00
auto funcs = QOpenGLContext::currentContext()->functions();
funcs->glDeleteTextures( 1, &id );
2017-07-21 16:21:34 +00:00
}
2020-11-01 14:44:15 +00:00
this->material.setTextureId( textureId );
this->opaqueMaterial.setTextureId( textureId );
2020-10-26 13:13:57 +00:00
}
2018-07-13 13:09:25 +00:00
2020-10-26 13:13:57 +00:00
uint QskTextureNode::textureId() const
{
Q_D( const QskTextureNode );
return d->material.textureId();
2017-07-21 16:21:34 +00:00
}
2020-10-26 17:06:06 +00:00
bool QskTextureNode::isNull() const
2020-11-01 14:44:15 +00:00
{
return textureId() == 0;
}
QRectF QskTextureNode::rect() const
{
Q_D( const QskTextureNode );
return d->rect;
}
Qt::Orientations QskTextureNode::mirrored() const
2020-10-26 17:06:06 +00:00
{
Q_D( const QskTextureNode );
2020-11-01 14:44:15 +00:00
return d->mirrored;
2020-10-26 17:06:06 +00:00
}