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 "QskRgbValue.h"
|
||||
#include "QskGradientDirection.h"
|
||||
#include "QskColorRamp.h"
|
||||
|
||||
#include <qsgtexture.h>
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qrhi_p.h>
|
||||
#include <private/qdrawhelper_p.h>
|
||||
#include <private/qsgplaintexture_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
#include <qcoreapplication.h>
|
||||
#include <cmath>
|
||||
|
||||
// RHI shaders are supported by Qt 5.15 and Qt 6.x
|
||||
|
@ -32,153 +33,6 @@ QSK_QT_PRIVATE_END
|
|||
using RhiShader = QSGMaterialShader;
|
||||
#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
|
||||
{
|
||||
class GradientMaterial : public QskGradientMaterial
|
||||
|
@ -215,6 +69,8 @@ namespace
|
|||
|
||||
virtual QSGMaterialShader* createShader() const = 0;
|
||||
#endif
|
||||
|
||||
virtual bool setGradient( const QRectF&, const QskGradient& ) = 0;
|
||||
};
|
||||
|
||||
#ifdef SHADER_GL
|
||||
|
@ -250,9 +106,9 @@ namespace
|
|||
|
||||
updateUniformValues( material );
|
||||
|
||||
auto colorRamp = ColorRampCache::instance()->colorRamp(
|
||||
auto texture = QskColorRamp::texture(
|
||||
nullptr, material->stops(), material->spread() );
|
||||
colorRamp->bind();
|
||||
texture->bind();
|
||||
}
|
||||
|
||||
char const* const* attributeNames() const override final
|
||||
|
@ -282,23 +138,23 @@ namespace
|
|||
}
|
||||
|
||||
void updateSampledImage( RenderState& state, int binding,
|
||||
QSGTexture* textures[], QSGMaterial* newMaterial, QSGMaterial*) override final
|
||||
QSGTexture* textures[], QSGMaterial* newMaterial, QSGMaterial* ) override final
|
||||
{
|
||||
if ( binding != 1 )
|
||||
return;
|
||||
|
||||
auto material = static_cast< const GradientMaterial* >( newMaterial );
|
||||
|
||||
auto colorRamp = ColorRampCache::instance()->colorRamp(
|
||||
auto texture = QskColorRamp::texture(
|
||||
state.rhi(), material->stops(), material->spread() );
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||
colorRamp->updateRhiTexture( state.rhi(), state.resourceUpdateBatch() );
|
||||
texture->updateRhiTexture( state.rhi(), state.resourceUpdateBatch() );
|
||||
#else
|
||||
colorRamp->commitTextureOperations( state.rhi(), state.resourceUpdateBatch() );
|
||||
texture->commitTextureOperations( state.rhi(), state.resourceUpdateBatch() );
|
||||
#endif
|
||||
|
||||
textures[0] = colorRamp;
|
||||
textures[0] = texture;
|
||||
}
|
||||
};
|
||||
#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;
|
||||
|
||||
|
@ -475,7 +331,7 @@ namespace
|
|||
return &type;
|
||||
}
|
||||
|
||||
bool setGradient( const QRectF& rect, const QskGradient& gradient )
|
||||
bool setGradient( const QRectF& rect, const QskGradient& gradient ) override
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
|
@ -646,7 +502,7 @@ namespace
|
|||
return &type;
|
||||
}
|
||||
|
||||
bool setGradient( const QRectF& rect, const QskGradient& gradient )
|
||||
bool setGradient( const QRectF& rect, const QskGradient& gradient ) override
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
|
@ -835,33 +691,20 @@ bool QskGradientMaterial::updateGradient( const QRectF& rect, const QskGradient&
|
|||
{
|
||||
Q_ASSERT( gradient.type() == m_gradientType );
|
||||
|
||||
if ( gradient.type() != m_gradientType )
|
||||
return false;
|
||||
|
||||
switch ( gradient.type() )
|
||||
if ( gradient.type() == m_gradientType )
|
||||
{
|
||||
case QskGradient::Linear:
|
||||
switch ( gradient.type() )
|
||||
{
|
||||
auto material = static_cast< LinearMaterial* >( this );
|
||||
return material->setGradient( rect, gradient );
|
||||
}
|
||||
case QskGradient::Linear:
|
||||
case QskGradient::Radial:
|
||||
case QskGradient::Conic:
|
||||
{
|
||||
auto material = static_cast< GradientMaterial* >( this );
|
||||
return material->setGradient( rect, gradient );
|
||||
}
|
||||
|
||||
case QskGradient::Radial:
|
||||
{
|
||||
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;
|
||||
default:
|
||||
qWarning( "Invalid gradient type" );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ HEADERS += \
|
|||
nodes/QskBoxRenderer.h \
|
||||
nodes/QskBoxRendererColorMap.h \
|
||||
nodes/QskBoxShadowNode.h \
|
||||
nodes/QskColorRamp.h \
|
||||
nodes/QskGraphicNode.h \
|
||||
nodes/QskPaintedNode.h \
|
||||
nodes/QskPlainTextRenderer.h \
|
||||
|
@ -131,6 +132,7 @@ SOURCES += \
|
|||
nodes/QskBoxRendererEllipse.cpp \
|
||||
nodes/QskBoxRendererDEllipse.cpp \
|
||||
nodes/QskBoxShadowNode.cpp \
|
||||
nodes/QskColorRamp.cpp \
|
||||
nodes/QskGraphicNode.cpp \
|
||||
nodes/QskPaintedNode.cpp \
|
||||
nodes/QskPlainTextRenderer.cpp \
|
||||
|
|
Loading…
Reference in New Issue