37 m_strokeColor =
color;
51 double distance = secondStop.first - firstStop.first;
52 double distanceDelta = newPos - firstStop.first;
53 double modifierValue = distanceDelta /
distance;
54 const auto firstStopRgbColor = firstStop.second.toRgb();
55 const auto secondStopRgbColor = secondStop.second.toRgb();
56 int redDelta = (secondStopRgbColor.red() - firstStopRgbColor.red()) * modifierValue;
57 int greenDelta = (secondStopRgbColor.green() - firstStopRgbColor.green()) * modifierValue;
58 int blueDelta = (secondStopRgbColor.blue() - firstStopRgbColor.blue()) * modifierValue;
59 int alphaDelta = (secondStopRgbColor.alpha() - firstStopRgbColor.alpha()) * modifierValue;
62 newStop.first = newPos;
63 newStop.second =
QColor(firstStopRgbColor.red() + redDelta,
64 firstStopRgbColor.green() + greenDelta,
65 firstStopRgbColor.blue() + blueDelta,
66 firstStopRgbColor.alpha() + alphaDelta);
75 bool needsNormalization =
false;
77 if (stop.first < 0.0 || stop.first > 1.0) {
78 needsNormalization =
true;
83 if (needsNormalization) {
85 if (stops.
count() == 1) {
90 normalizedStops.
append(stop);
96 for (
int i = 0;
i < stops.
count(); ++
i) {
97 if (stops.
at(
i).first < 0.0) {
99 }
else if (stops.
at(
i).first > 1.0) {
110 if (below + 1 < stops.
count()) {
114 singleStop.first = 0.0;
115 singleStop.second = stops.
at(below).second;
116 normalizedStops.
append(singleStop);
120 for (
int i = 0;
i < between.
count(); ++
i)
129 singleStop.first = 1.0;
130 singleStop.second = stops.
at(above).second;
131 normalizedStops.
append(singleStop);
136 m_gradientStops = normalizedStops;
139 m_gradientStops = stops;
147 m_vertical = vertical;
171 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
173 if (m_offscreenSurface) {
174 delete m_offscreenSurface;
175 m_offscreenSurface =
nullptr;
178 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
181 if (m_offscreenSurface ==
nullptr || m_offscreenSurface->
size() !=
QSize(std::ceil(m_rect.
width()), std::ceil(m_rect.
height()))) {
182 delete m_offscreenSurface;
190 vgClearPath(m_rectanglePath, VG_PATH_CAPABILITY_APPEND_TO);
191 vgClearPath(m_borderPath, VG_PATH_CAPABILITY_APPEND_TO);
193 if (m_penWidth == 0) {
194 generateRectanglePath(m_rect, m_radius, m_rectanglePath);
196 generateRectangleAndBorderPaths(m_rect, m_penWidth, m_radius, m_rectanglePath, m_borderPath);
204 if (m_gradientStops.
isEmpty()) {
205 vgSetParameteri(m_rectanglePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
209 vgSetParameteri(m_rectanglePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
210 const VGfloat linearGradient[] = {
213 m_vertical ? 0.0f :
static_cast<VGfloat
>(m_rect.
width()),
214 m_vertical ?
static_cast<VGfloat
>(m_rect.
height()) : 0.0f
216 vgSetParameterfv(m_rectanglePaint, VG_PAINT_LINEAR_GRADIENT, 4, linearGradient);
217 vgSetParameteri(m_rectanglePaint, VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_PAD);
218 vgSetParameteri(m_rectanglePaint, VG_PAINT_COLOR_RAMP_PREMULTIPLIED,
false);
221 for (
const QGradientStop &stop : std::as_const(m_gradientStops)) {
228 vgSetParameterfv(m_rectanglePaint, VG_PAINT_COLOR_RAMP_STOPS, stops.
length(), stops.
constData());
236 vgSetParameteri(m_borderPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
239 m_strokeDirty =
false;
243 if (m_penWidth > 0) {
244 vgSetPaint(m_borderPaint, VG_FILL_PATH);
245 vgDrawPath(m_borderPath, VG_FILL_PATH);
246 vgSetPaint(m_rectanglePaint, VG_FILL_PATH);
247 vgDrawPath(m_rectanglePath, VG_FILL_PATH);
249 vgSetPaint(m_rectanglePaint, VG_FILL_PATH);
250 vgDrawPath(m_rectanglePath, VG_FILL_PATH);
256 vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
258 vgDrawImage(m_offscreenSurface->
image());
266 m_strokeDirty =
true;
280void QSGOpenVGInternalRectangleNode::createVGResources()
282 m_rectanglePaint = vgCreatePaint();
283 m_borderPaint = vgCreatePaint();
284 m_rectanglePath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
285 VG_PATH_CAPABILITY_APPEND_TO);
286 m_borderPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
287 VG_PATH_CAPABILITY_APPEND_TO);
290void QSGOpenVGInternalRectangleNode::destroyVGResources()
292 if (m_offscreenSurface)
293 delete m_offscreenSurface;
295 vgDestroyPaint(m_rectanglePaint);
296 vgDestroyPaint(m_borderPaint);
297 vgDestroyPath(m_rectanglePath);
298 vgDestroyPath(m_borderPath);
301void QSGOpenVGInternalRectangleNode::generateRectanglePath(
const QRectF &
rect,
float radius, VGPath
path)
const
307 static const VGubyte rectCommands[] = {
317 coordinates[0] =
rect.x();
318 coordinates[1] =
rect.y();
319 coordinates[2] =
rect.width();
320 coordinates[3] =
rect.height();
321 coordinates[4] = -
rect.width();
322 vgAppendPathData(
path, 5, rectCommands, coordinates.constData());
325 static const VGubyte rectCommands[] = {
338 coordinates[0] = bottomLeft.
x();
339 coordinates[1] = bottomLeft.
y();
340 coordinates[2] = bottomRight.
x();
341 coordinates[3] = bottomRight.
y();
342 coordinates[4] = topRight.
x();
343 coordinates[5] = topRight.
y();
344 coordinates[6] = topLeft.
x();
345 coordinates[7] = topLeft.
y();
347 vgAppendPathData(
path, 5, rectCommands, coordinates.constData());
352 float adjustedRadius =
qMin((
float)
qMin(
rect.width(),
rect.height()) * 0.5f, radius);
358 static const VGubyte roundedRectCommands[] = {
374 coordinates[0] =
rect.x() + adjustedRadius / 2;
375 coordinates[1] =
rect.y();
377 coordinates[2] =
rect.width() - adjustedRadius;
379 coordinates[3] = adjustedRadius / 2;
380 coordinates[4] = adjustedRadius / 2;
382 coordinates[6] = adjustedRadius / 2;
383 coordinates[7] = adjustedRadius / 2;
385 coordinates[8] =
rect.height() - adjustedRadius;
387 coordinates[9] = adjustedRadius / 2;
388 coordinates[10] = adjustedRadius / 2;
390 coordinates[12] = -adjustedRadius / 2;
391 coordinates[13] = adjustedRadius / 2;
393 coordinates[14] = -(
rect.width() - adjustedRadius);
395 coordinates[15] = adjustedRadius / 2;
396 coordinates[16] = adjustedRadius / 2;
398 coordinates[18] = -adjustedRadius / 2;
399 coordinates[19] = -adjustedRadius / 2;
401 coordinates[20] = -(
rect.height() - adjustedRadius);
403 coordinates[21] = adjustedRadius / 2;
404 coordinates[22] = adjustedRadius / 2;
406 coordinates[24] = adjustedRadius / 2;
407 coordinates[25] = -adjustedRadius / 2;
409 vgAppendPathData(
path, 10, roundedRectCommands, coordinates.constData());
413void QSGOpenVGInternalRectangleNode::generateBorderPath(
const QRectF &
rect,
float borderWidth,
float borderHeight,
float radius, VGPath
path)
const
419 static const VGubyte squaredBorderCommands[] = {
434 coordinates[0] =
rect.x();
435 coordinates[1] =
rect.y();
436 coordinates[2] =
rect.width();
437 coordinates[3] =
rect.height();
438 coordinates[4] = -
rect.width();
440 coordinates[5] =
rect.x() + borderWidth;
441 coordinates[6] =
rect.y() + borderHeight;
442 coordinates[7] =
rect.height() - (borderHeight * 2);
443 coordinates[8] =
rect.width() - (borderWidth * 2);
444 coordinates[9] = -(
rect.height() - (borderHeight * 2));
446 vgAppendPathData(
path, 9, squaredBorderCommands, coordinates.constData());
449 static const VGubyte squaredBorderCommands[] = {
462 QRectF insideRect =
rect.marginsRemoved(
QMarginsF(borderWidth, borderHeight, borderWidth, borderHeight));
473 coordinates[0] = outsideBottomLeft.
x();
474 coordinates[1] = outsideBottomLeft.
y();
475 coordinates[2] = outsideBottomRight.
x();
476 coordinates[3] = outsideBottomRight.
y();
477 coordinates[4] = outsideTopRight.
x();
478 coordinates[5] = outsideTopRight.
y();
479 coordinates[6] = outsideTopLeft.
x();
480 coordinates[7] = outsideTopLeft.
y();
482 coordinates[8] = insideBottomLeft.
x();
483 coordinates[9] = insideBottomLeft.
y();
484 coordinates[10] = insideTopLeft.
x();
485 coordinates[11] = insideTopLeft.
y();
486 coordinates[12] = insideTopRight.
x();
487 coordinates[13] = insideTopRight.
y();
488 coordinates[14] = insideBottomRight.
x();
489 coordinates[15] = insideBottomRight.
y();
491 vgAppendPathData(
path, 9, squaredBorderCommands, coordinates.constData());
493 }
else if (radius <
qMax(borderWidth, borderHeight)){
496 static const VGubyte roundedRectCommands[] = {
514 float adjustedRadius = radius * 2;
519 coordinates[0] =
rect.x() + adjustedRadius / 2;
520 coordinates[1] =
rect.y();
522 coordinates[2] =
rect.width() - adjustedRadius;
524 coordinates[3] = adjustedRadius / 2;
525 coordinates[4] = adjustedRadius / 2;
527 coordinates[6] = adjustedRadius / 2;
528 coordinates[7] = adjustedRadius / 2;
530 coordinates[8] =
rect.height() - adjustedRadius;
532 coordinates[9] = adjustedRadius / 2;
533 coordinates[10] = adjustedRadius / 2;
535 coordinates[12] = -adjustedRadius / 2;
536 coordinates[13] = adjustedRadius / 2;
538 coordinates[14] = -(
rect.width() - adjustedRadius);
540 coordinates[15] = adjustedRadius / 2;
541 coordinates[16] = adjustedRadius / 2;
543 coordinates[18] = -adjustedRadius / 2;
544 coordinates[19] = -adjustedRadius / 2;
546 coordinates[20] = -(
rect.height() - adjustedRadius);
548 coordinates[21] = adjustedRadius / 2;
549 coordinates[22] = adjustedRadius / 2;
551 coordinates[24] = adjustedRadius / 2;
552 coordinates[25] = -adjustedRadius / 2;
555 coordinates[26] =
rect.x() + borderWidth;
556 coordinates[27] =
rect.y() + borderHeight;
557 coordinates[28] =
rect.height() - (borderHeight * 2);
558 coordinates[29] =
rect.width() - (borderWidth * 2);
559 coordinates[30] = -(
rect.height() - (borderHeight * 2));
561 vgAppendPathData(
path, 14, roundedRectCommands, coordinates.constData());
565 static const VGubyte roundedBorderCommands[] = {
590 float adjustedRadius = radius * 2;
591 float adjustedInnerRadius = (radius -
qMax(borderWidth, borderHeight)) * 2;
597 coordinates[0] =
rect.x() + adjustedRadius / 2;
598 coordinates[1] =
rect.y();
600 coordinates[2] =
rect.width() - adjustedRadius;
602 coordinates[3] = adjustedRadius / 2;
603 coordinates[4] = adjustedRadius / 2;
605 coordinates[6] = adjustedRadius / 2;
606 coordinates[7] = adjustedRadius / 2;
608 coordinates[8] =
rect.height() - adjustedRadius;
610 coordinates[9] = adjustedRadius / 2;
611 coordinates[10] = adjustedRadius / 2;
613 coordinates[12] = -adjustedRadius / 2;
614 coordinates[13] = adjustedRadius / 2;
616 coordinates[14] = -(
rect.width() - adjustedRadius);
618 coordinates[15] = adjustedRadius / 2;
619 coordinates[16] = adjustedRadius / 2;
621 coordinates[18] = -adjustedRadius / 2;
622 coordinates[19] = -adjustedRadius / 2;
624 coordinates[20] = -(
rect.height() - adjustedRadius);
626 coordinates[21] = adjustedRadius / 2;
627 coordinates[22] = adjustedRadius / 2;
629 coordinates[24] = adjustedRadius / 2;
630 coordinates[25] = -adjustedRadius / 2;
633 coordinates[26] =
rect.width() - (adjustedInnerRadius / 2 + borderWidth);
634 coordinates[27] =
rect.height() - borderHeight;
636 coordinates[28] = adjustedInnerRadius / 2;
637 coordinates[29] = adjustedInnerRadius / 2;
639 coordinates[31] = adjustedInnerRadius / 2;
640 coordinates[32] = -adjustedInnerRadius / 2;
642 coordinates[33] = -((
rect.height() - borderHeight * 2) - adjustedInnerRadius);
644 coordinates[34] = adjustedInnerRadius / 2;
645 coordinates[35] = adjustedInnerRadius / 2;
647 coordinates[37] = -adjustedInnerRadius / 2;
648 coordinates[38] = -adjustedInnerRadius / 2;
650 coordinates[39] = -((
rect.width() - borderWidth * 2) - adjustedInnerRadius);
652 coordinates[40] = adjustedInnerRadius / 2;
653 coordinates[41] = adjustedInnerRadius / 2;
655 coordinates[43] = -adjustedInnerRadius / 2;
656 coordinates[44] = adjustedInnerRadius / 2;
658 coordinates[45] = (
rect.height() - borderHeight * 2) - adjustedInnerRadius;
660 coordinates[46] = adjustedInnerRadius / 2;
661 coordinates[47] = adjustedInnerRadius / 2;
663 coordinates[49] = adjustedInnerRadius / 2;
664 coordinates[50] = adjustedInnerRadius / 2;
666 coordinates[51] = (
rect.width() - borderWidth * 2) - adjustedInnerRadius;
668 vgAppendPathData(
path, 19, roundedBorderCommands, coordinates.constData());
672void QSGOpenVGInternalRectangleNode::generateRectangleAndBorderPaths(
const QRectF &
rect,
float penWidth,
float radius, VGPath inside, VGPath outside)
const
675 float borderWidth =
qMin(penWidth, (
float)
rect.width() * 0.5f);
676 float borderHeight =
qMin(penWidth, (
float)
rect.height() * 0.5f);
679 float adjustedRadius =
qMin((
float)
qMin(
rect.width(),
rect.height()) * 0.5f, radius);
682 innerRect.
adjust(borderWidth, borderHeight, -borderWidth, -borderHeight);
686 generateRectanglePath(innerRect, 0, inside);
687 generateBorderPath(
rect, borderWidth, borderHeight, 0, outside);
690 float innerRadius = radius -
qMax(borderWidth, borderHeight);
694 generateRectanglePath(innerRect, innerRadius, inside);
695 generateBorderPath(
rect, borderWidth, borderHeight, adjustedRadius, outside);
The QColor class provides colors based on RGB, HSV or CMYK values.
const_pointer constData() const noexcept
bool isEmpty() const noexcept
qsizetype length() const noexcept
const_reference at(qsizetype i) const noexcept
qsizetype count() const noexcept
void append(parameter_type t)
QPointF map(const QPointF &point) const
\inmodule QtCore\reentrant
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
\inmodule QtCore\reentrant
constexpr qreal height() const noexcept
Returns the height of the rectangle.
constexpr qreal width() const noexcept
Returns the width of the rectangle.
constexpr QPointF bottomLeft() const noexcept
Returns the position of the rectangle's bottom-left corner.
constexpr QPointF topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
constexpr QPointF bottomRight() const noexcept
Returns the position of the rectangle's bottom-right corner.
constexpr void adjust(qreal x1, qreal y1, qreal x2, qreal y2) noexcept
Adds dx1, dy1, dx2 and dy2 respectively to the existing coordinates of the rectangle.
constexpr QPointF topRight() const noexcept
Returns the position of the rectangle's top-right corner.
void setGeometry(QSGGeometry *geometry)
Sets the geometry of this node to geometry.
void setMaterial(QSGMaterial *material)
Sets the material of this geometry node to material.
The QSGGeometry class provides low-level storage for graphics primitives in the \l{Qt Quick Scene Gra...
The QSGMaterial class encapsulates rendering state for a shader program.
void setTransform(const QOpenVGMatrix &transform) override
void setAligned(bool aligned) override
void setGradientStops(const QGradientStops &stops) override
void setRadius(qreal radius) override
void setGradientVertical(bool vertical) override
~QSGOpenVGInternalRectangleNode()
void setOpacity(float opacity) override
void setPenWidth(qreal width) override
void setRect(const QRectF &rect) override
void setPenColor(const QColor &color) override
QSGOpenVGInternalRectangleNode()
void setColor(const QColor &color) override
const QOpenVGMatrix & transform() const
virtual void setTransform(const QOpenVGMatrix &transform)
virtual void setOpacity(float opacity)
const QVector< VGfloat > qColorToVGColor(const QColor &color, float opacity)
QPair< qreal, QColor > QGradientStop
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
GLsizei GLsizei GLfloat distance
GLuint GLenum GLenum transform
GLsizei const GLchar *const * path
Int aligned(Int v, Int byteAlign)
static QGradientStop interpolateStop(const QGradientStop &firstStop, const QGradientStop &secondStop, double newPos)