QskArcRenderer - work in progress, QskArcRenderNode added
This commit is contained in:
parent
49e1d54724
commit
f6845c709c
|
@ -87,16 +87,18 @@ ArcPage::ArcPage( QQuickItem* parent )
|
|||
arc->setSpanAngle( 270.0 );
|
||||
arc->setThickness( 10.0 );
|
||||
|
||||
arc->setFillColor( Qt::darkRed );
|
||||
arc->setFillColor( Qt::yellow );
|
||||
|
||||
arc->setBorderWidth( 0 );
|
||||
arc->setBorderColor( Qt::darkYellow );
|
||||
arc->setBorderWidth( 2.0 );
|
||||
arc->setBorderColor( Qt::darkBlue );
|
||||
|
||||
#if 0
|
||||
arc->setShadowColor( Qt::black );
|
||||
arc->setSpreadRadius( 0.0 );
|
||||
arc->setBlurRadius( 4.0 );
|
||||
arc->setOffsetX( 2.0 );
|
||||
arc->setOffsetY( 2.0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
auto panel = new ControlPanel( arc );
|
||||
|
|
|
@ -102,6 +102,7 @@ list(APPEND SOURCES
|
|||
list(APPEND HEADERS
|
||||
nodes/QskArcNode.h
|
||||
nodes/QskArcRenderer.h
|
||||
nodes/QskArcRenderNode.h
|
||||
nodes/QskArcShadowNode.h
|
||||
nodes/QskBasicLinesNode.h
|
||||
nodes/QskBoxNode.h
|
||||
|
@ -143,6 +144,7 @@ list(APPEND PRIVATE_HEADERS
|
|||
list(APPEND SOURCES
|
||||
nodes/QskArcNode.cpp
|
||||
nodes/QskArcRenderer.cpp
|
||||
nodes/QskArcRenderNode.cpp
|
||||
nodes/QskArcShadowNode.cpp
|
||||
nodes/QskBasicLinesNode.cpp
|
||||
nodes/QskBoxNode.cpp
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "QskArcNode.h"
|
||||
#include "QskArcMetrics.h"
|
||||
#include "QskArcShadowNode.h"
|
||||
#include "QskArcRenderNode.h"
|
||||
#include "QskMargins.h"
|
||||
#include "QskGradient.h"
|
||||
#include "QskShapeNode.h"
|
||||
|
@ -13,9 +14,18 @@
|
|||
#include "QskSGNode.h"
|
||||
#include "QskShadowMetrics.h"
|
||||
|
||||
#include <qpen.h>
|
||||
#include <qpainterpath.h>
|
||||
|
||||
#define ARC_RENDERER
|
||||
|
||||
#ifdef ARC_RENDERER
|
||||
using BorderNode = QskArcRenderNode;
|
||||
#else
|
||||
#include <qpen.h>
|
||||
using BorderNode = QskStrokeNode;
|
||||
#endif
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
enum NodeRole
|
||||
|
@ -107,7 +117,7 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
|
|||
auto fillNode = static_cast< QskShapeNode* >(
|
||||
QskSGNode::findChildNode( this, FillRole ) );
|
||||
|
||||
auto borderNode = static_cast< QskStrokeNode* >(
|
||||
auto borderNode = static_cast< BorderNode* >(
|
||||
QskSGNode::findChildNode( this, BorderRole ) );
|
||||
|
||||
const auto arcRect = qskEffectiveRect( rect, borderWidth );
|
||||
|
@ -173,14 +183,19 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
|
|||
{
|
||||
if ( borderNode == nullptr )
|
||||
{
|
||||
borderNode = new QskStrokeNode;
|
||||
borderNode = new BorderNode;
|
||||
QskSGNode::setNodeRole( borderNode, BorderRole );
|
||||
}
|
||||
|
||||
#ifdef ARC_RENDERER
|
||||
borderNode->updateNode( arcRect, metricsArc, borderWidth,
|
||||
borderColor, gradient );
|
||||
#else
|
||||
QPen pen( borderColor, borderWidth );
|
||||
pen.setCapStyle( Qt::FlatCap );
|
||||
|
||||
borderNode->updateNode( path, QTransform(), pen );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -188,7 +203,7 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
|
|||
borderNode = nullptr;
|
||||
}
|
||||
|
||||
qskUpdateChildren(this, ShadowRole, shadowNode);
|
||||
qskUpdateChildren(this, FillRole, fillNode);
|
||||
qskUpdateChildren(this, BorderRole, borderNode);
|
||||
qskUpdateChildren( this, ShadowRole, shadowNode );
|
||||
qskUpdateChildren( this, FillRole, fillNode );
|
||||
qskUpdateChildren( this, BorderRole, borderNode );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) The authors
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskArcRenderNode.h"
|
||||
#include "QskGradient.h"
|
||||
#include "QskArcRenderer.h"
|
||||
#include "QskArcMetrics.h"
|
||||
#include "QskGradient.h"
|
||||
#include "QskSGNode.h"
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qsgnode_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
#if 1
|
||||
#include <qsgvertexcolormaterial.h>
|
||||
#include <qglobalstatic.h>
|
||||
// deriving from QskFillNode:TODO ...
|
||||
Q_GLOBAL_STATIC( QSGVertexColorMaterial, qskMaterialColorVertex )
|
||||
#endif
|
||||
|
||||
class QskArcRenderNodePrivate final : public QSGGeometryNodePrivate
|
||||
{
|
||||
public:
|
||||
QskArcRenderNodePrivate()
|
||||
: geometry( QSGGeometry::defaultAttributes_ColoredPoint2D(), 0 )
|
||||
{
|
||||
}
|
||||
|
||||
inline void resetValues()
|
||||
{
|
||||
hash = 0;
|
||||
}
|
||||
|
||||
QSGGeometry geometry;
|
||||
QskHashValue hash = 0;
|
||||
};
|
||||
|
||||
QskArcRenderNode::QskArcRenderNode()
|
||||
: QSGGeometryNode( *new QskArcRenderNodePrivate )
|
||||
{
|
||||
Q_D( QskArcRenderNode );
|
||||
|
||||
setGeometry( &d->geometry );
|
||||
|
||||
setMaterial( qskMaterialColorVertex );
|
||||
setFlag( QSGNode::OwnsMaterial, false );
|
||||
}
|
||||
|
||||
void QskArcRenderNode::updateNode(
|
||||
const QRectF& rect, const QskArcMetrics& metrics, qreal borderWidth,
|
||||
const QColor& borderColor, const QskGradient& gradient )
|
||||
{
|
||||
Q_D( QskArcRenderNode );
|
||||
|
||||
bool visible = !( rect.isEmpty() || metrics.isNull() );
|
||||
if ( visible )
|
||||
{
|
||||
visible = gradient.isVisible();
|
||||
if ( !visible )
|
||||
{
|
||||
visible = ( borderWidth > 0.0 )
|
||||
&& borderColor.isValid() && ( borderColor.alpha() > 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !visible )
|
||||
{
|
||||
d->resetValues();
|
||||
QskSGNode::resetGeometry( this );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
QskHashValue hash = 3496;
|
||||
|
||||
hash = qHashBits( &rect, sizeof( QRectF ), hash );
|
||||
hash = qHash( borderWidth, hash );
|
||||
hash = qHash( borderColor.rgba(), hash );
|
||||
hash = metrics.hash( hash );
|
||||
hash = gradient.hash( hash );
|
||||
|
||||
if ( hash != d->hash )
|
||||
{
|
||||
d->hash = hash;
|
||||
|
||||
QskArcRenderer::renderBorderGeometry(
|
||||
rect, metrics, borderWidth, *geometry() );
|
||||
|
||||
markDirty( QSGNode::DirtyGeometry );
|
||||
markDirty( QSGNode::DirtyMaterial );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) The authors
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_ARC_RENDER_NODE_H
|
||||
#define QSK_ARC_RENDER_NODE_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include <qsgnode.h>
|
||||
|
||||
class QskGradient;
|
||||
class QskArcMetrics;
|
||||
|
||||
class QskArcRenderNodePrivate;
|
||||
|
||||
class QSK_EXPORT QskArcRenderNode : public QSGGeometryNode
|
||||
{
|
||||
using Inherited = QSGGeometryNode;
|
||||
|
||||
public:
|
||||
QskArcRenderNode();
|
||||
|
||||
void updateNode( const QRectF&, const QskArcMetrics&, qreal borderWidth,
|
||||
const QColor& borderColor, const QskGradient& );
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE( QskArcRenderNode )
|
||||
};
|
||||
|
||||
#endif
|
|
@ -10,6 +10,10 @@
|
|||
|
||||
#include <qsggeometry.h>
|
||||
|
||||
#if 1
|
||||
#include <qdebug.h>
|
||||
#endif
|
||||
|
||||
static inline QskVertex::Line* qskAllocateLines(
|
||||
QSGGeometry& geometry, int lineCount )
|
||||
{
|
||||
|
@ -44,8 +48,75 @@ static inline int qskApproximatedCircumference( const QRectF& rect )
|
|||
|
||||
static inline int qskStepCount( const QRectF& rect )
|
||||
{
|
||||
#if 0
|
||||
const auto dist = 3.0;
|
||||
#else
|
||||
const auto dist = 20.0;
|
||||
#endif
|
||||
|
||||
const int length = qskApproximatedCircumference( rect );
|
||||
return std::max( 3, qCeil( length / 3.0 ) );
|
||||
return std::max( 3, qCeil( length / dist ) );
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class AngleIterator
|
||||
{
|
||||
public:
|
||||
AngleIterator( qreal radians1, qreal radians2, int stepCount );
|
||||
|
||||
inline void operator++() { increment(); }
|
||||
void increment();
|
||||
|
||||
inline double cos() const { return m_cos; }
|
||||
inline double sin() const { return m_sin; }
|
||||
|
||||
inline int step() const { return m_stepIndex; }
|
||||
inline int stepCount() const { return m_stepCount; }
|
||||
inline bool isDone() const { return m_stepIndex > m_stepCount; }
|
||||
|
||||
private:
|
||||
double m_cos;
|
||||
double m_sin;
|
||||
|
||||
int m_stepIndex;
|
||||
|
||||
int m_stepCount;
|
||||
|
||||
const double m_radians1;
|
||||
const double m_radians2;
|
||||
const double m_radiansStep;
|
||||
};
|
||||
|
||||
inline AngleIterator::AngleIterator( qreal radians1, qreal radians2, int stepCount )
|
||||
: m_stepIndex( 0 )
|
||||
, m_stepCount( stepCount )
|
||||
, m_radians1( radians1 )
|
||||
, m_radians2( radians2 )
|
||||
, m_radiansStep( ( radians2 - radians1 ) / stepCount )
|
||||
{
|
||||
m_cos = qFastCos( radians1 );
|
||||
m_sin = qFastSin( radians1 );
|
||||
}
|
||||
|
||||
inline void AngleIterator::increment()
|
||||
{
|
||||
if ( ++m_stepIndex >= m_stepCount )
|
||||
{
|
||||
if ( m_stepIndex == m_stepCount )
|
||||
{
|
||||
m_cos = qFastCos( m_radians2 );
|
||||
m_sin = qFastSin( m_radians2 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto radians = m_radians1 + m_stepIndex * m_radiansStep;
|
||||
|
||||
m_cos = qFastCos( radians );
|
||||
m_sin = qFastSin( radians );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
|
@ -58,49 +129,106 @@ namespace
|
|||
int fillCount() const;
|
||||
int borderCount() const;
|
||||
|
||||
void setBorderLines( QskVertex::Line* ) const;
|
||||
int setBorderLines( QskVertex::ColoredLine* ) const;
|
||||
|
||||
private:
|
||||
int arcLineCount() const;
|
||||
|
||||
void setArcLines( QskVertex::ColoredLine*, int lineCount,
|
||||
const QPointF&, const qreal width, const qreal height,
|
||||
const qreal radians1, const qreal radians2,
|
||||
qreal arcWidth, const QskVertex::Color ) const;
|
||||
|
||||
const QRectF& m_rect;
|
||||
const QskArcMetrics& m_metrics;
|
||||
const qreal m_borderWidth;
|
||||
};
|
||||
}
|
||||
|
||||
Stroker::Stroker( const QRectF& rect, const QskArcMetrics& metrics, qreal borderWidth )
|
||||
Stroker::Stroker( const QRectF& rect,
|
||||
const QskArcMetrics& metrics, qreal borderWidth )
|
||||
: m_rect( rect )
|
||||
, m_metrics( metrics )
|
||||
, m_borderWidth( borderWidth )
|
||||
{
|
||||
{
|
||||
Q_ASSERT( metrics.sizeMode() == Qt::AbsoluteSize );
|
||||
}
|
||||
}
|
||||
|
||||
int Stroker::fillCount() const
|
||||
{
|
||||
int Stroker::fillCount() const
|
||||
{
|
||||
return 0; // TODO
|
||||
}
|
||||
}
|
||||
|
||||
int Stroker::borderCount() const
|
||||
{
|
||||
int Stroker::arcLineCount() const
|
||||
{
|
||||
if ( m_metrics.isNull() )
|
||||
return 0;
|
||||
|
||||
int n = qskStepCount( m_rect );
|
||||
if ( !m_metrics.isClosed() )
|
||||
{
|
||||
n = qCeil( n * qAbs( m_metrics.spanAngle() ) / 360.0 );
|
||||
n += 1; // closing line
|
||||
}
|
||||
|
||||
n *= 2; // inner/outer border
|
||||
n += 1; // dummy line connection inner/outer border
|
||||
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
void Stroker::setBorderLines( QskVertex::Line* lines ) const
|
||||
{
|
||||
Q_UNUSED( lines );
|
||||
int Stroker::borderCount() const
|
||||
{
|
||||
if ( m_metrics.isNull() )
|
||||
return 0;
|
||||
|
||||
return 2 * arcLineCount() + 1;
|
||||
}
|
||||
|
||||
void Stroker::setArcLines( QskVertex::ColoredLine* lines, int lineCount,
|
||||
const QPointF& center, const qreal w, const qreal h,
|
||||
const qreal radians1, const qreal radians2,
|
||||
qreal arcWidth, const QskVertex::Color color ) const
|
||||
{
|
||||
const auto w2 = w - arcWidth;
|
||||
const auto h2 = h - arcWidth;
|
||||
|
||||
auto l = lines;
|
||||
|
||||
for ( AngleIterator it( radians1, radians2, lineCount - 1 ); !it.isDone(); ++it )
|
||||
{
|
||||
const auto x1 = center.x() + w * it.cos();
|
||||
const auto x2 = center.x() + w2 * it.cos();
|
||||
|
||||
const auto y1 = center.y() + h * it.sin();
|
||||
const auto y2 = center.y() + h2 * it.sin();
|
||||
|
||||
l++->setLine( x1, y1, x2, y2, color );
|
||||
}
|
||||
|
||||
if ( l - lines != lineCount )
|
||||
qWarning() << lineCount << "->" << l - lines;
|
||||
Q_ASSERT( l - lines == lineCount );
|
||||
}
|
||||
|
||||
int Stroker::setBorderLines( QskVertex::ColoredLine* lines ) const
|
||||
{
|
||||
const auto center = m_rect.center();
|
||||
|
||||
const qreal radians1 = qDegreesToRadians( m_metrics.startAngle() );
|
||||
const qreal radians2 = qDegreesToRadians( m_metrics.endAngle() );
|
||||
|
||||
const int n = arcLineCount();
|
||||
|
||||
const QskVertex::Color color( QColor( Qt::darkBlue ) );
|
||||
|
||||
auto w = 0.5 * m_rect.width();
|
||||
auto h = 0.5 * m_rect.height();
|
||||
|
||||
setArcLines( lines, n, center, w, h, radians1, radians2, m_borderWidth, color );
|
||||
|
||||
w -= m_metrics.thickness() - m_borderWidth;
|
||||
h -= m_metrics.thickness() - m_borderWidth;
|
||||
|
||||
setArcLines( lines + n + 1, n, center, w, h, radians2, radians1, m_borderWidth, color );
|
||||
|
||||
lines[n] = { lines[n - 1].p2, lines[n + 1].p1 };
|
||||
|
||||
return 2 * n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void QskArcRenderer::renderBorderGeometry( const QRectF& rect,
|
||||
|
@ -110,9 +238,17 @@ void QskArcRenderer::renderBorderGeometry( const QRectF& rect,
|
|||
|
||||
Stroker stroker( rect, metrics, borderWidth );
|
||||
|
||||
const auto lines = qskAllocateLines( geometry, stroker.borderCount() );
|
||||
const auto lineCount = stroker.borderCount();
|
||||
|
||||
const auto lines = qskAllocateColoredLines( geometry, lineCount );
|
||||
if ( lines )
|
||||
stroker.setBorderLines( lines );
|
||||
{
|
||||
const auto effectiveCount = stroker.setBorderLines( lines );
|
||||
if ( lineCount != effectiveCount )
|
||||
{
|
||||
qWarning() << lineCount << effectiveCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QskArcRenderer::renderFillGeometry( const QRectF& rect,
|
||||
|
|
Loading…
Reference in New Issue