Merge remote-tracking branch 'origin/master' into material-theme

This commit is contained in:
Peter Hartmann 2022-06-07 11:09:38 +02:00
commit c4dc6e8c2f
20 changed files with 506 additions and 1023 deletions

View File

@ -26,6 +26,5 @@ SUBDIRS += \
boxes \
buttons \
frames \
gbenchmark \
glabels \
messageboxQml

View File

@ -1,178 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "Benchmark.h"
#include <QskGraphic.h>
#include <QskGraphicIO.h>
#include <QskColorFilter.h>
#include <QskTextureRenderer.h>
#include <QDebug>
#include <QDir>
#include <QElapsedTimer>
#include <QPainter>
#include <QQuickWindow>
#include <QStringList>
#include <QSvgRenderer>
bool Benchmark::run( const QString& dirName )
{
QDir svgDir( dirName );
QStringList svgFiles = svgDir.entryList( QStringList() << "*.svg", QDir::Files );
if ( svgFiles.isEmpty() )
return false;
const char qvgPath[] = "/tmp/benchmark/qvg";
if ( !svgDir.mkpath( qvgPath ) )
return false;
QStringList qvgFiles = svgFiles;
for ( int i = 0; i < qvgFiles.size(); i++ )
{
svgFiles[ i ].prepend( "/" );
svgFiles[ i ].prepend( dirName );
qvgFiles[ i ].replace( ".svg", ".qvg" );
qvgFiles[ i ].prepend( "/" );
qvgFiles[ i ].prepend( qvgPath );
}
QVector< QskGraphic > graphics( qvgFiles.size() );
QVector< QSvgRenderer* > renderers( svgFiles.size() );
qint64 msElapsed[ 6 ];
QElapsedTimer timer;
{
// compile step
timer.start();
for ( int i = 0; i < svgFiles.size(); i++ )
{
renderers[ i ] = new QSvgRenderer();
if ( !renderers[ i ]->load( svgFiles[ i ] ) )
{
qCritical() << "Can't load" << svgFiles[ i ];
return false;
}
}
msElapsed[ 0 ] = timer.elapsed();
}
{
// converting into graphics and storing to disk
timer.start();
for ( int i = 0; i < renderers.size(); i++ )
{
QPainter painter( &graphics[ i ] );
renderers[ i ]->render( &painter );
painter.end();
}
msElapsed[ 1 ] = timer.elapsed();
}
{
// writing them to disk
timer.start();
for ( int i = 0; i < graphics.size(); i++ )
{
QskGraphicIO::write( graphics[ i ], qvgFiles[ i ] );
}
msElapsed[ 2 ] = timer.elapsed();
}
{
// loading qvg files to memory
timer.start();
for ( int i = 0; i < qvgFiles.size(); i++ )
{
graphics[ i ] = QskGraphicIO::read( qvgFiles[ i ] );
if ( graphics[ i ].isNull() )
{
qCritical() << "Can't load" << qvgFiles[ i ];
return false;
}
}
msElapsed[ 3 ] = timer.elapsed();
}
{
// creating textures using OpenGL
timer.start();
const QSize targetSize( 200, 200 );
const QskColorFilter colorFilter;
for ( int i = 0; i < qvgFiles.size(); i++ )
{
using namespace QskTextureRenderer;
const auto textureId = createTextureFromGraphic(
nullptr, OpenGL, targetSize, graphics[ i ], colorFilter,
Qt::IgnoreAspectRatio );
if ( textureId == 0 )
{
qCritical() << "Can't render texture for" << qvgFiles[ i ];
return false;
}
}
msElapsed[ 4 ] = timer.elapsed();
}
{
// creating textures using Raster
timer.start();
const QSize targetSize( 200, 200 );
const QskColorFilter colorFilter;
for ( int i = 0; i < qvgFiles.size(); i++ )
{
using namespace QskTextureRenderer;
const auto textureId = createTextureFromGraphic(
nullptr, Raster, targetSize, graphics[ i ], colorFilter,
Qt::IgnoreAspectRatio );
if ( textureId == 0 )
{
qCritical() << "Can't render texture for" << qvgFiles[ i ];
return false;
}
}
msElapsed[ 5 ] = timer.elapsed();
}
qDebug() << "#Icons:" << svgFiles.count() <<
"Compiled:" << msElapsed[ 0 ] <<
"Converted:" << msElapsed[ 1 ] <<
"Stored:" << msElapsed[ 2 ] <<
"Loaded:" << msElapsed[ 3 ] <<
"Rendered OpenGL:" << msElapsed[ 4 ] <<
"Rendered Raster:" << msElapsed[ 5 ];
svgDir.rmdir( qvgPath );
return true;
}

View File

@ -1,13 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#pragma once
class QString;
namespace Benchmark
{
bool run( const QString& svgDir );
}

View File

@ -1,10 +0,0 @@
CONFIG += qskexample
QT += svg
HEADERS += \
Benchmark.h
SOURCES += \
Benchmark.cpp \
main.cpp

View File

@ -1,65 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "Benchmark.h"
#include <QskLinearBox.h>
#include <QskPushButton.h>
#include <QskWindow.h>
#include <QCommandLineParser>
#include <QGuiApplication>
class Button : public QskPushButton
{
public:
Button( const QString& testDir )
: m_testDir( testDir )
{
setText( QString( "Run: " ) + testDir );
setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
}
void run()
{
Benchmark::run( m_testDir );
}
private:
QString m_testDir;
};
int main( int argc, char* argv[] )
{
QGuiApplication app( argc, argv );
QCommandLineParser parser;
parser.setApplicationDescription( "Benchmark for creating textures from SVGs" );
parser.addHelpOption();
parser.addPositionalArgument( "svgdir", "Directory with SVG files.", "[pathname]" );
parser.process( app );
const QStringList args = parser.positionalArguments();
if ( args.count() != 1 )
parser.showHelp( 1 );
auto button = new Button( args[ 0 ] );
button->setLayoutAlignmentHint( Qt::AlignCenter );
QObject::connect( button, &Button::clicked, button, &Button::run );
auto box = new QskLinearBox();
box->addItem( button );
QskWindow window;
window.setColor( Qt::white );
window.resize( 400, 400 );
window.addItem( box );
window.show();
return app.exec();
}

