code moved to QskColorRamp
This commit is contained in:
parent
d327a68fc1
commit
974e7372dd
|
@ -0,0 +1,170 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "QskColorRamp.h"
|
||||||
|
#include "QskRgbValue.h"
|
||||||
|
|
||||||
|
QSK_QT_PRIVATE_BEGIN
|
||||||
|
#include <private/qrhi_p.h>
|
||||||
|
#include <private/qsgplaintexture_p.h>
|
||||||
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
|
#include <qcoreapplication.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class Texture : public QSGPlainTexture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Texture( const QskGradientStops& stops, QGradient::Spread spread )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Qt creates tables of 1024 colors, while Chrome, Firefox, and Android
|
||||||
|
seem to use 256 colors only ( according to maybe outdated sources
|
||||||
|
from the internet ),
|
||||||
|
*/
|
||||||
|
|
||||||
|
setImage( QskRgb::colorTable( 256, stops ) );
|
||||||
|
|
||||||
|
const auto wrapMode = this->wrapMode( spread );
|
||||||
|
|
||||||
|
setHorizontalWrapMode( wrapMode );
|
||||||
|
setVerticalWrapMode( wrapMode );
|
||||||
|
|
||||||
|
setFiltering( QSGTexture::Linear );
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline QSGTexture::WrapMode wrapMode( QGradient::Spread spread )
|
||||||
|
{
|
||||||
|
switch ( spread )
|
||||||
|
{
|
||||||
|
case QGradient::RepeatSpread:
|
||||||
|
return QSGTexture::Repeat;
|
||||||
|
|
||||||
|
case QGradient::ReflectSpread:
|
||||||
|
return QSGTexture::MirroredRepeat;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return QSGTexture::ClampToEdge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class HashKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline bool operator==( const HashKey& other ) const
|
||||||
|
{
|
||||||
|
return rhi == other.rhi && spread == other.spread && stops == other.stops;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* rhi;
|
||||||
|
const QskGradientStops stops;
|
||||||
|
const QGradient::Spread spread;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline size_t qHash( const HashKey& key, size_t seed = 0 )
|
||||||
|
{
|
||||||
|
size_t values = seed + key.spread;
|
||||||
|
|
||||||
|
for ( const auto& stop : key.stops )
|
||||||
|
values += stop.rgb();
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Cache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~Cache() { qDeleteAll( m_hashTable ); }
|
||||||
|
|
||||||
|
void cleanupRhi( const QRhi* );
|
||||||
|
|
||||||
|
Texture* texture( const void* rhi,
|
||||||
|
const QskGradientStops&, QGradient::Spread );
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash< HashKey, Texture* > m_hashTable;
|
||||||
|
QVector< const QRhi* > m_rhiTable; // no QSet: we usually have only one entry
|
||||||
|
};
|
||||||
|
|
||||||
|
static Cache* s_cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qskCleanupCache()
|
||||||
|
{
|
||||||
|
delete s_cache;
|
||||||
|
s_cache = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qskCleanupRhi( const QRhi* rhi )
|
||||||
|
{
|
||||||
|
if ( s_cache )
|
||||||
|
s_cache->cleanupRhi( rhi );
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture* Cache::texture( const void* rhi,
|
||||||
|
const QskGradientStops& stops, QGradient::Spread spread )
|
||||||
|
{
|
||||||
|
const HashKey key { rhi, stops, spread };
|
||||||
|
|
||||||
|
auto texture = m_hashTable[key];
|
||||||
|
if ( texture == nullptr )
|
||||||
|
{
|
||||||
|
texture = new Texture( stops, spread );
|
||||||
|
m_hashTable[ key ] = texture;
|
||||||
|
|
||||||
|
if ( rhi != nullptr )
|
||||||
|
{
|
||||||
|
auto myrhi = ( QRhi* )rhi;
|
||||||
|
|
||||||
|
if ( !m_rhiTable.contains( myrhi ) )
|
||||||
|
{
|
||||||
|
myrhi->addCleanupCallback( qskCleanupRhi );
|
||||||
|
m_rhiTable += myrhi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cache::cleanupRhi( const QRhi* rhi )
|
||||||
|
{
|
||||||
|
for ( auto it = m_hashTable.begin(); it != m_hashTable.end(); )
|
||||||
|
{
|
||||||
|
if ( it.key().rhi == rhi )
|
||||||
|
{
|
||||||
|
delete it.value();
|
||||||
|
it = m_hashTable.erase( it );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rhiTable.removeAll( rhi );
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGTexture* QskColorRamp::texture( const void* rhi,
|
||||||
|
const QskGradientStops& stops, QGradient::Spread spread )
|
||||||
|
{
|
||||||
|
if ( s_cache == nullptr )
|
||||||
|
{
|
||||||
|
s_cache = new Cache();
|
||||||
|
|
||||||
|
/*
|
||||||
|
For RHI we have QRhi::addCleanupCallback, but with
|
||||||
|
OpenGL we would have to fiddle around with QOpenGLSharedResource
|
||||||
|
But as the OpenGL path is only for Qt5 we do not want to spend
|
||||||
|
much energy on finetuning the resource management.
|
||||||
|
*/
|
||||||
|
qAddPostRoutine( qskCleanupCache );
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_cache->texture( rhi, stops, spread );
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_COLOR_RAMP_H
|
||||||
|
#define QSK_COLOR_RAMP_H
|
||||||
|
|
||||||
|
#include "QskGlobal.h"
|
||||||
|
#include "QskGradientStop.h"
|
||||||
|
|
||||||
|
#include <qbrush.h>
|
||||||
|
|
||||||
|
class QSGTexture;
|
||||||
|
|
||||||
|
namespace QskColorRamp
|
||||||
|
{
|
||||||
|
QSGTexture* texture( const void* rhi, const QskGradientStops&, QGradient::Spread );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -7,14 +7,15 @@
|
||||||
#include "QskFunctions.h"
|
#include "QskFunctions.h"
|
||||||
#include "QskRgbValue.h"
|
#include "QskRgbValue.h"
|
||||||
#include "QskGradientDirection.h"
|
#include "QskGradientDirection.h"
|
||||||
|
#include "QskColorRamp.h"
|
||||||
|
|
||||||
|
#include <qsgtexture.h>
|
||||||
|
|
||||||
QSK_QT_PRIVATE_BEGIN
|
QSK_QT_PRIVATE_BEGIN
|
||||||
#include <private/qrhi_p.h>
|
#include <private/qrhi_p.h>
|
||||||
#include <private/qdrawhelper_p.h>
|
#include <private/qdrawhelper_p.h>
|
||||||
#include <private/qsgplaintexture_p.h>
|
|
||||||
QSK_QT_PRIVATE_END
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
#include <qcoreapplication.h>
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
// RHI shaders are supported by Qt 5.15 and Qt 6.x
|
// RHI shaders are supported by Qt 5.15 and Qt 6.x
|
||||||
|
@ -32,153 +33,6 @@ QSK_QT_PRIVATE_END
|
||||||
using RhiShader = QSGMaterialShader;
|
using RhiShader = QSGMaterialShader;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
class ColorRamp : public QSGPlainTexture
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ColorRamp( const QskGradientStops& stops, QGradient::Spread spread )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Qt creates tables of 1024 colors, while Chrome, Firefox, and Android
|
|
||||||
seem to use 256 colors only ( according to maybe outdated sources
|
|
||||||
from the internet ),
|
|
||||||
*/
|
|
||||||
|
|
||||||
setImage( QskRgb::colorTable( 256, stops ) );
|
|
||||||
|
|
||||||
const auto wrapMode = this->wrapMode( spread );
|
|
||||||
|
|
||||||
setHorizontalWrapMode( wrapMode );
|
|
||||||
setVerticalWrapMode( wrapMode );
|
|
||||||
|
|
||||||
setFiltering( QSGTexture::Linear );
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
static inline QSGTexture::WrapMode wrapMode( QGradient::Spread spread )
|
|
||||||
{
|
|
||||||
switch ( spread )
|
|
||||||
{
|
|
||||||
case QGradient::RepeatSpread:
|
|
||||||
return QSGTexture::Repeat;
|
|
||||||
|
|
||||||
case QGradient::ReflectSpread:
|
|
||||||
return QSGTexture::MirroredRepeat;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return QSGTexture::ClampToEdge;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ColorRampHashKey
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
inline bool operator==( const ColorRampHashKey& other ) const
|
|
||||||
{
|
|
||||||
return rhi == other.rhi && spread == other.spread && stops == other.stops;
|
|
||||||
}
|
|
||||||
|
|
||||||
const void* rhi;
|
|
||||||
const QskGradientStops stops;
|
|
||||||
const QGradient::Spread spread;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline size_t qHash( const ColorRampHashKey& key, size_t seed = 0 )
|
|
||||||
{
|
|
||||||
size_t valus = seed + key.spread;
|
|
||||||
|
|
||||||
for ( const auto& stop : key.stops )
|
|
||||||
valus += stop.rgb();
|
|
||||||
|
|
||||||
return valus;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ColorRampCache
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static ColorRampCache* instance()
|
|
||||||
{
|
|
||||||
static ColorRampCache* s_instance = nullptr;
|
|
||||||
if ( s_instance == nullptr )
|
|
||||||
{
|
|
||||||
s_instance = new ColorRampCache();
|
|
||||||
|
|
||||||
/*
|
|
||||||
For RHI we have QRhi::addCleanupCallback, but with
|
|
||||||
OpenGL we have to fiddle around with QOpenGLSharedResource
|
|
||||||
So let's keep things simple for the moment. TODO ...
|
|
||||||
*/
|
|
||||||
qAddPostRoutine( cleanup );
|
|
||||||
}
|
|
||||||
|
|
||||||
return s_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
~ColorRampCache()
|
|
||||||
{
|
|
||||||
qDeleteAll( m_hashTable );
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRamp* colorRamp( const void* rhi,
|
|
||||||
const QskGradientStops& stops, QGradient::Spread spread )
|
|
||||||
{
|
|
||||||
const ColorRampHashKey key { rhi, stops, spread };
|
|
||||||
|
|
||||||
auto texture = m_hashTable[key];
|
|
||||||
if ( texture == nullptr )
|
|
||||||
{
|
|
||||||
texture = new ColorRamp( stops, spread );
|
|
||||||
m_hashTable[ key ] = texture;
|
|
||||||
|
|
||||||
if ( rhi != nullptr )
|
|
||||||
{
|
|
||||||
auto myrhi = ( QRhi* )rhi;
|
|
||||||
|
|
||||||
if ( !m_rhiTable.contains( myrhi ) )
|
|
||||||
{
|
|
||||||
myrhi->addCleanupCallback( ColorRampCache::cleanupRhi );
|
|
||||||
m_rhiTable += myrhi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void cleanup()
|
|
||||||
{
|
|
||||||
delete instance();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cleanupRhi( const QRhi *rhi )
|
|
||||||
{
|
|
||||||
auto cache = instance();
|
|
||||||
|
|
||||||
auto& table = cache->m_hashTable;
|
|
||||||
for ( auto it = table.begin(); it != table.end(); )
|
|
||||||
{
|
|
||||||
if ( it.key().rhi == rhi )
|
|
||||||
{
|
|
||||||
delete it.value();
|
|
||||||
it = table.erase( it );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cache->m_rhiTable.removeAll( rhi );
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash< ColorRampHashKey, ColorRamp* > m_hashTable;
|
|
||||||
QVector< const QRhi* > m_rhiTable;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class GradientMaterial : public QskGradientMaterial
|
class GradientMaterial : public QskGradientMaterial
|
||||||
|
@ -215,6 +69,8 @@ namespace
|
||||||
|
|
||||||
virtual QSGMaterialShader* createShader() const = 0;
|
virtual QSGMaterialShader* createShader() const = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
virtual bool setGradient( const QRectF&, const QskGradient& ) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef SHADER_GL
|
#ifdef SHADER_GL
|
||||||
|
@ -250,9 +106,9 @@ namespace
|
||||||
|
|
||||||
updateUniformValues( material );
|
updateUniformValues( material );
|
||||||
|
|
||||||
auto colorRamp = ColorRampCache::instance()->colorRamp(
|
auto texture = QskColorRamp::texture(
|
||||||
nullptr, material->stops(), material->spread() );
|
nullptr, material->stops(), material->spread() );
|
||||||
colorRamp->bind();
|
texture->bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* const* attributeNames() const override final
|
char const* const* attributeNames() const override final
|
||||||
|
@ -282,23 +138,23 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateSampledImage( RenderState& state, int binding,
|
void updateSampledImage( RenderState& state, int binding,
|
||||||
QSGTexture* textures[], QSGMaterial* newMaterial, QSGMaterial*) override final
|
QSGTexture* textures[], QSGMaterial* newMaterial, QSGMaterial* ) override final
|
||||||
{
|
{
|
||||||
if ( binding != 1 )
|
if ( binding != 1 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto material = static_cast< const GradientMaterial* >( newMaterial );
|
auto material = static_cast< const GradientMaterial* >( newMaterial );
|
||||||
|
|
||||||
auto colorRamp = ColorRampCache::instance()->colorRamp(
|
auto texture = QskColorRamp::texture(
|
||||||
state.rhi(), material->stops(), material->spread() );
|
state.rhi(), material->stops(), material->spread() );
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
colorRamp->updateRhiTexture( state.rhi(), state.resourceUpdateBatch() );
|
texture->updateRhiTexture( state.rhi(), state.resourceUpdateBatch() );
|
||||||
#else
|
#else
|
||||||
colorRamp->commitTextureOperations( state.rhi(), state.resourceUpdateBatch() );
|
texture->commitTextureOperations( state.rhi(), state.resourceUpdateBatch() );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
textures[0] = colorRamp;
|
textures[0] = texture;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -314,7 +170,7 @@ namespace
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setGradient( const QRectF& rect, const QskGradient& gradient )
|
bool setGradient( const QRectF& rect, const QskGradient& gradient ) override
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
|
@ -475,7 +331,7 @@ namespace
|
||||||
return &type;
|
return &type;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setGradient( const QRectF& rect, const QskGradient& gradient )
|
bool setGradient( const QRectF& rect, const QskGradient& gradient ) override
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
|
@ -646,7 +502,7 @@ namespace
|
||||||
return &type;
|
return &type;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setGradient( const QRectF& rect, const QskGradient& gradient )
|
bool setGradient( const QRectF& rect, const QskGradient& gradient ) override
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
|
@ -835,33 +691,20 @@ bool QskGradientMaterial::updateGradient( const QRectF& rect, const QskGradient&
|
||||||
{
|
{
|
||||||
Q_ASSERT( gradient.type() == m_gradientType );
|
Q_ASSERT( gradient.type() == m_gradientType );
|
||||||
|
|
||||||
if ( gradient.type() != m_gradientType )
|
if ( gradient.type() == m_gradientType )
|
||||||
return false;
|
|
||||||
|
|
||||||
switch ( gradient.type() )
|
|
||||||
{
|
{
|
||||||
case QskGradient::Linear:
|
switch ( gradient.type() )
|
||||||
{
|
{
|
||||||
auto material = static_cast< LinearMaterial* >( this );
|
case QskGradient::Linear:
|
||||||
return material->setGradient( rect, gradient );
|
case QskGradient::Radial:
|
||||||
}
|
case QskGradient::Conic:
|
||||||
|
{
|
||||||
|
auto material = static_cast< GradientMaterial* >( this );
|
||||||
|
return material->setGradient( rect, gradient );
|
||||||
|
}
|
||||||
|
|
||||||
case QskGradient::Radial:
|
default:
|
||||||
{
|
qWarning( "Invalid gradient type" );
|
||||||
auto material = static_cast< RadialMaterial* >( this );
|
|
||||||
return material->setGradient( rect, gradient );
|
|
||||||
}
|
|
||||||
|
|
||||||
case QskGradient::Conic:
|
|
||||||
{
|
|
||||||
auto material = static_cast< ConicMaterial* >( this );
|
|
||||||
return material->setGradient( rect, gradient );
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
qWarning( "Invalid gradient type" );
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,7 @@ HEADERS += \
|
||||||
nodes/QskBoxRenderer.h \
|
nodes/QskBoxRenderer.h \
|
||||||
nodes/QskBoxRendererColorMap.h \
|
nodes/QskBoxRendererColorMap.h \
|
||||||
nodes/QskBoxShadowNode.h \
|
nodes/QskBoxShadowNode.h \
|
||||||
|
nodes/QskColorRamp.h \
|
||||||
nodes/QskGraphicNode.h \
|
nodes/QskGraphicNode.h \
|
||||||
nodes/QskPaintedNode.h \
|
nodes/QskPaintedNode.h \
|
||||||
nodes/QskPlainTextRenderer.h \
|
nodes/QskPlainTextRenderer.h \
|
||||||
|
@ -131,6 +132,7 @@ SOURCES += \
|
||||||
nodes/QskBoxRendererEllipse.cpp \
|
nodes/QskBoxRendererEllipse.cpp \
|
||||||
nodes/QskBoxRendererDEllipse.cpp \
|
nodes/QskBoxRendererDEllipse.cpp \
|
||||||
nodes/QskBoxShadowNode.cpp \
|
nodes/QskBoxShadowNode.cpp \
|
||||||
|
nodes/QskColorRamp.cpp \
|
||||||
nodes/QskGraphicNode.cpp \
|
nodes/QskGraphicNode.cpp \
|
||||||
nodes/QskPaintedNode.cpp \
|
nodes/QskPaintedNode.cpp \
|
||||||
nodes/QskPlainTextRenderer.cpp \
|
nodes/QskPlainTextRenderer.cpp \
|
||||||
|
|
Loading…
Reference in New Issue