Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsgopenvginternalrectanglenode.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "qsgopenvghelpers.h"
6#include <cmath>
7#include <VG/vgu.h>
8
10{
11 // Set Dummy material and geometry to avoid asserts
14 createVGResources();
15}
16
21
22
24{
25 m_rect = rect;
26 m_pathDirty = true;
27}
28
30{
31 m_fillColor = color;
32 m_fillDirty = true;
33}
34
36{
37 m_strokeColor = color;
38 m_strokeDirty = true;
39}
40
42{
43 m_penWidth = width;
44 m_strokeDirty = true;
45 m_pathDirty = true;
46}
47
48//Move first stop by pos relative to seconds
49static QGradientStop interpolateStop(const QGradientStop &firstStop, const QGradientStop &secondStop, double newPos)
50{
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;
60
61 QGradientStop newStop;
62 newStop.first = newPos;
63 newStop.second = QColor(firstStopRgbColor.red() + redDelta,
64 firstStopRgbColor.green() + greenDelta,
65 firstStopRgbColor.blue() + blueDelta,
66 firstStopRgbColor.alpha() + alphaDelta);
67
68 return newStop;
69}
70
72{
73
74 //normalize stops
75 bool needsNormalization = false;
76 for (const QGradientStop &stop : std::as_const(stops)) {
77 if (stop.first < 0.0 || stop.first > 1.0) {
78 needsNormalization = true;
79 continue;
80 }
81 }
82
83 if (needsNormalization) {
84 QGradientStops normalizedStops;
85 if (stops.count() == 1) {
86 //If there is only one stop, then the position does not matter
87 //It is just treated as a color
88 QGradientStop stop = stops.at(0);
89 stop.first = 0.0;
90 normalizedStops.append(stop);
91 } else {
92 //Clip stops to only the first below 0.0 and above 1.0
93 int below = -1;
94 int above = -1;
95 QVector<int> between;
96 for (int i = 0; i < stops.count(); ++i) {
97 if (stops.at(i).first < 0.0) {
98 below = i;
99 } else if (stops.at(i).first > 1.0) {
100 above = i;
101 break;
102 } else {
103 between.append(i);
104 }
105 }
106
107 //Interpoloate new color values for above and below
108 if (below != -1 ) {
109 //If there are more than one stops left, interpolate
110 if (below + 1 < stops.count()) {
111 normalizedStops.append(interpolateStop(stops.at(below), stops.at(below + 1), 0.0));
112 } else {
113 QGradientStop singleStop;
114 singleStop.first = 0.0;
115 singleStop.second = stops.at(below).second;
116 normalizedStops.append(singleStop);
117 }
118 }
119
120 for (int i = 0; i < between.count(); ++i)
121 normalizedStops.append(stops.at(between.at(i)));
122
123 if (above != -1) {
124 //If there stops before above, interpolate
125 if (above >= 1) {
126 normalizedStops.append(interpolateStop(stops.at(above), stops.at(above - 1), 1.0));
127 } else {
128 QGradientStop singleStop;
129 singleStop.first = 1.0;
130 singleStop.second = stops.at(above).second;
131 normalizedStops.append(singleStop);
132 }
133 }
134 }
135
136 m_gradientStops = normalizedStops;
137
138 } else {
139 m_gradientStops = stops;
140 }
141
142 m_fillDirty = true;
143}
144
146{
147 m_vertical = vertical;
148 m_fillDirty = true;
149}
150
152{
153 m_radius = radius;
154 m_pathDirty = true;
155}
156
158{
159 m_aligned = aligned;
160}
161
165
167{
168 // Set Transform
169 if (transform().isAffine()) {
170 // Use current transform matrix
171 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
172 vgLoadMatrix(transform().constData());
173 if (m_offscreenSurface) {
174 delete m_offscreenSurface;
175 m_offscreenSurface = nullptr;
176 }
177 } else {
178 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
179 vgLoadIdentity();
180 // Fallback to rendering to an image for rounded rects with perspective transforms
181 if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height()))) {
182 delete m_offscreenSurface;
183 m_offscreenSurface = new QOpenVGOffscreenSurface(QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height())));
184 }
185 m_offscreenSurface->makeCurrent();
186 }
187
188 // If path is dirty
189 if (m_pathDirty) {
190 vgClearPath(m_rectanglePath, VG_PATH_CAPABILITY_APPEND_TO);
191 vgClearPath(m_borderPath, VG_PATH_CAPABILITY_APPEND_TO);
192
193 if (m_penWidth == 0) {
194 generateRectanglePath(m_rect, m_radius, m_rectanglePath);
195 } else {
196 generateRectangleAndBorderPaths(m_rect, m_penWidth, m_radius, m_rectanglePath, m_borderPath);
197 }
198
199 m_pathDirty = false;
200 }
201
202 //If fill is drity
203 if (m_fillDirty) {
204 if (m_gradientStops.isEmpty()) {
205 vgSetParameteri(m_rectanglePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
206 vgSetParameterfv(m_rectanglePaint, VG_PAINT_COLOR, 4, QSGOpenVGHelpers::qColorToVGColor(m_fillColor, opacity()).constData());
207 } else {
208 // Linear Gradient
209 vgSetParameteri(m_rectanglePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
210 const VGfloat linearGradient[] = {
211 0.0f,
212 0.0f,
213 m_vertical ? 0.0f : static_cast<VGfloat>(m_rect.width()),
214 m_vertical ? static_cast<VGfloat>(m_rect.height()) : 0.0f
215 };
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);
219
220 QVector<VGfloat> stops;
221 for (const QGradientStop &stop : std::as_const(m_gradientStops)) {
222 // offset
223 stops.append(stop.first);
224 // color
225 stops.append(QSGOpenVGHelpers::qColorToVGColor(stop.second, opacity()));
226 }
227
228 vgSetParameterfv(m_rectanglePaint, VG_PAINT_COLOR_RAMP_STOPS, stops.length(), stops.constData());
229 }
230
231 m_fillDirty = false;
232 }
233
234 //If stroke is dirty
235 if (m_strokeDirty) {
236 vgSetParameteri(m_borderPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
237 vgSetParameterfv(m_borderPaint, VG_PAINT_COLOR, 4, QSGOpenVGHelpers::qColorToVGColor(m_strokeColor, opacity()).constData());
238
239 m_strokeDirty = false;
240 }
241
242 //Draw
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);
248 } else {
249 vgSetPaint(m_rectanglePaint, VG_FILL_PATH);
250 vgDrawPath(m_rectanglePath, VG_FILL_PATH);
251 }
252
253 if (!transform().isAffine()) {
254 m_offscreenSurface->doneCurrent();
255 // Render offscreen surface
256 vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
257 vgLoadMatrix(transform().constData());
258 vgDrawImage(m_offscreenSurface->image());
259 }
260}
261
263{
266 m_strokeDirty = true;
267 m_fillDirty = true;
268 }
269}
270
272{
273 // if there transform matrix is not affine, regenerate the path
274 if (transform.isAffine())
275 m_pathDirty = true;
276
278}
279
280void QSGOpenVGInternalRectangleNode::createVGResources()
281{
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);
288}
289
290void QSGOpenVGInternalRectangleNode::destroyVGResources()
291{
292 if (m_offscreenSurface)
293 delete m_offscreenSurface;
294
295 vgDestroyPaint(m_rectanglePaint);
296 vgDestroyPaint(m_borderPaint);
297 vgDestroyPath(m_rectanglePath);
298 vgDestroyPath(m_borderPath);
299}
300
301void QSGOpenVGInternalRectangleNode::generateRectanglePath(const QRectF &rect, float radius, VGPath path) const
302{
303 if (radius == 0) {
304 // Generate a rectangle
305 if (transform().isAffine()) {
306 // Create command list
307 static const VGubyte rectCommands[] = {
308 VG_MOVE_TO_ABS,
309 VG_HLINE_TO_REL,
310 VG_VLINE_TO_REL,
311 VG_HLINE_TO_REL,
312 VG_CLOSE_PATH
313 };
314
315 // Create command data
316 QVector<VGfloat> coordinates(5);
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());
323 } else {
324 // Pre-transform path
325 static const VGubyte rectCommands[] = {
326 VG_MOVE_TO_ABS,
327 VG_LINE_TO_ABS,
328 VG_LINE_TO_ABS,
329 VG_LINE_TO_ABS,
330 VG_CLOSE_PATH
331 };
332
333 QVector<VGfloat> coordinates(8);
334 const QPointF topLeft = transform().map(rect.topLeft());
335 const QPointF topRight = transform().map(rect.topRight());
336 const QPointF bottomLeft = transform().map(rect.bottomLeft());
337 const QPointF bottomRight = transform().map(rect.bottomRight());
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();
346
347 vgAppendPathData(path, 5, rectCommands, coordinates.constData());
348 }
349 } else {
350 // Generate a rounded rectangle
351 //Radius should never exceeds half of the width or half of the height
352 float adjustedRadius = qMin((float)qMin(rect.width(), rect.height()) * 0.5f, radius);
353
354 // OpenVG expectes radius to be 2x what we expect
355 adjustedRadius *= 2;
356
357 // Create command list
358 static const VGubyte roundedRectCommands[] = {
359 VG_MOVE_TO_ABS,
360 VG_HLINE_TO_REL,
361 VG_SCCWARC_TO_REL,
362 VG_VLINE_TO_REL,
363 VG_SCCWARC_TO_REL,
364 VG_HLINE_TO_REL,
365 VG_SCCWARC_TO_REL,
366 VG_VLINE_TO_REL,
367 VG_SCCWARC_TO_REL,
368 VG_CLOSE_PATH
369 };
370
371 // Create command data
372 QVector<VGfloat> coordinates(26);
373
374 coordinates[0] = rect.x() + adjustedRadius / 2;
375 coordinates[1] = rect.y();
376
377 coordinates[2] = rect.width() - adjustedRadius;
378
379 coordinates[3] = adjustedRadius / 2;
380 coordinates[4] = adjustedRadius / 2;
381 coordinates[5] = 0;
382 coordinates[6] = adjustedRadius / 2;
383 coordinates[7] = adjustedRadius / 2;
384
385 coordinates[8] = rect.height() - adjustedRadius;
386
387 coordinates[9] = adjustedRadius / 2;
388 coordinates[10] = adjustedRadius / 2;
389 coordinates[11] = 0;
390 coordinates[12] = -adjustedRadius / 2;
391 coordinates[13] = adjustedRadius / 2;
392
393 coordinates[14] = -(rect.width() - adjustedRadius);
394
395 coordinates[15] = adjustedRadius / 2;
396 coordinates[16] = adjustedRadius / 2;
397 coordinates[17] = 0;
398 coordinates[18] = -adjustedRadius / 2;
399 coordinates[19] = -adjustedRadius / 2;
400
401 coordinates[20] = -(rect.height() - adjustedRadius);
402
403 coordinates[21] = adjustedRadius / 2;
404 coordinates[22] = adjustedRadius / 2;
405 coordinates[23] = 0;
406 coordinates[24] = adjustedRadius / 2;
407 coordinates[25] = -adjustedRadius / 2;
408
409 vgAppendPathData(path, 10, roundedRectCommands, coordinates.constData());
410 }
411}
412
413void QSGOpenVGInternalRectangleNode::generateBorderPath(const QRectF &rect, float borderWidth, float borderHeight, float radius, VGPath path) const
414{
415 if (radius == 0) {
416 // squared frame
417 if (transform().isAffine()) {
418 // Create command list
419 static const VGubyte squaredBorderCommands[] = {
420 VG_MOVE_TO_ABS,
421 VG_HLINE_TO_REL,
422 VG_VLINE_TO_REL,
423 VG_HLINE_TO_REL,
424 VG_MOVE_TO_ABS,
425 VG_VLINE_TO_REL,
426 VG_HLINE_TO_REL,
427 VG_VLINE_TO_REL,
428 VG_CLOSE_PATH
429 };
430
431 // Create command data
432 QVector<VGfloat> coordinates(10);
433 // Outside Square
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();
439 // Inside Square (opposite direction)
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));
445
446 vgAppendPathData(path, 9, squaredBorderCommands, coordinates.constData());
447 } else {
448 // persepective transform
449 static const VGubyte squaredBorderCommands[] = {
450 VG_MOVE_TO_ABS,
451 VG_LINE_TO_ABS,
452 VG_LINE_TO_ABS,
453 VG_LINE_TO_ABS,
454 VG_MOVE_TO_ABS,
455 VG_LINE_TO_ABS,
456 VG_LINE_TO_ABS,
457 VG_LINE_TO_ABS,
458 VG_CLOSE_PATH
459 };
460
461 QVector<VGfloat> coordinates(16);
462 QRectF insideRect = rect.marginsRemoved(QMarginsF(borderWidth, borderHeight, borderWidth, borderHeight));
463 QPointF outsideBottomLeft = transform().map(rect.bottomLeft());
464 QPointF outsideBottomRight = transform().map(rect.bottomRight());
465 QPointF outsideTopRight = transform().map(rect.topRight());
466 QPointF outsideTopLeft = transform().map(rect.topLeft());
467 QPointF insideBottomLeft = transform().map(insideRect.bottomLeft());
468 QPointF insideTopLeft = transform().map(insideRect.topLeft());
469 QPointF insideTopRight = transform().map(insideRect.topRight());
470 QPointF insideBottomRight = transform().map(insideRect.bottomRight());
471
472 // Outside
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();
481 // Inside
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();
490
491 vgAppendPathData(path, 9, squaredBorderCommands, coordinates.constData());
492 }
493 } else if (radius < qMax(borderWidth, borderHeight)){
494 // rounded outside, squared inside
495 // Create command list
496 static const VGubyte roundedRectCommands[] = {
497 VG_MOVE_TO_ABS,
498 VG_HLINE_TO_REL,
499 VG_SCCWARC_TO_REL,
500 VG_VLINE_TO_REL,
501 VG_SCCWARC_TO_REL,
502 VG_HLINE_TO_REL,
503 VG_SCCWARC_TO_REL,
504 VG_VLINE_TO_REL,
505 VG_SCCWARC_TO_REL,
506 VG_MOVE_TO_ABS,
507 VG_VLINE_TO_REL,
508 VG_HLINE_TO_REL,
509 VG_VLINE_TO_REL,
510 VG_CLOSE_PATH
511 };
512
513 // Ajust for OpenVG's usage or radius
514 float adjustedRadius = radius * 2;
515
516 // Create command data
517 QVector<VGfloat> coordinates(31);
518 // Outside Rounded Rect
519 coordinates[0] = rect.x() + adjustedRadius / 2;
520 coordinates[1] = rect.y();
521
522 coordinates[2] = rect.width() - adjustedRadius;
523
524 coordinates[3] = adjustedRadius / 2;
525 coordinates[4] = adjustedRadius / 2;
526 coordinates[5] = 0;
527 coordinates[6] = adjustedRadius / 2;
528 coordinates[7] = adjustedRadius / 2;
529
530 coordinates[8] = rect.height() - adjustedRadius;
531
532 coordinates[9] = adjustedRadius / 2;
533 coordinates[10] = adjustedRadius / 2;
534 coordinates[11] = 0;
535 coordinates[12] = -adjustedRadius / 2;
536 coordinates[13] = adjustedRadius / 2;
537
538 coordinates[14] = -(rect.width() - adjustedRadius);
539
540 coordinates[15] = adjustedRadius / 2;
541 coordinates[16] = adjustedRadius / 2;
542 coordinates[17] = 0;
543 coordinates[18] = -adjustedRadius / 2;
544 coordinates[19] = -adjustedRadius / 2;
545
546 coordinates[20] = -(rect.height() - adjustedRadius);
547
548 coordinates[21] = adjustedRadius / 2;
549 coordinates[22] = adjustedRadius / 2;
550 coordinates[23] = 0;
551 coordinates[24] = adjustedRadius / 2;
552 coordinates[25] = -adjustedRadius / 2;
553
554 // Inside Square (opposite direction)
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));
560
561 vgAppendPathData(path, 14, roundedRectCommands, coordinates.constData());
562 } else {
563 // rounded outside, rounded inside
564
565 static const VGubyte roundedBorderCommands[] = {
566 // Outer
567 VG_MOVE_TO_ABS,
568 VG_HLINE_TO_REL,
569 VG_SCCWARC_TO_REL,
570 VG_VLINE_TO_REL,
571 VG_SCCWARC_TO_REL,
572 VG_HLINE_TO_REL,
573 VG_SCCWARC_TO_REL,
574 VG_VLINE_TO_REL,
575 VG_SCCWARC_TO_REL,
576 // Inner
577 VG_MOVE_TO_ABS,
578 VG_SCWARC_TO_REL,
579 VG_VLINE_TO_REL,
580 VG_SCWARC_TO_REL,
581 VG_HLINE_TO_REL,
582 VG_SCWARC_TO_REL,
583 VG_VLINE_TO_REL,
584 VG_SCWARC_TO_REL,
585 VG_HLINE_TO_REL,
586 VG_CLOSE_PATH
587 };
588
589 // Adjust for OpenVG's usage or radius
590 float adjustedRadius = radius * 2;
591 float adjustedInnerRadius = (radius - qMax(borderWidth, borderHeight)) * 2;
592
593 // Create command data
594 QVector<VGfloat> coordinates(52);
595
596 // Outer
597 coordinates[0] = rect.x() + adjustedRadius / 2;
598 coordinates[1] = rect.y();
599
600 coordinates[2] = rect.width() - adjustedRadius;
601
602 coordinates[3] = adjustedRadius / 2;
603 coordinates[4] = adjustedRadius / 2;
604 coordinates[5] = 0;
605 coordinates[6] = adjustedRadius / 2;
606 coordinates[7] = adjustedRadius / 2;
607
608 coordinates[8] = rect.height() - adjustedRadius;
609
610 coordinates[9] = adjustedRadius / 2;
611 coordinates[10] = adjustedRadius / 2;
612 coordinates[11] = 0;
613 coordinates[12] = -adjustedRadius / 2;
614 coordinates[13] = adjustedRadius / 2;
615
616 coordinates[14] = -(rect.width() - adjustedRadius);
617
618 coordinates[15] = adjustedRadius / 2;
619 coordinates[16] = adjustedRadius / 2;
620 coordinates[17] = 0;
621 coordinates[18] = -adjustedRadius / 2;
622 coordinates[19] = -adjustedRadius / 2;
623
624 coordinates[20] = -(rect.height() - adjustedRadius);
625
626 coordinates[21] = adjustedRadius / 2;
627 coordinates[22] = adjustedRadius / 2;
628 coordinates[23] = 0;
629 coordinates[24] = adjustedRadius / 2;
630 coordinates[25] = -adjustedRadius / 2;
631
632 // Inner
633 coordinates[26] = rect.width() - (adjustedInnerRadius / 2 + borderWidth);
634 coordinates[27] = rect.height() - borderHeight;
635
636 coordinates[28] = adjustedInnerRadius / 2;
637 coordinates[29] = adjustedInnerRadius / 2;
638 coordinates[30] = 0;
639 coordinates[31] = adjustedInnerRadius / 2;
640 coordinates[32] = -adjustedInnerRadius / 2;
641
642 coordinates[33] = -((rect.height() - borderHeight * 2) - adjustedInnerRadius);
643
644 coordinates[34] = adjustedInnerRadius / 2;
645 coordinates[35] = adjustedInnerRadius / 2;
646 coordinates[36] = 0;
647 coordinates[37] = -adjustedInnerRadius / 2;
648 coordinates[38] = -adjustedInnerRadius / 2;
649
650 coordinates[39] = -((rect.width() - borderWidth * 2) - adjustedInnerRadius);
651
652 coordinates[40] = adjustedInnerRadius / 2;
653 coordinates[41] = adjustedInnerRadius / 2;
654 coordinates[42] = 0;
655 coordinates[43] = -adjustedInnerRadius / 2;
656 coordinates[44] = adjustedInnerRadius / 2;
657
658 coordinates[45] = (rect.height() - borderHeight * 2) - adjustedInnerRadius;
659
660 coordinates[46] = adjustedInnerRadius / 2;
661 coordinates[47] = adjustedInnerRadius / 2;
662 coordinates[48] = 0;
663 coordinates[49] = adjustedInnerRadius / 2;
664 coordinates[50] = adjustedInnerRadius / 2;
665
666 coordinates[51] = (rect.width() - borderWidth * 2) - adjustedInnerRadius;
667
668 vgAppendPathData(path, 19, roundedBorderCommands, coordinates.constData());
669 }
670}
671
672void QSGOpenVGInternalRectangleNode::generateRectangleAndBorderPaths(const QRectF &rect, float penWidth, float radius, VGPath inside, VGPath outside) const
673{
674 //Borders can not be more than half the height/width of a rect
675 float borderWidth = qMin(penWidth, (float)rect.width() * 0.5f);
676 float borderHeight = qMin(penWidth, (float)rect.height() * 0.5f);
677
678 //Radius should never exceeds half of the width or half of the height
679 float adjustedRadius = qMin((float)qMin(rect.width(), rect.height()) * 0.5f, radius);
680
681 QRectF innerRect = rect;
682 innerRect.adjust(borderWidth, borderHeight, -borderWidth, -borderHeight);
683
684 if (radius == 0) {
685 // Regular rect with border
686 generateRectanglePath(innerRect, 0, inside);
687 generateBorderPath(rect, borderWidth, borderHeight, 0, outside);
688 } else {
689 // Rounded Rect with border
690 float innerRadius = radius - qMax(borderWidth, borderHeight);
691 if (innerRadius < 0)
692 innerRadius = 0.0f;
693
694 generateRectanglePath(innerRect, innerRadius, inside);
695 generateBorderPath(rect, borderWidth, borderHeight, adjustedRadius, outside);
696 }
697}
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
qsizetype count() const noexcept
Definition qlist.h:398
\inmodule QtCore
Definition qmargins.h:270
QPointF map(const QPointF &point) const
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr QRectF marginsRemoved(const QMarginsF &margins) const noexcept
Definition qrect.h:895
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.
Definition qrect.h:805
void setGeometry(QSGGeometry *geometry)
Sets the geometry of this node to geometry.
Definition qsgnode.cpp:764
void setMaterial(QSGMaterial *material)
Sets the material of this geometry node to material.
Definition qsgnode.cpp:927
The QSGGeometry class provides low-level storage for graphics primitives in the \l{Qt Quick Scene Gra...
Definition qsggeometry.h:15
The QSGMaterial class encapsulates rendering state for a shader program.
Definition qsgmaterial.h:15
void setTransform(const QOpenVGMatrix &transform) override
void setGradientStops(const QGradientStops &stops) override
void setRect(const QRectF &rect) override
void setPenColor(const QColor &color) override
void setColor(const QColor &color) override
const QOpenVGMatrix & transform() const
virtual void setTransform(const QOpenVGMatrix &transform)
virtual void setOpacity(float opacity)
\inmodule QtCore
Definition qsize.h:25
rect
[4]
const QVector< VGfloat > qColorToVGColor(const QColor &color, float opacity)
QPair< qreal, QColor > QGradientStop
Definition qbrush.h:131
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLsizei GLsizei GLfloat distance
GLint GLsizei width
GLuint color
[2]
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)
double qreal
Definition qtypes.h:187