View File

@ -10,7 +10,6 @@
#include "QskColorFilter.h"
#include "QskFunctions.h"
#include "QskGraphic.h"
#include "QskTextureNode.h"
QskGraphicLabelSkinlet::QskGraphicLabelSkinlet( QskSkin* skin )
: Inherited( skin )

View File

@ -7,6 +7,7 @@
#include "QskArcNode.h"
#include "QskAspect.h"
#include "QskArcMetrics.h"
#include "QskBoxBorderColors.h"
#include "QskBoxBorderMetrics.h"
#include "QskBoxClipNode.h"
@ -24,6 +25,7 @@
#include "QskTextNode.h"
#include "QskTextOptions.h"
#include "QskSkinStateChanger.h"
#include "QskTextureRenderer.h"
#include <qquickwindow.h>
#include <qsgsimplerectnode.h>
@ -111,18 +113,17 @@ static inline QSGNode* qskUpdateGraphicNode(
if ( control == nullptr )
return nullptr;
auto mode = QskTextureRenderer::OpenGL;
auto graphicNode = static_cast< QskGraphicNode* >( node );
if ( graphicNode == nullptr )
graphicNode = new QskGraphicNode();
if ( control->testUpdateFlag( QskControl::PreferRasterForTextures ) )
mode = QskTextureRenderer::Raster;
const bool useRaster = control->testUpdateFlag( QskControl::PreferRasterForTextures );
graphicNode->setRenderHint( useRaster ? QskPaintedNode::Raster : QskPaintedNode::OpenGL );
graphicNode->setMirrored( mirrored );
const auto r = qskSceneAlignedRect( control, rect );
graphicNode->setGraphic( control->window(), graphic,
colorFilter, mode, r, mirrored );
graphicNode->setGraphic( control->window(), graphic, colorFilter, r );
return graphicNode;
}

View File

@ -54,16 +54,30 @@ QSize QskGraphicTextureFactory::size() const
return m_size;
}
QSGTexture* QskGraphicTextureFactory::createTexture( QQuickWindow* window ) const
{
using namespace QskTextureRenderer;
class PaintHelper : public QskTextureRenderer::PaintHelper
{
public:
PaintHelper( const QskGraphic& graphic, const QskColorFilter& filter )
: m_graphic( graphic )
, m_filter( filter )
{
}
const uint textureId = createTextureFromGraphic(
window, QskTextureRenderer::OpenGL, m_size, m_graphic, m_colorFilter,
Qt::IgnoreAspectRatio );
void paint( QPainter* painter, const QSize& size ) override
{
const QRect rect( 0, 0, size.width(), size.height() );
m_graphic.render( painter, rect, m_filter );
}
return textureFromId( window, textureId, m_size );
private:
const QskGraphic& m_graphic;
const QskColorFilter& m_filter;
};
PaintHelper helper( m_graphic, m_colorFilter );
return QskTextureRenderer::createPaintedTexture( window, m_size, &helper );
}
QSize QskGraphicTextureFactory::textureSize() const

View File

