QskArcRenderer started with some boilerplate code

This commit is contained in:
Uwe Rathmann 2024-04-24 11:25:06 +02:00
parent 0afecc4b9e
commit 49e1d54724
3 changed files with 217 additions and 0 deletions

View File

@ -101,6 +101,7 @@ list(APPEND SOURCES
list(APPEND HEADERS
nodes/QskArcNode.h
nodes/QskArcRenderer.h
nodes/QskArcShadowNode.h
nodes/QskBasicLinesNode.h
nodes/QskBoxNode.h
@ -141,6 +142,7 @@ list(APPEND PRIVATE_HEADERS
list(APPEND SOURCES
nodes/QskArcNode.cpp
nodes/QskArcRenderer.cpp
nodes/QskArcShadowNode.cpp
nodes/QskBasicLinesNode.cpp
nodes/QskBoxNode.cpp

View File

@ -0,0 +1,164 @@
/******************************************************************************
* QSkinny - Copyright (C) The authors
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskArcRenderer.h"
#include "QskArcMetrics.h"
#include "QskGradient.h"
#include "QskVertex.h"
#include <qsggeometry.h>
static inline QskVertex::Line* qskAllocateLines(
QSGGeometry& geometry, int lineCount )
{
geometry.allocate( 2 * lineCount ); // 2 points per line
return reinterpret_cast< QskVertex::Line* >( geometry.vertexData() );
}
static inline QskVertex::ColoredLine* qskAllocateColoredLines(
QSGGeometry& geometry, int lineCount )
{
geometry.allocate( 2 * lineCount ); // 2 points per line
return reinterpret_cast< QskVertex::ColoredLine* >( geometry.vertexData() );
}
static inline int qskApproximatedCircumference( const QRectF& rect )
{
const qreal a = rect.width();
const qreal b = rect.height();
const auto ratio = a / b;
if ( ratio > 0.9 || ratio < 1.1 )
return std::max( a, b ) * 2.0 * M_PI; // circle
// Srinivasa Ramanujan: https://en.wikipedia.org/wiki/Ellipse#Circumference
const qreal d1 = ( a - b );
const qreal d2 = ( a + b );
const qreal h = ( d1 * d1 ) / ( d2 * d2 );
return M_PI * d2 * ( 1.0 + ( 3 * h / ( 10 + sqrt( 4 - 3 * h ) ) ) );
}
static inline int qskStepCount( const QRectF& rect )
{
const int length = qskApproximatedCircumference( rect );
return std::max( 3, qCeil( length / 3.0 ) );
}
namespace
{
class Stroker
{
public:
Stroker( const QRectF&, const QskArcMetrics& metrics, qreal borderWidth );
int fillCount() const;
int borderCount() const;
void setBorderLines( QskVertex::Line* ) const;
private:
const QRectF& m_rect;
const QskArcMetrics& m_metrics;
const qreal m_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
{
return 0; // TODO
}
int Stroker::borderCount() 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 );
}
void QskArcRenderer::renderBorderGeometry( const QRectF& rect,
const QskArcMetrics& metrics, qreal borderWidth, QSGGeometry& geometry )
{
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
Stroker stroker( rect, metrics, borderWidth );
const auto lines = qskAllocateLines( geometry, stroker.borderCount() );
if ( lines )
stroker.setBorderLines( lines );
}
void QskArcRenderer::renderFillGeometry( const QRectF& rect,
const QskArcMetrics& metrics, qreal borderWidth, QSGGeometry& geometry )
{
Q_UNUSED( rect );
Q_UNUSED( geometry );
Stroker stroker( rect, metrics, borderWidth );
const auto lines = qskAllocateColoredLines( geometry, stroker.fillCount() );
if ( lines )
{
// TODO
}
}
void QskArcRenderer::renderFillGeometry( const QRectF& rect,
const QskArcMetrics& metrics, QSGGeometry& geometry )
{
renderFillGeometry( rect, metrics, 0.0, geometry );
}
bool QskArcRenderer::isGradientSupported(
const QskArcMetrics& metrics, const QskGradient& gradient )
{
if ( metrics.isNull() || !gradient.isVisible() || gradient.isMonochrome() )
return true;
return gradient.type() == QskGradient::Stops;
}
void QskArcRenderer::renderArc( const QRectF& rect,
const QskArcMetrics& metrics, qreal borderWidth, const QColor& borderColor,
const QskGradient& gradient, QSGGeometry& geometry )
{
Q_UNUSED( rect );
Q_UNUSED( metrics );
Q_UNUSED( borderWidth );
Q_UNUSED( borderColor );
Q_UNUSED( gradient );
Q_UNUSED( geometry );
}
void QskArcRenderer::renderArc( const QRectF& rect, const QskArcMetrics& metrics,
const QskGradient& gradient, QSGGeometry& geometry )
{
renderArc( rect, metrics, 0, QColor(), gradient, geometry );
}

View File

@ -0,0 +1,51 @@
/******************************************************************************
* QSkinny - Copyright (C) The authors
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_ARC_RENDERER_H
#define QSK_ARC_RENDERER_H
#include "QskGlobal.h"
class QskArcMetrics;
class QskGradient;
class QSGGeometry;
class QRectF;
class QColor;
namespace QskArcRenderer
{
/*
Filling the geometry without any color information:
see QSGGeometry::defaultAttributes_Point2D()
- clip nodes
- using shaders setting the color information
*/
QSK_EXPORT void renderBorderGeometry( const QRectF&,
const QskArcMetrics&, qreal borderWidth, QSGGeometry& );
QSK_EXPORT void renderFillGeometry( const QRectF&,
const QskArcMetrics&, qreal borderWidth, QSGGeometry& );
QSK_EXPORT void renderFillGeometry( const QRectF&,
const QskArcMetrics&, QSGGeometry& );
/*
Filling the geometry usually with color information:
see QSGGeometry::defaultAttributes_ColoredPoint2D()
*/
QSK_EXPORT bool isGradientSupported( const QskArcMetrics&, const QskGradient& );
QSK_EXPORT void renderArc( const QRectF&,
const QskArcMetrics&, qreal borderWidth, const QColor& borderColor,
const QskGradient&, QSGGeometry& );
QSK_EXPORT void renderArc( const QRectF&, const QskArcMetrics&,
const QskGradient&, QSGGeometry& );
}
#endif