Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsgbasicinternalrectanglenode.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
6#include <QtCore/qmath.h>
7
9
10namespace
11{
12 struct Color4ub
13 {
14 unsigned char r, g, b, a;
15 };
16
17 Color4ub operator *(Color4ub c, float t) { c.a *= t; c.r *= t; c.g *= t; c.b *= t; return c; }
18 Color4ub operator +(Color4ub a, Color4ub b) { a.a += b.a; a.r += b.r; a.g += b.g; a.b += b.b; return a; }
19
20 inline Color4ub colorToColor4ub(const QColor &c)
21 {
22 float r, g, b, a;
23 c.getRgbF(&r, &g, &b, &a);
24 Color4ub color = { uchar(qRound(r * a * 255)),
25 uchar(qRound(g * a * 255)),
26 uchar(qRound(b * a * 255)),
27 uchar(qRound(a * 255))
28 };
29 return color;
30 }
31
32 // Same layout as QSGGeometry::ColoredPoint2D, but uses Color4ub for convenience.
33 struct Vertex
34 {
35 float x, y;
37
38 void set(float primary, float secondary, Color4ub ncolor, bool vertical)
39 {
40 if (vertical) {
41 x = secondary; y = primary;
42 } else {
43 x = primary; y = secondary;
44 }
45 color = ncolor;
46 }
47 };
48
49 struct SmoothVertex : public Vertex
50 {
51 float dx, dy;
52
53 void set(float primary, float secondary, Color4ub ncolor, float dPrimary, float dSecondary, bool vertical)
54 {
55 Vertex::set(primary, secondary, ncolor, vertical);
56 if (vertical) {
57 dx = dSecondary; dy = dPrimary;
58 } else {
59 dx = dPrimary; dy = dSecondary;
60 }
61 }
62 };
63
65 {
66 static QSGGeometry::Attribute data[] = {
67 QSGGeometry::Attribute::createWithAttributeType(0, 2, QSGGeometry::FloatType, QSGGeometry::PositionAttribute),
68 QSGGeometry::Attribute::createWithAttributeType(1, 4, QSGGeometry::UnsignedByteType, QSGGeometry::ColorAttribute),
69 QSGGeometry::Attribute::createWithAttributeType(2, 2, QSGGeometry::FloatType, QSGGeometry::TexCoordAttribute)
70 };
71 static QSGGeometry::AttributeSet attrs = { 3, sizeof(SmoothVertex), data };
72 return attrs;
73 }
74}
75
76QSGBasicInternalRectangleNode::QSGBasicInternalRectangleNode()
77 : QSGInternalRectangleNode()
78 , m_aligned(true)
79 , m_antialiasing(false)
80 , m_gradient_is_opaque(true)
81 , m_dirty_geometry(false)
82 , m_gradient_is_vertical(true)
83 , m_isTopLeftRadiusSet(false)
84 , m_isTopRightRadiusSet(false)
85 , m_isBottomLeftRadiusSet(false)
86 , m_isBottomRightRadiusSet(false)
87 , m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0)
88{
89 setGeometry(&m_geometry);
90
91#ifdef QSG_RUNTIME_DESCRIPTION
92 qsgnode_set_description(this, QLatin1String("internalrectangle"));
93#endif
94}
95
96void QSGBasicInternalRectangleNode::setRect(const QRectF &rect)
97{
98 if (rect == m_rect)
99 return;
100 m_rect = rect;
101 m_dirty_geometry = true;
102}
103
104void QSGBasicInternalRectangleNode::setColor(const QColor &color)
105{
106 if (color == m_color)
107 return;
108 m_color = color;
109 if (m_gradient_stops.isEmpty())
110 m_dirty_geometry = true;
111}
112
113void QSGBasicInternalRectangleNode::setPenColor(const QColor &color)
114{
115 if (color == m_border_color)
116 return;
117 m_border_color = color;
118 if (m_pen_width > 0)
119 m_dirty_geometry = true;
120}
121
122void QSGBasicInternalRectangleNode::setPenWidth(qreal width)
123{
124 if (width == m_pen_width)
125 return;
126 m_pen_width = width;
127 m_dirty_geometry = true;
128}
129
130
131void QSGBasicInternalRectangleNode::setGradientStops(const QGradientStops &stops)
132{
133 if (stops.constData() == m_gradient_stops.constData())
134 return;
135
136 m_gradient_stops = stops;
137
138 m_gradient_is_opaque = true;
139 for (int i = 0; i < stops.size(); ++i)
140 m_gradient_is_opaque &= stops.at(i).second.alpha() == 0xff;
141 m_dirty_geometry = true;
142}
143
144void QSGBasicInternalRectangleNode::setGradientVertical(bool vertical)
145{
146 if (vertical == m_gradient_is_vertical)
147 return;
148 m_gradient_is_vertical = vertical;
149 m_dirty_geometry = true;
150}
151
152
153void QSGBasicInternalRectangleNode::setRadius(qreal radius)
154{
155 if (radius == m_radius)
156 return;
157 m_radius = radius;
158 m_dirty_geometry = true;
159}
160
161void QSGBasicInternalRectangleNode::setTopLeftRadius(qreal radius)
162{
163 if (m_isTopLeftRadiusSet && m_topLeftRadius == radius)
164 return;
165 m_isTopLeftRadiusSet = true;
166 m_topLeftRadius = radius;
167 m_dirty_geometry = true;
168}
169void QSGBasicInternalRectangleNode::setTopRightRadius(qreal radius)
170{
171 if (m_isTopRightRadiusSet && m_topRightRadius == radius)
172 return;
173 m_isTopRightRadiusSet = true;
174 m_topRightRadius = radius;
175 m_dirty_geometry = true;
176}
177void QSGBasicInternalRectangleNode::setBottomLeftRadius(qreal radius)
178{
179 if (m_isBottomLeftRadiusSet && m_bottomLeftRadius == radius)
180 return;
181 m_isBottomLeftRadiusSet = true;
182 m_bottomLeftRadius = radius;
183 m_dirty_geometry = true;
184}
185void QSGBasicInternalRectangleNode::setBottomRightRadius(qreal radius)
186{
187 if (m_isBottomRightRadiusSet && m_bottomRightRadius == radius)
188 return;
189 m_isBottomRightRadiusSet = true;
190 m_bottomRightRadius = radius;
191 m_dirty_geometry = true;
192}
193
194void QSGBasicInternalRectangleNode::resetTopLeftRadius()
195{
196 if (!m_isTopLeftRadiusSet)
197 return;
198 m_isTopLeftRadiusSet = false;
199 m_dirty_geometry = true;
200}
201
202void QSGBasicInternalRectangleNode::resetTopRightRadius()
203{
204 if (!m_isTopRightRadiusSet)
205 return;
206 m_isTopRightRadiusSet = false;
207 m_dirty_geometry = true;
208}
209
210void QSGBasicInternalRectangleNode::resetBottomLeftRadius()
211{
212 if (!m_isBottomLeftRadiusSet)
213 return;
214 m_isBottomLeftRadiusSet = false;
215 m_dirty_geometry = true;
216}
217
218void QSGBasicInternalRectangleNode::resetBottomRightRadius()
219{
220 if (!m_isBottomRightRadiusSet)
221 return;
222 m_isBottomRightRadiusSet = false;
223 m_dirty_geometry = true;
224}
225
226void QSGBasicInternalRectangleNode::setAntialiasing(bool antialiasing)
227{
228 if (!supportsAntialiasing())
229 return;
230
231 if (antialiasing == m_antialiasing)
232 return;
233 m_antialiasing = antialiasing;
234 if (m_antialiasing) {
235 setGeometry(new QSGGeometry(smoothAttributeSet(), 0));
236 setFlag(OwnsGeometry, true);
237 } else {
238 setGeometry(&m_geometry);
239 setFlag(OwnsGeometry, false);
240 }
241 updateMaterialAntialiasing();
242 m_dirty_geometry = true;
243}
244
245void QSGBasicInternalRectangleNode::setAligned(bool aligned)
246{
247 if (aligned == m_aligned)
248 return;
249 m_aligned = aligned;
250 m_dirty_geometry = true;
251}
252
253void QSGBasicInternalRectangleNode::update()
254{
255 if (m_dirty_geometry) {
256 updateGeometry();
257 m_dirty_geometry = false;
258
259 QSGNode::DirtyState state = QSGNode::DirtyGeometry;
260 updateMaterialBlending(&state);
261 markDirty(state);
262 }
263}
264
265void QSGBasicInternalRectangleNode::updateGeometry()
266{
267 float width = float(m_rect.width());
268 float height = float(m_rect.height());
269 float penWidth = qMin(qMin(width, height) * 0.5f, float(m_pen_width));
270
271 if (m_aligned)
272 penWidth = qRound(penWidth);
273
274 QSGGeometry *g = geometry();
275 g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
276 int vertexStride = g->sizeOfVertex();
277
278 union {
279 Vertex *vertices;
280 SmoothVertex *smoothVertices;
281 };
282
283 Color4ub fillColor = colorToColor4ub(m_color);
284 Color4ub borderColor = colorToColor4ub(m_border_color);
285 Color4ub transparent = { 0, 0, 0, 0 };
286 const QGradientStops &stops = m_gradient_stops;
287
288 float gradientStart = (m_gradient_is_vertical ? m_rect.top() : m_rect.left());
289 float gradientLength = (m_gradient_is_vertical ? height : width);
290 float secondaryLength = (m_gradient_is_vertical ? width : height);
291
292 int nextGradientStop = 0;
293 float gradientPos = penWidth / gradientLength;
294 while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
295 ++nextGradientStop;
296 int lastGradientStop = stops.size() - 1;
297 float lastGradientPos = 1.0f - penWidth / gradientLength;
298 while (lastGradientStop >= nextGradientStop && stops.at(lastGradientStop).first >= lastGradientPos)
299 --lastGradientStop;
300 int gradientIntersections = (lastGradientStop - nextGradientStop + 1);
301
302 if (m_radius > 0
303 || m_isTopLeftRadiusSet
304 || m_isTopRightRadiusSet
305 || m_isBottomLeftRadiusSet
306 || m_isBottomRightRadiusSet) {
307 // Rounded corners.
308
309 // Radius should never exceed half the width or half the height.
310 float radiusTL = qMin(qMin(width, height) * 0.4999f,
311 float(m_isTopLeftRadiusSet ? m_topLeftRadius : m_radius));
312 float radiusTR = qMin(qMin(width, height) * 0.4999f,
313 float(m_isTopRightRadiusSet ? m_topRightRadius : m_radius));
314 float radiusBL = qMin(qMin(width, height) * 0.4999f,
315 float(m_isBottomLeftRadiusSet ? m_bottomLeftRadius : m_radius));
316 float radiusBR = qMin(qMin(width, height) * 0.4999f,
317 float(m_isBottomRightRadiusSet ? m_bottomRightRadius : m_radius));
318
319 // The code produces some artefacts when radius <= 0.5. A radius of half a pixel
320 // does not make much sense anyway, so we draw a normal corner in such a case.
321 if (radiusTL <= 0.5)
322 radiusTL = 0;
323 if (radiusTR <= 0.5)
324 radiusTR = 0;
325 if (radiusBL <= 0.5)
326 radiusBL = 0;
327 if (radiusBR <= 0.5)
328 radiusBR = 0;
329
330 // We want to keep a minimal inner radius in order to make the inner
331 // x-coordinates of an arc mathematically unique and identifiable.
332 const float innerRadiusTL = qMax(radiusTL - penWidth * 1.0f, 0.01);
333 const float innerRadiusTR = qMax(radiusTR - penWidth * 1.0f, 0.01);
334 const float innerRadiusBL = qMax(radiusBL - penWidth * 1.0f, 0.01);
335 const float innerRadiusBR = qMax(radiusBR - penWidth * 1.0f, 0.01);
336 const float outerRadiusTL = radiusTL;
337 const float outerRadiusTR = radiusTR;
338 const float outerRadiusBL = radiusBL;
339 const float outerRadiusBR = radiusBR;
340 const float delta = qMin(width, height) * 0.5f;
341
342 int segmentsTL = radiusTL == 0 ? 0 : qBound(3, qCeil(radiusTL * (M_PI / 6)), 18);
343 int segmentsTR = radiusTR == 0 ? 0 : qBound(3, qCeil(radiusTR * (M_PI / 6)), 18);
344 int segmentsBL = radiusBL == 0 ? 0 : qBound(3, qCeil(radiusBL * (M_PI / 6)), 18);
345 int segmentsBR = radiusBR == 0 ? 0 : qBound(3, qCeil(radiusBR * (M_PI / 6)), 18);
346
347 // If the radii on opposite sites in genraration direction are the same,
348 // we will set the segments of one side to 0 as these points would be
349 // calculated twice. Also, this optimizes for the case of similar radii
350 if (m_gradient_is_vertical) {
351 if (innerRadiusTL == innerRadiusTR) {
352 if (segmentsTL <= segmentsTR)
353 segmentsTL = 0;
354 else
355 segmentsTR = 0;
356 }
357 if (innerRadiusBL == innerRadiusBR){
358 if (segmentsBL <= segmentsBR)
359 segmentsBL = 0;
360 else
361 segmentsBR = 0;
362 }
363 } else {
364 if (innerRadiusTL == innerRadiusBL) {
365 if (segmentsTL <= segmentsBL)
366 segmentsTL = 0;
367 else
368 segmentsBL = 0;
369 }
370 if (innerRadiusTR == innerRadiusBR) {
371 if (segmentsTR <= segmentsBR)
372 segmentsTR = 0;
373 else
374 segmentsBR = 0;
375 }
376 }
377
378 const int sumSegments = segmentsTL + segmentsTR + segmentsBL + segmentsBR;
379
380 /*
381
382 --+--__
383 --+--__--__
384 | --__--__
385 | seg --__--+
386 --+-__ ment _+ \
387 --+-__--__ - \ \
388 --__--+ se \ \
389 + \ g \ \
390 \ \ m \ \
391 -----------+--+ e \ \ <- gradient line
392 \ \ nt\ \
393 fill +--+----+--+
394 | | | |
395 border
396 inner AA outer AA (AA = antialiasing)
397
398 */
399
400 const int innerVertexCount = (sumSegments + 4) * 2 + gradientIntersections * 2;
401 const int outerVertexCount = (sumSegments + 4) * 2;
402 int vertexCount = innerVertexCount;
403 if (m_antialiasing || penWidth)
404 vertexCount += innerVertexCount;
405 if (penWidth)
406 vertexCount += outerVertexCount;
407 if (m_antialiasing && penWidth)
408 vertexCount += outerVertexCount;
409
410
411 const int fillIndexCount = innerVertexCount;
412 const int innerAAIndexCount = innerVertexCount * 2 + 2;
413 const int borderIndexCount = innerVertexCount * 2 + 2;
414 const int outerAAIndexCount = outerVertexCount * 2 + 2;
415 int indexCount = 0;
416 int fillHead = 0;
417 int innerAAHead = 0;
418 int innerAATail = 0;
419 int borderHead = 0;
420 int borderTail = 0;
421 int outerAAHead = 0;
422 int outerAATail = 0;
423 bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
424 if (hasFill)
425 indexCount += fillIndexCount;
426 if (m_antialiasing) {
427 innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
428 indexCount += innerAAIndexCount;
429 }
430 if (penWidth) {
431 borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
432 indexCount += borderIndexCount;
433 }
434 if (m_antialiasing && penWidth) {
435 outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
436 indexCount += outerAAIndexCount;
437 }
438
439 g->allocate(vertexCount, indexCount);
440 vertices = reinterpret_cast<Vertex *>(g->vertexData());
441 memset(vertices, 0, vertexCount * vertexStride);
442 quint16 *indices = g->indexDataAsUShort();
443 quint16 index = 0;
444
445
446 float innerXPrev = 0.; // previous inner primary coordinate, both sides.
447 float innerYLeftPrev = 0.; // previous inner secondary coordinate, left.
448 float innerYRightPrev = 0.; // previous inner secondary coordinate, right.
449
450 const float angleTL = 0.5f * float(M_PI) / segmentsTL;
451 const float cosStepTL = qFastCos(angleTL);
452 const float sinStepTL = qFastSin(angleTL);
453 const float angleTR = 0.5f * float(M_PI) / segmentsTR;
454 const float cosStepTR = qFastCos(angleTR);
455 const float sinStepTR = qFastSin(angleTR);
456 const float angleBL = 0.5f * float(M_PI) / segmentsBL;
457 const float cosStepBL = qFastCos(angleBL);
458 const float sinStepBL = qFastSin(angleBL);
459 const float angleBR = 0.5f * float(M_PI) / segmentsBR;
460 const float cosStepBR = qFastCos(angleBR);
461 const float sinStepBR = qFastSin(angleBR);
462
463 //The x- and y-Axis are transposed, depending on gradient being vertical or horizontal
464 //Lets define some coordinates and radii. The first index is the part, the second index
465 //is the left or right side, as seen when moving from part0 to part1
466
467 // left vertices | right vertices
468 // |
469 // *************|**************
470 // * | | | *
471 // *--o | o--*
472 // * innerX/Y | innerX/Y *
473 // * | *
474 // * | * part 0
475 // * | *
476 // * | *
477 // * | *
478 // -----------------+--------------------> y
479 // * | *
480 // * | *
481 // * | *
482 // * | * part 1
483 // * | *
484 // * innerX/Y | innerX/Y *
485 // *--o | o--*
486 // * | | | *
487 // *************|**************
488 // |
489 // v x
490 //
491 // direction of vertex generation
492
493 const float outerXCenter[][2] = {{
494 float(m_gradient_is_vertical ? m_rect.top() + radiusTL : m_rect.left() + radiusTL),
495 float(m_gradient_is_vertical ? m_rect.top() + radiusTR : m_rect.left() + radiusBL)
496 }, {
497 float(m_gradient_is_vertical ? m_rect.bottom() - radiusBL : m_rect.right() - radiusTR),
498 float(m_gradient_is_vertical ? m_rect.bottom() - radiusBR : m_rect.right() - radiusBR)
499 }};
500
501 const float outerYCenter[][2] = {{
502 float(!m_gradient_is_vertical ? m_rect.top() + outerRadiusTL : m_rect.left() + outerRadiusTL),
503 float(!m_gradient_is_vertical ? m_rect.bottom() - outerRadiusBL : m_rect.right() - outerRadiusTR)
504 }, {
505 float(!m_gradient_is_vertical ? m_rect.top() + outerRadiusTR : m_rect.left() + outerRadiusBL),
506 float(!m_gradient_is_vertical ? m_rect.bottom() - outerRadiusBR : m_rect.right() - outerRadiusBR)
507 }};
508
509 const float innerXCenter[][2] = { {
510 float(m_gradient_is_vertical ? m_rect.top() + innerRadiusTL + penWidth : m_rect.left() + innerRadiusTL + penWidth),
511 float(m_gradient_is_vertical ? m_rect.top() + innerRadiusTR + penWidth: m_rect.left() + innerRadiusBL + penWidth)
512 }, {
513 float(m_gradient_is_vertical ? m_rect.bottom() - innerRadiusBL - penWidth: m_rect.right() - innerRadiusTR - penWidth),
514 float(m_gradient_is_vertical ? m_rect.bottom() - innerRadiusBR - penWidth: m_rect.right() - innerRadiusBR - penWidth)
515 }};
516
517 const float innerYCenter[][2] = { {
518 float(!m_gradient_is_vertical ? m_rect.top() + innerRadiusTL + penWidth : m_rect.left() + innerRadiusTL + penWidth),
519 float(!m_gradient_is_vertical ? m_rect.bottom() - innerRadiusBL - penWidth : m_rect.right() - innerRadiusTR - penWidth)
520 },{
521 float(!m_gradient_is_vertical ? m_rect.top() + innerRadiusTR + penWidth : m_rect.left() + innerRadiusBL + penWidth),
522 float(!m_gradient_is_vertical ? m_rect.bottom() - innerRadiusBR - penWidth : m_rect.right() - innerRadiusBR - penWidth)
523 }};
524
525 const float innerRadius[][2] = {{
526 innerRadiusTL,
527 !m_gradient_is_vertical ? innerRadiusBL : innerRadiusTR
528 }, {
529 !m_gradient_is_vertical ? innerRadiusTR : innerRadiusBL,
530 innerRadiusBR
531 }};
532
533 const float outerRadius[][2] = {{
534 outerRadiusTL,
535 !m_gradient_is_vertical ? outerRadiusBL : outerRadiusTR
536 }, {
537 !m_gradient_is_vertical ? outerRadiusTR : outerRadiusBL,
538 outerRadiusBR
539 }};
540
541 const int segments[][2] = {{
542 segmentsTL,
543 !m_gradient_is_vertical ? segmentsBL : segmentsTR
544 }, {
545 !m_gradient_is_vertical ? segmentsTR : segmentsBL,
546 segmentsBR
547 }};
548
549 const float cosStep[][2] = {{
550 cosStepTL,
551 !m_gradient_is_vertical ? cosStepBL : cosStepTR
552 }, {
553 !m_gradient_is_vertical ? cosStepTR : cosStepBL,
554 cosStepBR
555 }};
556
557 const float sinStep[][2] = {{
558 sinStepTL,
559 !m_gradient_is_vertical ? sinStepBL : sinStepTR
560 }, {
561 !m_gradient_is_vertical ? sinStepTR : sinStepBL,
562 sinStepBR
563 }};
564
565 auto fillColorFromX = [&](float x) {
566
567 float t = (x - gradientStart) / gradientLength;
568 t = qBound(0.0, t, 1.0);
569
570 int i = 1;
571 if (t < stops.first().first)
572 return colorToColor4ub(stops.first().second);
573 while (i < stops.size()) {
574 const QGradientStop &prev = stops.at(i - 1);
575 const QGradientStop &next = stops.at(i);
576 if (prev.first <= t && next.first > t) {
577 t = (t - prev.first) / (next.first - prev.first);
578 return colorToColor4ub(prev.second) * (1. - t) + colorToColor4ub(next.second) * t; }
579 i++;
580 }
581 return colorToColor4ub(stops.last().second);
582 };
583
584 for (int part = 0; part < 2; ++part) {
585 // cosine of the angle of the current segment, starting at 1 for part 0 and 0 for part 1
586 float cosSegmentAngleLeft = 1. - part;
587 // sine of the angle of the current segment
588 float sinSegmentAngleLeft = part;
589
590 float cosSegmentAngleRight = 1. - part;
591 float sinSegmentAngleRight = part;
592
593 bool advanceLeft = true;
594
595 // We draw both the left part and the right part of the rectangle at the same time.
596 // We also draw a vertex on the left side for every vertex on the right side. This
597 // syncronisation is required to make sure that all gradient stops can be inserted.
598 for (int iLeft = 0, iRight = 0; iLeft <= segments[part][0] || iRight <= segments[part][1]; ) {
599
600 float xLeft, yLeft,
601 xRight, yRight;
602
603 float outerXLeft, outerYLeft,
604 outerXRight, outerYRight;
605
606 float sinAngleLeft, cosAngleLeft,
607 sinAngleRight, cosAngleRight;
608
609 // calculate inner x-coordinates
610 xLeft = innerXCenter[part][0] - innerRadius[part][0] * cosSegmentAngleLeft;
611 xRight = innerXCenter[part][1] - innerRadius[part][1] * cosSegmentAngleRight;
612
613 // calcuate inner y-coordinates
614 yLeft = innerYCenter[part][0] - innerRadius[part][0] * sinSegmentAngleLeft;
615 yRight = innerYCenter[part][1] + innerRadius[part][1] * sinSegmentAngleRight;
616
617 // Synchronize left and right hand x-coordinates. This is required to
618 // make sure that we can insert all gradient stops that require exactly two triangles at
619 // every x-coordinate. Take the smaller of both x-coordinates and then find the matching
620 // y-coordinates.
621 if ((iLeft <= segments[part][0] && xLeft <= xRight) || iRight > segments[part][1]) {
622 advanceLeft = true;
623 } else {
624 advanceLeft = false;
625 }
626
627 // Inner: Find the matching y-coordinates for the x-coordinate found above.
628 // Outer: Also set the sine and cosine to make sure that outer vertices are
629 // drawn correctly.
630 if (innerRadius[part][0] == innerRadius[part][1]) {
631 // Special case of equal radii. Optimize to avoid performance regression:
632 // Left and right is always equal and we can just copy the angles and
633 // mirror the coordinates.
634 if (advanceLeft) {
635 if (outerRadius[part][0] == 0) {
636 sinAngleLeft = 1.;
637 cosAngleLeft = part ? -1. : 1.;
638 } else {
639 sinAngleLeft = sinSegmentAngleLeft;
640 cosAngleLeft = cosSegmentAngleLeft;
641 }
642 if (outerRadius[part][1] == 0) {
643 sinAngleRight = 1.;
644 cosAngleRight = part ? -1. : 1.;
645 } else {
646 sinAngleRight = sinSegmentAngleLeft;
647 cosAngleRight = cosSegmentAngleLeft;
648 }
649 xRight = xLeft;
650 yRight = innerYCenter[part][1] + innerRadius[part][1] * sinAngleRight;
651 } else {
652 if (outerRadius[part][0] == 0) {
653 sinAngleLeft = 1.;
654 cosAngleLeft = part ? -1. : 1.;
655 } else {
656 sinAngleLeft = sinSegmentAngleRight;
657 cosAngleLeft = cosSegmentAngleRight;
658 }
659 if (outerRadius[part][1] == 0) {
660 sinAngleRight = 1.;
661 cosAngleRight = part ? -1. : 1.;
662 } else {
663 sinAngleRight = sinSegmentAngleRight;
664 cosAngleRight = cosSegmentAngleRight;
665 }
666 xLeft = xRight;
667 yLeft = innerYCenter[part][0] - innerRadius[part][0] * sinAngleLeft;
668 }
669 } else if (advanceLeft) {
670 if (outerRadius[part][0] == 0) {
671 sinAngleLeft = 1.;
672 cosAngleLeft = part ? -1. : 1.;
673 } else {
674 sinAngleLeft = sinSegmentAngleLeft;
675 cosAngleLeft = cosSegmentAngleLeft;
676 }
677 if (outerRadius[part][1] == 0) {
678 // Outer: If the outer radius is zero we can return both sin and cos = 1
679 // to form a nice corner. Inner: Accept the x-coordinate from the other
680 // side and match the y-coordinate
681 sinAngleRight = 1.;
682 cosAngleRight = part ? -1. : 1.;
683 xRight = xLeft;
684 yRight = innerYCenter[part][1] + innerRadius[part][1] * sinAngleRight;
685 } else if (xLeft >= innerXCenter[0][1] && xLeft <= innerXCenter[1][1]) {
686 // Outer: If we are on the straight line between the inner centers, we can
687 // just return sin = 1 and cos = 0. Inner: Accept the x-coordinate from the
688 // other side and match the y-coordinate
689 sinAngleRight = 1.;
690 cosAngleRight = 0.;
691 xRight = xLeft;
692 yRight = innerYCenter[part][1] + innerRadius[part][1] * sinAngleRight;
693 } else {
694 // Inner: If we are on the rounded part of the oposite side, we have to find a vertex
695 // on that curve that matches the x-coordinate we selected.
696 // We always select the smaller x-coordinate and can therefore use a linear
697 // interpolation between the last point on this side and the point on this side
698 // that was not accepted because it was too large.
699 if (xRight != innerXPrev) {
700 float t = (xLeft - innerXPrev) / (xRight - innerXPrev);
701 yRight = innerYRightPrev * (1. - t) + yRight * t;
702 xRight = xLeft;
703 }
704 // Outer: With the coordinates from the interpolation we can calculate the sine
705 // and cosine of the respective angle quickly.
706 sinAngleRight = (yRight - innerYCenter[part][1]) / innerRadius[part][1];
707 cosAngleRight = -(xRight - innerXCenter[part][1]) / innerRadius[part][1];
708 }
709 } else {
710 // same as above but for the other side.
711 if (outerRadius[part][1] == 0) {
712 sinAngleRight = 1.;
713 cosAngleRight = part ? -1. : 1.;
714 } else {
715 sinAngleRight = sinSegmentAngleRight;
716 cosAngleRight = cosSegmentAngleRight;
717 }
718 if (outerRadius[part][0] == 0) {
719 sinAngleLeft = 1.;
720 cosAngleLeft = part ? -1. : 1.;
721 xLeft = xRight;
722 yLeft = innerYCenter[part][0] - innerRadius[part][0] * sinAngleLeft;
723 } else if (xRight >= innerXCenter[0][0] && xRight <= innerXCenter[1][0]) {
724 sinAngleLeft = 1.;
725 cosAngleLeft = 0.;
726 xLeft = xRight;
727 yLeft = innerYCenter[part][0] - innerRadius[part][0] * sinAngleLeft;
728 } else {
729 if (xLeft != innerXPrev) {
730 float t = (xRight - innerXPrev) / (xLeft - innerXPrev);
731 yLeft = innerYLeftPrev * (1. - t) + yLeft * t;
732 xLeft = xRight;
733 }
734 sinAngleLeft = -(yLeft - innerYCenter[part][0]) / innerRadius[part][0];
735 cosAngleLeft = -(xLeft - innerXCenter[part][0]) / innerRadius[part][0];
736 }
737 }
738
739 gradientPos = (xLeft - gradientStart) / gradientLength;
740
741 // calculate the matching outer coordinates
742 outerXLeft = outerXCenter[part][0] - outerRadius[part][0] * cosAngleLeft;
743 outerYLeft = outerYCenter[part][0] - outerRadius[part][0] * sinAngleLeft;
744 outerXRight = outerXCenter[part][1] - outerRadius[part][1] * cosAngleRight;
745 outerYRight = outerYCenter[part][1] + outerRadius[part][1] * sinAngleRight;
746
747 // insert gradient stops as required
748 while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
749 float gradientX;
750 float gradientYLeft;
751 float gradientYRight;
752
753 // Insert vertices at gradient stops
754 gradientX = gradientStart + stops.at(nextGradientStop).first * gradientLength;
755 // bilinear interpolation of known vertices
756 float t = (gradientX - innerXPrev) / (xLeft - innerXPrev);
757 gradientYLeft = innerYLeftPrev * (1. - t) + t * yLeft;
758 gradientYRight = innerYRightPrev * (1. - t) + t * yRight;
759
760 fillColor = fillColorFromX(gradientX);
761
762 if (hasFill) {
763 indices[fillHead++] = index;
764 indices[fillHead++] = index + 1;
765 }
766
767 if (penWidth) {
768 --borderHead;
769 indices[borderHead] = indices[borderHead + 2];
770 indices[--borderHead] = index + 2;
771 indices[borderTail++] = index + 3;
772 indices[borderTail] = indices[borderTail - 2];
773 ++borderTail;
774 }
775
776 if (m_antialiasing) {
777 indices[--innerAAHead] = index + 2;
778 indices[--innerAAHead] = index;
779 indices[innerAATail++] = index + 1;
780 indices[innerAATail++] = index + 3;
781
782 bool lower = stops.at(nextGradientStop).first > 0.5f;
783 float dp = lower ? qMin(0.0f, gradientLength - gradientX - delta) : qMax(0.0f, delta - gradientX);
784 smoothVertices[index++].set(gradientX, gradientYRight, fillColor, dp, secondaryLength - gradientYRight - delta, m_gradient_is_vertical);
785 smoothVertices[index++].set(gradientX, gradientYLeft, fillColor, dp, delta - gradientYLeft, m_gradient_is_vertical);
786 if (penWidth) {
787 smoothVertices[index++].set(gradientX, gradientYRight, borderColor, -0.49f * penWidth * cosAngleRight, 0.49f * penWidth * sinAngleRight, m_gradient_is_vertical);
788 smoothVertices[index++].set(gradientX, gradientYLeft, borderColor, -0.49f * penWidth * cosAngleLeft, -0.49f * penWidth * sinAngleLeft, m_gradient_is_vertical);
789 } else {
790 dp = lower ? delta : -delta;
791 smoothVertices[index++].set(gradientX, gradientYRight, transparent, dp, delta, m_gradient_is_vertical);
792 smoothVertices[index++].set(gradientX, gradientYLeft, transparent, dp, -delta, m_gradient_is_vertical);
793 }
794 } else {
795 vertices[index++].set(gradientX, gradientYRight, fillColor, m_gradient_is_vertical);
796 vertices[index++].set(gradientX, gradientYLeft, fillColor, m_gradient_is_vertical);
797 if (penWidth) {
798 vertices[index++].set(gradientX, gradientYRight, borderColor, m_gradient_is_vertical);
799 vertices[index++].set(gradientX, gradientYLeft, borderColor, m_gradient_is_vertical);
800 }
801 }
802
803 innerXPrev = gradientX;
804 innerYLeftPrev = gradientYLeft;
805 innerYRightPrev = gradientYRight;
806
807 nextGradientStop++;
808 }
809
810 if (!stops.isEmpty()) {
811 fillColor = fillColorFromX(xLeft);
812 }
813
814 if (hasFill) {
815 indices[fillHead++] = index;
816 indices[fillHead++] = index + 1;
817 }
818
819 if (penWidth) {
820 indices[--borderHead] = index + 4;
821 indices[--borderHead] = index + 2;
822 indices[borderTail++] = index + 3;
823 indices[borderTail++] = index + 5;
824 }
825
826 if (m_antialiasing) {
827 indices[--innerAAHead] = index + 2;
828 indices[--innerAAHead] = index;
829 indices[innerAATail++] = index + 1;
830 indices[innerAATail++] = index + 3;
831
832 float dp = part ? qMin(0.0f, gradientLength - xRight - delta) : qMax(0.0f, delta - xRight);
833 smoothVertices[index++].set(xRight, yRight, fillColor, dp, secondaryLength - yRight - delta, m_gradient_is_vertical);
834 smoothVertices[index++].set(xLeft, yLeft, fillColor, dp, delta - yLeft, m_gradient_is_vertical);
835
836 dp = part ? delta : -delta;
837 if (penWidth) {
838 smoothVertices[index++].set(xRight, yRight, borderColor, -0.49f * penWidth * cosAngleRight, 0.49f * penWidth * sinAngleRight, m_gradient_is_vertical);
839 smoothVertices[index++].set(xLeft, yLeft, borderColor, -0.49f * penWidth * cosAngleLeft, -0.49f * penWidth * sinAngleLeft, m_gradient_is_vertical);
840 smoothVertices[index++].set(outerXRight, outerYRight, borderColor, 0.49f * penWidth * cosAngleRight, -0.49f * penWidth * sinAngleRight, m_gradient_is_vertical);
841 smoothVertices[index++].set(outerXLeft, outerYLeft, borderColor, 0.49f * penWidth * cosAngleLeft, 0.49f * penWidth * sinAngleLeft, m_gradient_is_vertical);
842 smoothVertices[index++].set(outerXRight, outerYRight, transparent, dp, delta, m_gradient_is_vertical);
843 smoothVertices[index++].set(outerXLeft, outerYLeft, transparent, dp, -delta, m_gradient_is_vertical);
844
845 indices[--outerAAHead] = index - 2;
846 indices[--outerAAHead] = index - 4;
847 indices[outerAATail++] = index - 3;
848 indices[outerAATail++] = index - 1;
849 } else {
850 smoothVertices[index++].set(xRight, yRight, transparent, dp, delta, m_gradient_is_vertical);
851 smoothVertices[index++].set(xLeft, yLeft, transparent, dp, -delta, m_gradient_is_vertical);
852 }
853 } else {
854 vertices[index++].set(xRight, yRight, fillColor, m_gradient_is_vertical);
855 vertices[index++].set(xLeft, yLeft, fillColor, m_gradient_is_vertical);
856 if (penWidth) {
857 vertices[index++].set(xRight, yRight, borderColor, m_gradient_is_vertical);
858 vertices[index++].set(xLeft, yLeft, borderColor, m_gradient_is_vertical);
859 vertices[index++].set(outerXRight, outerYRight, borderColor, m_gradient_is_vertical);
860 vertices[index++].set(outerXLeft, outerYLeft, borderColor, m_gradient_is_vertical);
861 }
862 }
863
864 innerXPrev = xLeft;
865 innerYLeftPrev = yLeft;
866 innerYRightPrev = yRight;
867
868 // Advance the point. This corresponds to a rotation of the respective segment
869 if (advanceLeft) {
870 iLeft++;
871 qreal tmp = cosSegmentAngleLeft;
872 cosSegmentAngleLeft = cosSegmentAngleLeft * cosStep[part][0] - sinSegmentAngleLeft * sinStep[part][0];
873 sinSegmentAngleLeft = sinSegmentAngleLeft * cosStep[part][0] + tmp * sinStep[part][0];
874 } else {
875 iRight++;
876 qreal tmp = cosSegmentAngleRight;
877 cosSegmentAngleRight = cosSegmentAngleRight * cosStep[part][1] - sinSegmentAngleRight * sinStep[part][1];
878 sinSegmentAngleRight = sinSegmentAngleRight * cosStep[part][1] + tmp * sinStep[part][1];
879 }
880 }
881 }
882
883 Q_ASSERT(index == vertexCount);
884
885 // Close the triangle strips.
886 if (m_antialiasing) {
887 indices[--innerAAHead] = indices[innerAATail - 1];
888 indices[--innerAAHead] = indices[innerAATail - 2];
889 Q_ASSERT(innerAATail <= indexCount);
890 }
891 if (penWidth) {
892 indices[--borderHead] = indices[borderTail - 1];
893 indices[--borderHead] = indices[borderTail - 2];
894 Q_ASSERT(borderTail <= indexCount);
895 }
896 if (m_antialiasing && penWidth) {
897 indices[--outerAAHead] = indices[outerAATail - 1];
898 indices[--outerAAHead] = indices[outerAATail - 2];
899 Q_ASSERT(outerAATail == indexCount);
900 }
901 } else {
902 // Straight corners.
903 QRectF innerRect = m_rect;
904 QRectF outerRect = m_rect;
905
906 if (penWidth)
907 innerRect.adjust(1.0f * penWidth, 1.0f * penWidth, -1.0f * penWidth, -1.0f * penWidth);
908
909 float delta = qMin(width, height) * 0.5f;
910 int innerVertexCount = 4 + gradientIntersections * 2;
911 int outerVertexCount = 4;
912 int vertexCount = innerVertexCount;
913 if (m_antialiasing || penWidth)
914 vertexCount += innerVertexCount;
915 if (penWidth)
916 vertexCount += outerVertexCount;
917 if (m_antialiasing && penWidth)
918 vertexCount += outerVertexCount;
919
920 int fillIndexCount = innerVertexCount;
921 int innerAAIndexCount = innerVertexCount * 2 + 2;
922 int borderIndexCount = innerVertexCount * 2 + 2;
923 int outerAAIndexCount = outerVertexCount * 2 + 2;
924 int indexCount = 0;
925 int fillHead = 0;
926 int innerAAHead = 0;
927 int innerAATail = 0;
928 int borderHead = 0;
929 int borderTail = 0;
930 int outerAAHead = 0;
931 int outerAATail = 0;
932 bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
933 if (hasFill)
934 indexCount += fillIndexCount;
935 if (m_antialiasing) {
936 innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
937 indexCount += innerAAIndexCount;
938 }
939 if (penWidth) {
940 borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
941 indexCount += borderIndexCount;
942 }
943 if (m_antialiasing && penWidth) {
944 outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
945 indexCount += outerAAIndexCount;
946 }
947
948 g->allocate(vertexCount, indexCount);
949 vertices = reinterpret_cast<Vertex *>(g->vertexData());
950 memset(vertices, 0, vertexCount * vertexStride);
951 quint16 *indices = g->indexDataAsUShort();
952 quint16 index = 0;
953
954 float innerStart = (m_gradient_is_vertical ? innerRect.top() : innerRect.left());
955 float innerEnd = (m_gradient_is_vertical ? innerRect.bottom() : innerRect.right());
956 float outerStart = (m_gradient_is_vertical ? outerRect.top() : outerRect.left());
957 float outerEnd = (m_gradient_is_vertical ? outerRect.bottom() : outerRect.right());
958
959 float innerSecondaryStart = (m_gradient_is_vertical ? innerRect.left() : innerRect.top());
960 float innerSecondaryEnd = (m_gradient_is_vertical ? innerRect.right() : innerRect.bottom());
961 float outerSecondaryStart = (m_gradient_is_vertical ? outerRect.left() : outerRect.top());
962 float outerSecondaryEnd = (m_gradient_is_vertical ? outerRect.right() : outerRect.bottom());
963
964 for (int part = -1; part <= 1; part += 2) {
965 float innerEdge = (part == 1 ? innerEnd : innerStart);
966 float outerEdge = (part == 1 ? outerEnd : outerStart);
967 gradientPos = (innerEdge - innerStart + penWidth) / gradientLength;
968
969 while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
970 // Insert vertices at gradient stops.
971 float gp = (innerStart - penWidth) + stops.at(nextGradientStop).first * gradientLength;
972
973 fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
974
975 if (hasFill) {
976 indices[fillHead++] = index;
977 indices[fillHead++] = index + 1;
978 }
979
980 if (penWidth) {
981 --borderHead;
982 indices[borderHead] = indices[borderHead + 2];
983 indices[--borderHead] = index + 2;
984 indices[borderTail++] = index + 3;
985 indices[borderTail] = indices[borderTail - 2];
986 ++borderTail;
987 }
988
989 if (m_antialiasing) {
990 indices[--innerAAHead] = index + 2;
991 indices[--innerAAHead] = index;
992 indices[innerAATail++] = index + 1;
993 indices[innerAATail++] = index + 3;
994
995 bool lower = stops.at(nextGradientStop).first > 0.5f;
996 float dp = lower ? qMin(0.0f, gradientLength - gp - delta) : qMax(0.0f, delta - gp);
997 smoothVertices[index++].set(gp, innerSecondaryEnd, fillColor, dp, secondaryLength - innerSecondaryEnd - delta, m_gradient_is_vertical);
998 smoothVertices[index++].set(gp, innerSecondaryStart, fillColor, dp, delta - innerSecondaryStart, m_gradient_is_vertical);
999 if (penWidth) {
1000 smoothVertices[index++].set(gp, innerSecondaryEnd, borderColor, (lower ? 0.49f : -0.49f) * penWidth, 0.49f * penWidth, m_gradient_is_vertical);
1001 smoothVertices[index++].set(gp, innerSecondaryStart, borderColor, (lower ? 0.49f : -0.49f) * penWidth, -0.49f * penWidth, m_gradient_is_vertical);
1002 } else {
1003 smoothVertices[index++].set(gp, innerSecondaryEnd, transparent, lower ? delta : -delta, delta, m_gradient_is_vertical);
1004 smoothVertices[index++].set(gp, innerSecondaryStart, transparent, lower ? delta : -delta, -delta, m_gradient_is_vertical);
1005 }
1006 } else {
1007 vertices[index++].set(gp, innerSecondaryEnd, fillColor, m_gradient_is_vertical);
1008 vertices[index++].set(gp, innerSecondaryStart, fillColor, m_gradient_is_vertical);
1009 if (penWidth) {
1010 vertices[index++].set(gp, innerSecondaryEnd, borderColor, m_gradient_is_vertical);
1011 vertices[index++].set(gp, innerSecondaryStart, borderColor, m_gradient_is_vertical);
1012 }
1013 }
1014 ++nextGradientStop;
1015 }
1016
1017 if (!stops.isEmpty()) {
1018 if (nextGradientStop == 0) {
1019 fillColor = colorToColor4ub(stops.at(0).second);
1020 } else if (nextGradientStop == stops.size()) {
1021 fillColor = colorToColor4ub(stops.last().second);
1022 } else {
1023 const QGradientStop &prev = stops.at(nextGradientStop - 1);
1024 const QGradientStop &next = stops.at(nextGradientStop);
1025 float t = (gradientPos - prev.first) / (next.first - prev.first);
1026 fillColor = colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t;
1027 }
1028 }
1029
1030 if (hasFill) {
1031 indices[fillHead++] = index;
1032 indices[fillHead++] = index + 1;
1033 }
1034
1035 if (penWidth) {
1036 indices[--borderHead] = index + 4;
1037 indices[--borderHead] = index + 2;
1038 indices[borderTail++] = index + 3;
1039 indices[borderTail++] = index + 5;
1040 }
1041
1042 if (m_antialiasing) {
1043 indices[--innerAAHead] = index + 2;
1044 indices[--innerAAHead] = index;
1045 indices[innerAATail++] = index + 1;
1046 indices[innerAATail++] = index + 3;
1047
1048 float dp = part == 1 ? qMin(0.0f, gradientLength - innerEdge - delta) : qMax(0.0f, delta - innerEdge);
1049 smoothVertices[index++].set(innerEdge, innerSecondaryEnd, fillColor, dp, secondaryLength - innerSecondaryEnd - delta, m_gradient_is_vertical);
1050 smoothVertices[index++].set(innerEdge, innerSecondaryStart, fillColor, dp, delta - innerSecondaryStart, m_gradient_is_vertical);
1051
1052 if (penWidth) {
1053 smoothVertices[index++].set(innerEdge, innerSecondaryEnd, borderColor, 0.49f * penWidth * part, 0.49f * penWidth, m_gradient_is_vertical);
1054 smoothVertices[index++].set(innerEdge, innerSecondaryStart, borderColor, 0.49f * penWidth * part, -0.49f * penWidth, m_gradient_is_vertical);
1055 smoothVertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, -0.49f * penWidth * part, -0.49f * penWidth, m_gradient_is_vertical);
1056 smoothVertices[index++].set(outerEdge, outerSecondaryStart, borderColor, -0.49f * penWidth * part, 0.49f * penWidth, m_gradient_is_vertical);
1057 smoothVertices[index++].set(outerEdge, outerSecondaryEnd, transparent, delta * part, delta, m_gradient_is_vertical);
1058 smoothVertices[index++].set(outerEdge, outerSecondaryStart, transparent, delta * part, -delta, m_gradient_is_vertical);
1059
1060 indices[--outerAAHead] = index - 2;
1061 indices[--outerAAHead] = index - 4;
1062 indices[outerAATail++] = index - 3;
1063 indices[outerAATail++] = index - 1;
1064 } else {
1065 smoothVertices[index++].set(innerEdge, innerSecondaryEnd, transparent, delta * part, delta, m_gradient_is_vertical);
1066 smoothVertices[index++].set(innerEdge, innerSecondaryStart, transparent, delta * part, -delta, m_gradient_is_vertical);
1067 }
1068 } else {
1069 vertices[index++].set(innerEdge, innerSecondaryEnd, fillColor, m_gradient_is_vertical);
1070 vertices[index++].set(innerEdge, innerSecondaryStart, fillColor, m_gradient_is_vertical);
1071 if (penWidth) {
1072 vertices[index++].set(innerEdge, innerSecondaryEnd, borderColor, m_gradient_is_vertical);
1073 vertices[index++].set(innerEdge, innerSecondaryStart, borderColor, m_gradient_is_vertical);
1074 vertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, m_gradient_is_vertical);
1075 vertices[index++].set(outerEdge, outerSecondaryStart, borderColor, m_gradient_is_vertical);
1076 }
1077 }
1078 }
1079 Q_ASSERT(index == vertexCount);
1080
1081 // Close the triangle strips.
1082 if (m_antialiasing) {
1083 indices[--innerAAHead] = indices[innerAATail - 1];
1084 indices[--innerAAHead] = indices[innerAATail - 2];
1085 Q_ASSERT(innerAATail <= indexCount);
1086 }
1087 if (penWidth) {
1088 indices[--borderHead] = indices[borderTail - 1];
1089 indices[--borderHead] = indices[borderTail - 2];
1090 Q_ASSERT(borderTail <= indexCount);
1091 }
1092 if (m_antialiasing && penWidth) {
1093 indices[--outerAAHead] = indices[outerAATail - 1];
1094 indices[--outerAAHead] = indices[outerAATail - 2];
1095 Q_ASSERT(outerAATail == indexCount);
1096 }
1097 }
1098}
1099
1100QT_END_NAMESPACE
const QSGGeometry::AttributeSet & smoothAttributeSet()
Color4ub colorToColor4ub(const QColor &c)
Color4ub operator*(Color4ub c, float t)
Color4ub operator+(Color4ub a, Color4ub b)
void set(float primary, float secondary, Color4ub ncolor, float dPrimary, float dSecondary, bool vertical)
void set(float primary, float secondary, Color4ub ncolor, bool vertical)