@ -4,7 +4,19 @@
*****************************************************************************/
#include "QskArcNode.h"
#include "QskArcMetrics.h"
#include "QskArcRenderer.h"
#include "QskGradient.h"
namespace
{
class ArcData
{
public:
const QskArcMetrics& metrics;
const QskGradient& gradient;
};
}
QskArcNode::QskArcNode()
{
@ -17,26 +29,28 @@ QskArcNode::~QskArcNode()
void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& metrics,
const QskGradient& gradient, QQuickWindow* window )
{
m_metrics = metrics;
m_gradient = gradient;
update( window, QskTextureRenderer::AutoDetect, rect.toRect() );
const ArcData arcData { metrics, gradient };
update( window, rect, QSizeF(), &arcData );
}
void QskArcNode::paint( QPainter* painter, const QSizeF& size )
void QskArcNode::paint( QPainter* painter, const QSize& size, const void* nodeData )
{
const qreal w = m_metrics.width();
const auto arcData = reinterpret_cast< const ArcData* >( nodeData );
const qreal w = arcData->metrics.width();
const QRectF rect( 0.5 * w, 0.5 * w, size.width() - w, size.height() - w );
QskArcRenderer renderer;
renderer.renderArc( rect, m_metrics, m_gradient, painter );
renderer.renderArc( rect, arcData->metrics, arcData->gradient, painter );
}
QskHashValue QskArcNode::hash() const
QskHashValue QskArcNode::hash( const void* nodeData ) const
{
auto h = m_metrics.hash();
const auto arcData = reinterpret_cast< const ArcData* >( nodeData );
for( const auto& stop : qAsConst( m_gradient.stops() ) )
auto h = arcData->metrics.hash();
for( const auto& stop : qAsConst( arcData->gradient.stops() ) )
h = stop.hash( h );
return h;

View File

@ -6,10 +6,13 @@
#ifndef QSK_ARC_NODE_H
#define QSK_ARC_NODE_H
#include "QskArcMetrics.h"
#include "QskGradient.h"
#include "QskPaintedNode.h"
class QskArcMetrics;
class QskGradient;
// should be a QSGGeometryNode, TODO ..
class QSK_EXPORT QskArcNode : public QskPaintedNode
{
public:
@ -19,12 +22,9 @@ class QSK_EXPORT QskArcNode : public QskPaintedNode
void setArcData( const QRectF&, const QskArcMetrics&,
const QskGradient&, QQuickWindow* );
void paint( QPainter* painter, const QSizeF& size ) override;
QskHashValue hash() const override;
private:
QskArcMetrics m_metrics;
QskGradient m_gradient;
protected:
void paint( QPainter*, const QSize&, const void* nodeData ) override;
QskHashValue hash( const void* nodeData ) const override;
};
#endif

View File

@ -8,27 +8,17 @@
#include "QskColorFilter.h"
#include "QskPainterCommand.h"
static inline QskHashValue qskHash(
const QskGraphic& graphic, const QskColorFilter& colorFilter,
QskTextureRenderer::RenderMode renderMode )
namespace
{
QskHashValue hash = 12000;
const auto& substitutions = colorFilter.substitutions();
if ( substitutions.size() > 0 )
class GraphicData
{
hash = qHashBits( substitutions.constData(),
substitutions.size() * sizeof( substitutions[ 0 ] ), hash );
}
hash = graphic.hash( hash );
hash = qHash( renderMode, hash );
return hash;
public:
const QskGraphic& graphic;
const QskColorFilter& colorFilter;
};
}
QskGraphicNode::QskGraphicNode()
: m_hash( 0 )
{
}
@ -36,14 +26,10 @@ QskGraphicNode::~QskGraphicNode()
{
}
void QskGraphicNode::setGraphic(
QQuickWindow* window, const QskGraphic& graphic, const QskColorFilter& colorFilter,
QskTextureRenderer::RenderMode renderMode, const QRectF& rect,
Qt::Orientations mirrored )
void QskGraphicNode::setGraphic( QQuickWindow* window, const QskGraphic& graphic,
const QskColorFilter& colorFilter, const QRectF& rect )
{
bool isTextureDirty = isNull();
QSize textureSize;
QSizeF size;
if ( graphic.commandTypes() == QskGraphic::RasterData )
{
@ -52,34 +38,43 @@ void QskGraphicNode::setGraphic(
There is no benefit in rescaling it into the target rectangle
by the CPU and creating a new texture.
*/
textureSize = graphic.defaultSize().toSize();
}
else
{
textureSize = rect.size().toSize();
if ( !isTextureDirty )
{
const auto oldRect = QskTextureNode::rect();
isTextureDirty = ( rect.width() != static_cast< int >( oldRect.width() ) ) ||
( rect.height() != static_cast< int >( oldRect.height() ) );
}
size = graphic.defaultSize();
}
const auto hash = qskHash( graphic, colorFilter, renderMode );
if ( hash != m_hash )
{
m_hash = hash;
isTextureDirty = true;
}
auto textureId = QskTextureNode::textureId();
if ( isTextureDirty )
{
textureId = QskTextureRenderer::createTextureFromGraphic(
window, renderMode, textureSize, graphic, colorFilter, Qt::IgnoreAspectRatio );
}
QskTextureNode::setTexture( window, rect, textureId, mirrored );
const GraphicData graphicData { graphic, colorFilter };
update( window, rect, size, &graphicData );
}
void QskGraphicNode::paint( QPainter* painter, const QSize& size, const void* nodeData )
{
const auto graphicData = reinterpret_cast< const GraphicData* >( nodeData );
const auto& graphic = graphicData->graphic;
const auto& colorFilter = graphicData->colorFilter;
if ( graphic.commandTypes() == QskGraphic::RasterData )
{
qDebug() << size;
}
const QRectF rect( 0, 0, size.width(), size.height() );
graphic.render( painter, rect, colorFilter, Qt::IgnoreAspectRatio );
}
QskHashValue QskGraphicNode::hash( const void* nodeData ) const
{
const auto graphicData = reinterpret_cast< const GraphicData* >( nodeData );
const auto& graphic = graphicData->graphic;
QskHashValue hash = 12000;
const auto& substitutions = graphicData->colorFilter.substitutions();
if ( substitutions.size() > 0 )
{
hash = qHashBits( substitutions.constData(),
substitutions.size() * sizeof( substitutions[ 0 ] ), hash );
}
return graphic.hash( hash );
}

View File

@ -6,29 +6,23 @@
#ifndef QSK_GRAPHIC_NODE_H
#define QSK_GRAPHIC_NODE_H
#include "QskTextureRenderer.h"
#include "QskTextureNode.h"
#include "QskPaintedNode.h"
class QskGraphic;
class QskColorFilter;
class QQuickWindow;
class QSK_EXPORT QskGraphicNode : public QskTextureNode
class QSK_EXPORT QskGraphicNode : public QskPaintedNode
{
public:
QskGraphicNode();
~QskGraphicNode() override;
void setGraphic( QQuickWindow*,
const QskGraphic&, const QskColorFilter&,
QskTextureRenderer::RenderMode, const QRectF&,
Qt::Orientations mirrored = Qt::Orientations() );
void setGraphic( QQuickWindow*, const QskGraphic&,
const QskColorFilter&, const QRectF& );
private:
void setTexture( QQuickWindow*,
const QRectF&, uint id, Qt::Orientations ) = delete;
QskHashValue m_hash;
virtual void paint( QPainter*, const QSize&, const void* nodeData ) override;
virtual QskHashValue hash( const void* nodeData ) const override;
};
#endif

View File

@ -4,24 +4,44 @@
*****************************************************************************/
#include "QskPaintedNode.h"
#include "QskSGNode.h"
#include "QskTextureRenderer.h"
class QskPaintedNode::PaintHelper : public QskTextureRenderer::PaintHelper
#include <qsgimagenode.h>
#include <qquickwindow.h>
#include <qimage.h>
#include <qpainter.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgplaintexture_p.h>
QSK_QT_PRIVATE_END
static inline QSGImageNode::TextureCoordinatesTransformMode
qskEffectiveTransformMode( const Qt::Orientations mirrored )
{
public:
inline PaintHelper( QskPaintedNode* node )
: m_node( node )
{
}
QSGImageNode::TextureCoordinatesTransformMode mode;
void paint( QPainter* painter, const QSize& size ) override
{
m_node->paint( painter, size );
}
if ( mirrored & Qt::Vertical )
mode |= QSGImageNode::MirrorVertically;
private:
QskPaintedNode* m_node;
};
if ( mirrored & Qt::Horizontal )
mode |= QSGImageNode::MirrorHorizontally;
return mode;
}
namespace
{
const quint8 imageRole = 250; // reserved for internal use
inline QSGImageNode* findImageNode( const QSGNode* parentNode )
{
auto node = QskSGNode::findChildNode(
const_cast< QSGNode* >( parentNode ), imageRole );
return static_cast< QSGImageNode* >( node );
}
}
QskPaintedNode::QskPaintedNode()
{
@ -31,33 +51,185 @@ QskPaintedNode::~QskPaintedNode()
{
}
void QskPaintedNode::update( QQuickWindow* window,
QskTextureRenderer::RenderMode renderMode, const QRect& rect )
void QskPaintedNode::setRenderHint( RenderHint renderHint )
{
bool isTextureDirty = isNull();
m_renderHint = renderHint;
}
if ( !isTextureDirty )
QskPaintedNode::RenderHint QskPaintedNode::renderHint() const
{
return m_renderHint;
}
void QskPaintedNode::setMirrored( Qt::Orientations orientations )
{
if ( orientations != m_mirrored )
{
const auto oldRect = QskTextureNode::rect();
isTextureDirty = ( rect.width() != static_cast< int >( oldRect.width() ) ) ||
( rect.height() != static_cast< int >( oldRect.height() ) );
m_mirrored = orientations;
if ( auto imageNode = findImageNode( this ) )
{
imageNode->setTextureCoordinatesTransform(
qskEffectiveTransformMode( orientations ) );
}
}
}
Qt::Orientations QskPaintedNode::mirrored() const
{
return m_mirrored;
}
QSize QskPaintedNode::textureSize() const
{
if ( const auto imageNode = findImageNode( this ) )
{
if ( auto texture = imageNode->texture() )
return texture->textureSize();
}
const auto newHash = hash();
return QSize();
}
QRectF QskPaintedNode::rect() const
{
const auto imageNode = findImageNode( this );
return imageNode ? imageNode->rect() : QRectF();
}
void QskPaintedNode::update( QQuickWindow* window,
const QRectF& rect, const QSizeF& size, const void* nodeData )
{
auto imageNode = findImageNode( this );
if ( rect.isEmpty() )
{
if ( imageNode )
{
removeChildNode( imageNode );
delete imageNode;
}
return;
}
if ( imageNode == nullptr )
{
imageNode = window->createImageNode();
imageNode->setOwnsTexture( true );
QskSGNode::setNodeRole( imageNode, imageRole );
appendChildNode( imageNode );
}
QSize imageSize;
{
auto scaledSize = size.isEmpty() ? rect.size() : size;
scaledSize *= window->effectiveDevicePixelRatio();
imageSize = scaledSize.toSize();
}
bool isTextureDirty = false;
const auto newHash = hash( nodeData );
if ( ( newHash == 0 ) || ( newHash != m_hash ) )
{
m_hash = newHash;
isTextureDirty = true;
}
auto textureId = QskTextureNode::textureId();
if ( isTextureDirty )
else
{
PaintHelper helper( this );
textureId = QskTextureRenderer::createTexture(
window, renderMode, rect.size(), &helper );
isTextureDirty = ( imageSize != textureSize() );
}
QskTextureNode::setTexture( window, rect, textureId );
if ( isTextureDirty )
updateTexture( window, imageSize, nodeData );
imageNode->setRect( rect );
imageNode->setTextureCoordinatesTransform(
qskEffectiveTransformMode( m_mirrored ) );
}
void QskPaintedNode::updateTexture( QQuickWindow* window,
const QSize& size, const void* nodeData )
{
auto imageNode = findImageNode( this );
if ( ( m_renderHint == OpenGL ) && QskTextureRenderer::isOpenGLWindow( window ) )
{
const auto textureId = createTextureGL( window, size, nodeData );
auto texture = qobject_cast< QSGPlainTexture* >( imageNode->texture() );
if ( texture == nullptr )
{
texture = new QSGPlainTexture;
texture->setHasAlphaChannel( true );
texture->setOwnsTexture( true );
imageNode->setTexture( texture );
}
QskTextureRenderer::setTextureId( window, textureId, size, texture );
}
else
{
const auto image = createImage( window, size, nodeData );
if ( auto texture = qobject_cast< QSGPlainTexture* >( imageNode->texture() ) )
texture->setImage( image );
else
imageNode->setTexture( window->createTextureFromImage( image ) );
}
}
QImage QskPaintedNode::createImage( QQuickWindow* window,
const QSize& size, const void* nodeData )
{
QImage image( size, QImage::Format_RGBA8888_Premultiplied );
image.fill( Qt::transparent );
QPainter painter( &image );
/*
setting a devicePixelRatio for the image only works for
value >= 1.0. So we have to scale manually.
*/
const auto ratio = window->effectiveDevicePixelRatio();
painter.scale( ratio, ratio );
paint( &painter, size / ratio, nodeData );
painter.end();
return image;
}
quint32 QskPaintedNode::createTextureGL(
QQuickWindow* window, const QSize& size, const void* nodeData )
{
class PaintHelper : public QskTextureRenderer::PaintHelper
{
public:
PaintHelper( QskPaintedNode* node, const void* nodeData )
: m_node( node )
, m_nodeData( nodeData )
{
}
void paint( QPainter* painter, const QSize& size ) override
{
m_node->paint( painter, size, m_nodeData );
}
private:
QskPaintedNode* m_node;
const void* m_nodeData;
};
PaintHelper helper( this, nodeData );
return createPaintedTextureGL( window, size, &helper );
}

View File

@ -6,31 +6,62 @@
#ifndef QSK_PAINTED_NODE_H
#define QSK_PAINTED_NODE_H
#include "QskTextureNode.h"
#include "QskTextureRenderer.h"
#include "QskGlobal.h"
#include <qsgnode.h>
class QSK_EXPORT QskPaintedNode : public QskTextureNode
class QQuickWindow;
class QPainter;
class QImage;
class QSK_EXPORT QskPaintedNode : public QSGNode
{
public:
/*
Raster usually provides a better antialiasing and is less buggy,
while OpenGL might be faster - depending on the content that has
to be painted.
Since Qt 5.10 X11 is back and could be an interesting option
with good quality and hardware accelerated performance. TODO ...
OpenGL might be ignored depending on the backend used by the
application.
*/
enum RenderHint
{
Raster,
OpenGL
};
QskPaintedNode();
~QskPaintedNode() override;
void update( QQuickWindow*,
QskTextureRenderer::RenderMode, const QRect& );
void setRenderHint( RenderHint );
RenderHint renderHint() const;
void setMirrored( Qt::Orientations );
Qt::Orientations mirrored() const;
QRectF rect() const;
QSize textureSize() const;
virtual void paint( QPainter*, const QSize&, const void* nodeData ) = 0;
protected:
virtual void paint( QPainter*, const QSizeF& ) = 0;
void update( QQuickWindow*, const QRectF&, const QSizeF&, const void* nodeData );
// a hash value of '0' always results in repainting
virtual QskHashValue hash() const = 0;
virtual QskHashValue hash( const void* nodeData ) const = 0;
private:
class PaintHelper;
void updateTexture( QQuickWindow*, const QSize&, const void* nodeData );
void setTexture( QQuickWindow*,
const QRectF&, uint id, Qt::Orientations ) = delete;
QImage createImage( QQuickWindow*, const QSize&, const void* nodeData );
quint32 createTextureGL( QQuickWindow*, const QSize&, const void* nodeData );
QskHashValue m_hash;
RenderHint m_renderHint = OpenGL;
Qt::Orientations m_mirrored;
QskHashValue m_hash = 0;
};
#endif

View File

@ -1,393 +0,0 @@
#include "QskTextureNode.h"
#include "QskFunctions.h"
#include <qopenglfunctions.h>
#include <qsggeometry.h>
#include <qsgmaterial.h>
#include <qquickwindow.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
QSK_QT_PRIVATE_END
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
#include <qsgtexture.h>
#include <qsgtexturematerial.h>
#include <qsgtexture_platform.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qrhi_p.h>
#include <private/qrhigles2_p_p.h>
QSK_QT_PRIVATE_END
static void qskUpdateGLTextureId( QRhiTexture* rhiTexture, uint textureId )
{
// hack time: we do not want to create a new QSGTexture object for each texture
class Texture : public QRhiTexture
{
public:
GLuint texture;
// ...
};
GLuint id = rhiTexture->nativeTexture().object;
if ( id )
{
auto funcs = QOpenGLContext::currentContext()->functions();
funcs->glDeleteTextures( 1, &id );
}
auto glTexture = static_cast< Texture* >( rhiTexture );
glTexture->texture = textureId;
Q_ASSERT( rhiTexture->nativeTexture().object == textureId );
}
using TextureMaterial = QSGTextureMaterial;
using OpaqueTextureMaterial = QSGOpaqueTextureMaterial;
static inline void qskDeleteTexture( const TextureMaterial& material )
{
delete material.texture();
}
#endif
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
namespace
{
class MaterialShader final : public QSGMaterialShader
{
public:
MaterialShader( bool isOpaque );
char const* const* attributeNames() const override;
void updateState( const RenderState&, QSGMaterial*, QSGMaterial* ) override;
protected:
void initialize() override;
private:
int m_matrixId = -1;
int m_opacityId = -1;
const bool m_isOpaque : 1;
};
class Material : public QSGMaterial
{
public:
Material( bool isOpaque );
QSGMaterialType* type() const override;
QSGMaterialShader* createShader() const override;
void setTextureId( uint );
uint textureId() const;
int compare( const QSGMaterial* ) const override;
private:
uint m_textureId = 0;
const bool m_isOpaque : 1;
};
class TextureMaterial final : public Material
{
public:
TextureMaterial()
: Material( false )
{
}
};
class OpaqueTextureMaterial final : public Material
{
public:
OpaqueTextureMaterial()
: Material( true )
{
}
};
MaterialShader::MaterialShader( bool isOpaque )
: m_isOpaque( isOpaque )
{
setShaderSourceFile( QOpenGLShader::Vertex,
QStringLiteral( ":/qt-project.org/scenegraph/shaders/opaquetexture.vert" ) );
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 );
}
char const* const* MaterialShader::attributeNames() const
{
static char const* const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 };
return attr;
}
void MaterialShader::updateState(
const RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial )
{
if ( !m_isOpaque && state.isOpacityDirty() )
program()->setUniformValue( m_opacityId, state.opacity() );
auto* materialOld = static_cast< Material* >( oldMaterial );
auto* materialNew = static_cast< Material* >( newMaterial );
if ( ( materialOld == nullptr ) ||
( materialOld->textureId() != materialNew->textureId() ) )
{
auto funcs = QOpenGLContext::currentContext()->functions();
funcs->glBindTexture( GL_TEXTURE_2D, materialNew->textureId() );
}
if ( state.isMatrixDirty() )
program()->setUniformValue( m_matrixId, state.combinedMatrix() );
}
void MaterialShader::initialize()
{
m_matrixId = program()->uniformLocation( "qt_Matrix" );
if ( !m_isOpaque )
m_opacityId = program()->uniformLocation( "opacity" );
}
Material::Material( bool isOpaque )
: m_isOpaque( isOpaque )
{
setFlag( Blending, true ); // alpha blending
}
void Material::setTextureId( uint id )
{
m_textureId = id;
}
uint Material::textureId() const
{
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 );
if ( m_textureId == otherMaterial->m_textureId )
return 0;
return ( m_textureId > otherMaterial->m_textureId ) ? 1 : -1;
}
}
static inline void qskDeleteTexture( const TextureMaterial& material )
{
if ( material.textureId() > 0 )
{
/*
In certain environments we have the effect, that at
program termination the context is already gone
*/
if ( auto context = QOpenGLContext::currentContext() )
{
GLuint id = material.textureId();
auto funcs = context->functions();
funcs->glDeleteTextures( 1, &id );
}
}
}
#endif
class QskTextureNodePrivate final : public QSGGeometryNodePrivate
{
public:
QskTextureNodePrivate()
: geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 )
{
}
void setTextureId( QQuickWindow*, uint id );
void updateTextureGeometry()
{
QRectF r( 0, 0, 1, 1 );
if ( this->mirrored & Qt::Horizontal )
{
r.setLeft( 1 );
r.setRight( 0 );
}
if ( mirrored & Qt::Vertical )
{
r.setTop( 1 );
r.setBottom( 0 );
}
QSGGeometry::updateTexturedRectGeometry( &geometry, rect, r );
}
QSGGeometry geometry;
OpaqueTextureMaterial opaqueMaterial;
TextureMaterial material;
QRectF rect;
Qt::Orientations mirrored;
};
QskTextureNode::QskTextureNode()
: QSGGeometryNode( *new QskTextureNodePrivate )
{
Q_D( QskTextureNode );
setGeometry( &d->geometry );
setMaterial( &d->material );
setOpaqueMaterial( &d->opaqueMaterial );
}
QskTextureNode::~QskTextureNode()
{
Q_D( const QskTextureNode );
qskDeleteTexture( d->material );
}
void QskTextureNode::setTexture( QQuickWindow* window,
const QRectF& rect, uint textureId,
Qt::Orientations mirrored )
{
Q_D( QskTextureNode );
if ( ( d->rect != rect ) || ( d->mirrored != mirrored ) )
{
d->rect = rect;
d->mirrored = mirrored;
d->updateTextureGeometry();
markDirty( DirtyGeometry );
}
if ( textureId != this->textureId() )
{
d->setTextureId( window, textureId );
markDirty( DirtyMaterial );
}
}
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
void QskTextureNodePrivate::setTextureId( QQuickWindow*, uint textureId )
{
qskDeleteTexture( this->material );
this->material.setTextureId( textureId );
this->opaqueMaterial.setTextureId( textureId );
}
uint QskTextureNode::textureId() const
{
Q_D( const QskTextureNode );
return d->material.textureId();
}
#endif
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
void QskTextureNodePrivate::setTextureId( QQuickWindow* window, uint textureId )
{
auto texture = this->material.texture();
if ( texture )
{
// we do not want to create a new QSGTexture object only
// to replace the textureId
switch( window->rendererInterface()->graphicsApi() )
{
case QSGRendererInterface::OpenGL:
{
qskUpdateGLTextureId( texture->rhiTexture(), textureId );
break;
}
default:
{
delete texture;
texture = nullptr;
}
}
}
if ( textureId > 0 && texture == nullptr )
{
texture = QNativeInterface::QSGOpenGLTexture::fromNative(
static_cast< GLuint >( textureId ), window,
this->rect.size().toSize(), QQuickWindow::TextureHasAlphaChannel );
}
this->material.setTexture( texture );
this->opaqueMaterial.setTexture( texture );
}
uint QskTextureNode::textureId() const
{
Q_D( const QskTextureNode );
if ( auto texture = d->material.texture() )
{
const auto nativeTexture = texture->rhiTexture()->nativeTexture();
return nativeTexture.object;
}
return 0;
}
#endif
bool QskTextureNode::isNull() const
{
return textureId() == 0;
}
QRectF QskTextureNode::rect() const
{
Q_D( const QskTextureNode );
return d->rect;
}
Qt::Orientations QskTextureNode::mirrored() const
{
Q_D( const QskTextureNode );
return d->mirrored;
}

View File

@ -1,36 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#ifndef QSK_TEXTURE_NODE_H
#define QSK_TEXTURE_NODE_H
#include "QskGlobal.h"
#include <qnamespace.h>
#include <qsgnode.h>
class QQuickWindow;
class QskTextureNodePrivate;
class QSK_EXPORT QskTextureNode : public QSGGeometryNode
{
public:
QskTextureNode();
~QskTextureNode() override;
bool isNull() const;
void setTexture( QQuickWindow*, const QRectF&, uint id,
Qt::Orientations mirrored = Qt::Orientations() );
uint textureId() const;
QRectF rect() const;
Qt::Orientations mirrored() const;
private:
Q_DECLARE_PRIVATE( QskTextureNode )
};
#endif

View File

@ -4,92 +4,178 @@
*****************************************************************************/
#include "QskTextureRenderer.h"
#include "QskColorFilter.h"
#include "QskGraphic.h"
#include "QskSetup.h"
#include <qopenglcontext.h>
#include <qopenglextrafunctions.h>
#include <qopenglframebufferobject.h>
#include <qopenglfunctions.h>
#include <qopenglpaintdevice.h>
#include <qopengltexture.h>
#include <qimage.h>
#include <qpainter.h>
#include <qquickwindow.h>
#include <qsgtexture.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgplaintexture_p.h>
#include <private/qopenglframebufferobject_p.h>
#include <private/qquickwindow_p.h>
QSK_QT_PRIVATE_END
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
#include <qsgtexture_platform.h>
#include <qquickopenglutils.h>
#endif
static inline bool qskHasOpenGLRenderer( const QQuickWindow* window )
static GLuint qskTakeTexture( QOpenGLFramebufferObject& fbo )
{
/*
See https://bugreports.qt.io/browse/QTBUG-103929
As we create a FBO for each update of a node we can't live
without having this ( ugly ) workaround.
*/
class MyFBO
{
public:
virtual ~MyFBO() = default;
QScopedPointer< QOpenGLFramebufferObjectPrivate > d_ptr;
};
static_assert( sizeof( MyFBO ) == sizeof( QOpenGLFramebufferObject ),
"Bad cast: QOpenGLFramebufferObject does not match" );
auto& attachment = reinterpret_cast< MyFBO* >( &fbo )->d_ptr->colorAttachments[0];
auto guard = attachment.guard;
const auto textureId = fbo.takeTexture();
if ( guard )
{
class MyGuard : public QOpenGLSharedResourceGuard
{
public:
void invalidateTexture() { invalidateResource(); }
};
reinterpret_cast< MyGuard* >( guard )->invalidateTexture();
}
attachment.guard = guard;
return textureId;
}
bool QskTextureRenderer::isOpenGLWindow( const QQuickWindow* window )
{
if ( window == nullptr )
return false;
const auto renderer = window->rendererInterface();
return renderer->graphicsApi() == QSGRendererInterface::OpenGL;
switch( renderer->graphicsApi() )
{
case QSGRendererInterface::OpenGL:
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
case QSGRendererInterface::OpenGLRhi:
#endif
return true;
default:
return false;
}
}
static uint qskCreateTextureOpenGL( QQuickWindow* window,
const QSize& size, QskTextureRenderer::PaintHelper* helper )
void QskTextureRenderer::setTextureId( QQuickWindow* window,
quint32 textureId, const QSize& size, QSGTexture* texture )
{
const auto ratio = window ? window->effectiveDevicePixelRatio() : 1.0;
auto plainTexture = qobject_cast< QSGPlainTexture* >( texture );
if ( plainTexture == nullptr )
return;
const int width = ratio * size.width();
const int height = ratio * size.height();
auto rhi = QQuickWindowPrivate::get( window )->rhi;
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
plainTexture->setTextureFromNativeTexture(
rhi, quint64( textureId ), 0, size, {}, {} );
#else
if ( rhi )
{
// enabled with: "export QSG_RHI=1"
plainTexture->setTextureFromNativeObject( rhi,
QQuickWindow::NativeObjectTexture, &textureId, 0, size, false );
}
else
{
plainTexture->setTextureId( textureId );
plainTexture->setTextureSize( size );
}
#endif
}
quint32 QskTextureRenderer::createPaintedTextureGL(
QQuickWindow* window, const QSize& size, QskTextureRenderer::PaintHelper* helper )
{
/*
Binding GL_ARRAY_BUFFER/GL_ELEMENT_ARRAY_BUFFER to 0 seems to be enough.
However - as we do not know what is finally painted and what the
OpenGL paint engine is doing with better reinitialize everything.
Hope this has no side effects as the context will leave the function
in a modified state. Otherwise we could try to change the buffers
only and reset them, before leaving.
QQuickFramebufferObject does the FBO rendering early
( QQuickWindow::beforeRendering ). But so far doing it below updatePaintNode
seems to work as well. Let's see if we run into issues ...
*/
window->beginExternalCommands();
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
QQuickOpenGLUtils::resetOpenGLState();
#else
window->resetOpenGLState();
#endif
auto context = QOpenGLContext::currentContext();
QOpenGLFramebufferObjectFormat format1;
format1.setAttachment( QOpenGLFramebufferObject::CombinedDepthStencil );
// ### TODO: get samples from window instead
format1.setSamples( QOpenGLContext::currentContext()->format().samples() );
format1.setSamples( context->format().samples() );
QOpenGLFramebufferObject multisampledFbo( width, height, format1 );
QOpenGLFramebufferObject multisampledFbo( size, format1 );
QOpenGLPaintDevice pd( width, height );
QOpenGLPaintDevice pd( size );
pd.setPaintFlipped( true );
{
QPainter painter( &pd );
painter.scale( ratio, ratio );
painter.setCompositionMode( QPainter::CompositionMode_Source );
painter.fillRect( 0, 0, width, height, Qt::transparent );
painter.fillRect( 0, 0, size.width(), size.height(), Qt::transparent );
painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
helper->paint( &painter, size );
const auto ratio = window->effectiveDevicePixelRatio();
#if 1
if ( format1.samples() > 0 )
{
/*
Multisampling in the window surface might get lost
as a side effect of rendering to the FBO.
weired, needs to be investigated more
*/
painter.setRenderHint( QPainter::Antialiasing, true );
}
#endif
painter.scale( ratio, ratio );
helper->paint( &painter, size / ratio );
}
QOpenGLFramebufferObjectFormat format2;
format2.setAttachment( QOpenGLFramebufferObject::NoAttachment );
QOpenGLFramebufferObject fbo( width, height, format2 );
QOpenGLFramebufferObject fbo( size, format2 );
const QRect fboRect( 0, 0, width, height );
const QRect fboRect( 0, 0, size.width(), size.height() );
QOpenGLFramebufferObject::blitFramebuffer(
&fbo, fboRect, &multisampledFbo, fboRect );
return fbo.takeTexture();
window->endExternalCommands();
return qskTakeTexture( fbo );
}
static uint qskCreateTextureRaster( QQuickWindow* window,
static QSGTexture* qskCreateTextureRaster( QQuickWindow* window,
const QSize& size, QskTextureRenderer::PaintHelper* helper )
{
const auto ratio = window ? window->effectiveDevicePixelRatio() : 1.0;
@ -109,130 +195,26 @@ static uint qskCreateTextureRaster( QQuickWindow* window,
helper->paint( &painter, size );
}
const auto target = QOpenGLTexture::Target2D;
return window->createTextureFromImage( image, QQuickWindow::TextureHasAlphaChannel );
}
auto context = QOpenGLContext::currentContext();
if ( context == nullptr )
return 0;
auto& f = *context->functions();
GLint oldTexture; // we can't rely on having OpenGL Direct State Access
f.glGetIntegerv( QOpenGLTexture::BindingTarget2D, &oldTexture );
GLuint textureId;
f.glGenTextures( 1, &textureId );
f.glBindTexture( target, textureId );
f.glTexParameteri( target, GL_TEXTURE_MIN_FILTER, QOpenGLTexture::Nearest );
f.glTexParameteri( target, GL_TEXTURE_MAG_FILTER, QOpenGLTexture::Nearest );
f.glTexParameteri( target, GL_TEXTURE_WRAP_S, QOpenGLTexture::ClampToEdge );
f.glTexParameteri( target, GL_TEXTURE_WRAP_T, QOpenGLTexture::ClampToEdge );
if ( QOpenGLTexture::hasFeature( QOpenGLTexture::ImmutableStorage ) )
QSGTexture* QskTextureRenderer::createPaintedTexture(
QQuickWindow* window, const QSize& size, PaintHelper* helper )
{
if ( isOpenGLWindow( window ) )
{
auto& ef = *context->extraFunctions();
ef.glTexStorage2D( target, 1,
QOpenGLTexture::RGBA8_UNorm, image.width(), image.height() );
const auto textureId = createPaintedTextureGL( window, size, helper );
f.glTexSubImage2D( target, 0, 0, 0, image.width(), image.height(),
QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.constBits() );
auto texture = new QSGPlainTexture;
texture->setHasAlphaChannel( true );
texture->setOwnsTexture( true );
setTextureId( window, textureId, size, texture );
return texture;
}
else
{
f.glTexImage2D( target, 0, QOpenGLTexture::RGBA8_UNorm,
image.width(), image.height(), 0,
QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.constBits() );
}
f.glBindTexture( target, oldTexture );
return textureId;
}
QSGTexture* QskTextureRenderer::textureFromId(
QQuickWindow* window, uint textureId, const QSize& size )
{
const auto flags = static_cast< QQuickWindow::CreateTextureOptions >(
QQuickWindow::TextureHasAlphaChannel | QQuickWindow::TextureOwnsGLTexture );
QSGTexture* texture;
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
texture = QNativeInterface::QSGOpenGLTexture::fromNative(
textureId, window, size, flags );
#else
const int nativeLayout = 0; // VkImageLayout in case of Vulkan
texture = window->createTextureFromNativeObject(
QQuickWindow::NativeObjectTexture, &textureId, nativeLayout, size, flags );
#endif
return texture;
}
uint QskTextureRenderer::createTexture(
QQuickWindow* window, RenderMode renderMode,
const QSize& size, PaintHelper* helper )
{
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
// Qt6.0.0 is buggy when using FBOs. So let's disable it for the moment TODO ...
renderMode = Raster;
#endif
if ( renderMode != Raster )
{
if ( !qskHasOpenGLRenderer( window ) )
renderMode = Raster;
}
if ( renderMode == AutoDetect )
{
if ( qskSetup->testItemUpdateFlag( QskQuickItem::PreferRasterForTextures ) )
renderMode = Raster;
else
renderMode = OpenGL;
}
if ( renderMode == Raster )
return qskCreateTextureRaster( window, size, helper );
else
return qskCreateTextureOpenGL( window, size, helper );
}
uint QskTextureRenderer::createTextureFromGraphic(
QQuickWindow* window, RenderMode renderMode, const QSize& size,
const QskGraphic& graphic, const QskColorFilter& colorFilter,
Qt::AspectRatioMode aspectRatioMode )
{
class PaintHelper : public QskTextureRenderer::PaintHelper
{
public:
PaintHelper( const QskGraphic& graphic,
const QskColorFilter& filter, Qt::AspectRatioMode aspectRatioMode )
: m_graphic( graphic )
, m_filter( filter )
, m_aspectRatioMode( aspectRatioMode )
{
}
void paint( QPainter* painter, const QSize& size ) override
{
const QRect rect( 0, 0, size.width(), size.height() );
m_graphic.render( painter, rect, m_filter, m_aspectRatioMode );
}
private:
const QskGraphic& m_graphic;
const QskColorFilter& m_filter;
const Qt::AspectRatioMode m_aspectRatioMode;
};
PaintHelper helper( graphic, colorFilter, aspectRatioMode );
return createTexture( window, renderMode, size, &helper );
}
}

View File

@ -7,35 +7,15 @@
#define QSK_TEXTURE_RENDERER_H
#include "QskGlobal.h"
#include <qnamespace.h>
class QskGraphic;
class QskColorFilter;
class QPainter;
class QSize;
class QPainter;
class QSGTexture;
class QQuickWindow;
namespace QskTextureRenderer
{
/*
Raster usually provides a better antialiasing and is less buggy,
while OpenGL might be faster - depending on the content that has
to be painted.
Since Qt 5.10 X11 is back and could be an interesting option
with good quality and hardware accelerated performance. TODO ...
*/
enum RenderMode
{
AutoDetect, // depends on QskSetup::controlFlags()
Raster,
OpenGL
};
class QSK_EXPORT PaintHelper
class PaintHelper
{
public:
PaintHelper() = default;
@ -47,15 +27,16 @@ namespace QskTextureRenderer
Q_DISABLE_COPY( PaintHelper )
};
QSK_EXPORT uint createTexture(
QQuickWindow*, RenderMode, const QSize&, PaintHelper* );
bool isOpenGLWindow( const QQuickWindow* );
QSK_EXPORT uint createTextureFromGraphic(
QQuickWindow*, RenderMode, const QSize&, const QskGraphic&,
const QskColorFilter&, Qt::AspectRatioMode );
void setTextureId( QQuickWindow*,
quint32 textureId, const QSize&, QSGTexture* );
QSK_EXPORT QSGTexture* textureFromId(
QQuickWindow*, uint textureId, const QSize& );
quint32 createPaintedTextureGL(
QQuickWindow*, const QSize&, QskTextureRenderer::PaintHelper* );
QSK_EXPORT QSGTexture* createPaintedTexture(
QQuickWindow* window, const QSize& size, PaintHelper* helper );
}
#endif

View File

@ -3,6 +3,10 @@ TARGET = $$qskLibraryTarget(qskinny)
QT += quick quick-private
greaterThan( QT_MAJOR_VERSION, 5 ) {
QT += opengl-private
}
contains(QSK_CONFIG, QskDll): DEFINES += QSK_MAKEDLL
QSK_SUBDIRS = common graphic nodes controls layouts dialogs inputpanel
@ -107,7 +111,6 @@ HEADERS += \
nodes/QskSGNode.h \
nodes/QskTextNode.h \
nodes/QskTextRenderer.h \
nodes/QskTextureNode.h \
nodes/QskTextureRenderer.h \
nodes/QskTickmarksNode.h \
nodes/QskVertex.h
@ -128,7 +131,6 @@ SOURCES += \
nodes/QskSGNode.cpp \
nodes/QskTextNode.cpp \
nodes/QskTextRenderer.cpp \
nodes/QskTextureNode.cpp \
nodes/QskTextureRenderer.cpp \
nodes/QskTickmarksNode.cpp \
nodes/QskVertex.cpp

View File

@ -1,6 +0,0 @@
#!/bin/sh
LD_LIBRARY_PATH=/home/uwe/qskinny/config/qsk1/Qt/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
export LD_LIBRARY_PATH
QT_PLUGIN_PATH=/home/uwe/qskinny/config/qsk1/Qt/plugins${QT_PLUGIN_PATH:+:$QT_PLUGIN_PATH}
export QT_PLUGIN_PATH
exec "$@"