Commit b9dfaef5f73df692712709fdfa4b5af8e91e260b

Improve the scissor API's.
  
5858 m_painter->fillRect(0, 0, m_size.width(), m_size.height(), m_clearColor);
5959}
6060
61void QGLSimulator::setScissor(int x, int y, int width, int height)
61void QGLSimulator::setScissor(const QRect& rect)
6262{
63 QRect rect(x, height - 1 - y, width, height);
63 m_scissor = rect;
6464 m_painter->setClipRect(rect);
65}
66
67void QGLSimulator::intersectScissor(const QRect& rect)
68{
69 m_scissor = rect.intersected(m_scissor);
70 m_painter->setClipRect(m_scissor);
71}
72
73void QGLSimulator::expandScissor(const QRect& rect)
74{
75 m_scissor = rect.united(m_scissor);
76 m_painter->setClipRect(m_scissor);
6577}
6678
6779void QGLSimulator::clearScissor()
  
5757 void setClearColor(const QColor& color) { m_clearColor = color; }
5858 void clear();
5959
60 void setScissor(int x, int y, int width, int height);
60 void setScissor(const QRect& rect);
61 void intersectScissor(const QRect& rect);
62 void expandScissor(const QRect& rect);
6163 void clearScissor();
6264
6365 void setViewport(int x, int y, int width, int height);
8282 QRect m_viewport;
8383 QMatrix4x4 m_projectionMatrix;
8484 QMatrix4x4 m_modelViewMatrix;
85 QRect m_scissor;
8586
8687 QPointF project(const QVector3D& vector) const;
8788};
  
5959 void cleanupTestCase();
6060 void clear();
6161 void drawTriangle();
62 void scissor();
6263 void userMatrixStack();
6364 void projectionMatrixStack();
6465 void modelViewMatrixStack();
6969 void clearPaintQ(QPainter *painter, const QSize& size);
7070 void drawTrianglePaint();
7171 void drawTrianglePaintQ(QPainter *painter, const QSize& size);
72 void scissorPaint();
73 void scissorPaintQ(QPainter *painter, const QSize& size);
7274
7375private:
7476 QGLTestWidget *widget;
151151 vertices.append(500, 100);
152152 vertices.append(500, 500);
153153
154 sim.drawTriangles(vertices);
155}
156
157static QRect fetchGLScissor(const QRect& windowRect)
158{
159 GLint scissor[4];
160 glGetIntegerv(GL_SCISSOR_BOX, scissor);
161 if (scissor[2] != 0 && scissor[3] != 0) {
162 return QRect(scissor[0],
163 windowRect.height() - (scissor[1] + scissor[3]),
164 scissor[2], scissor[3]);
165 } else {
166 // Normally should be (0, 0, 0, 0) - don't adjust for window height.
167 return QRect(scissor[0], scissor[1], scissor[2], scissor[3]);
168 }
169}
170
171void tst_QGLPainter::scissor()
172{
173 // Run a painting test to check that the scissor works.
174 QVERIFY(widget->runTest(this, "scissorPaint"));
175
176 // Perform some lower level tests to ensure that the
177 // GL state is updated properly as the scissor changes.
178 QGLPainter painter;
179 painter.begin(widget);
180 QRect windowRect = widget->rect();
181
182 QVERIFY(painter.scissor().isNull());
183 QVERIFY(!glIsEnabled(GL_SCISSOR_TEST));
184
185 painter.setScissor(windowRect);
186 QCOMPARE(painter.scissor(), windowRect);
187 QVERIFY(glIsEnabled(GL_SCISSOR_TEST));
188 QCOMPARE(fetchGLScissor(windowRect), windowRect);
189
190 QRect subRect(windowRect.width() / 3,
191 windowRect.height() / 3,
192 2 * windowRect.width() / 3,
193 2 * windowRect.height() / 3);
194 painter.setScissor(subRect);
195 QCOMPARE(painter.scissor(), subRect);
196 QVERIFY(glIsEnabled(GL_SCISSOR_TEST));
197 QCOMPARE(fetchGLScissor(windowRect), subRect);
198
199 QRect leftHalf(0, 0, windowRect.width() / 2, windowRect.height());
200 painter.intersectScissor(leftHalf);
201 QCOMPARE(painter.scissor(), subRect.intersected(leftHalf));
202 QVERIFY(glIsEnabled(GL_SCISSOR_TEST));
203 QCOMPARE(fetchGLScissor(windowRect), subRect.intersected(leftHalf));
204
205 QRect rightHalf(windowRect.width() - windowRect.width() / 2, 0,
206 windowRect.width() / 2, windowRect.height());
207 QRect expandedRect(subRect.x(), 0, windowRect.width() - subRect.x(),
208 windowRect.height());
209 painter.expandScissor(rightHalf);
210 QCOMPARE(painter.scissor(), expandedRect);
211 QVERIFY(glIsEnabled(GL_SCISSOR_TEST));
212 QCOMPARE(fetchGLScissor(windowRect), expandedRect);
213
214 // QRect(0, 0, -2, -2) is a special value indicating "clip everything".
215 painter.setScissor(QRect(0, 0, -2, -2));
216 QCOMPARE(painter.scissor(), QRect(0, 0, -2, -2));
217 QVERIFY(glIsEnabled(GL_SCISSOR_TEST));
218 QCOMPARE(fetchGLScissor(windowRect), QRect(0, 0, 0, 0));
219
220 painter.setScissor(subRect);
221 painter.setScissor(QRect());
222 QCOMPARE(painter.scissor(), QRect());
223 QVERIFY(!glIsEnabled(GL_SCISSOR_TEST));
224 QCOMPARE(fetchGLScissor(windowRect), subRect);
225
226 painter.setScissor(windowRect);
227 glScissor(subRect.x(),
228 windowRect.height() - (subRect.y() + subRect.height()),
229 subRect.width(), subRect.height());
230 painter.resetScissor();
231 QCOMPARE(painter.scissor(), subRect);
232 QVERIFY(glIsEnabled(GL_SCISSOR_TEST));
233 QCOMPARE(fetchGLScissor(windowRect), subRect);
234
235 glDisable(GL_SCISSOR_TEST);
236 painter.resetScissor();
237 QVERIFY(!glIsEnabled(GL_SCISSOR_TEST));
238 QCOMPARE(fetchGLScissor(windowRect), subRect);
239 QCOMPARE(painter.scissor(), QRect());
240}
241
242void tst_QGLPainter::scissorPaint()
243{
244 QGLPainter painter;
245 painter.begin();
246 painter.setClearColor(Qt::black);
247 painter.clear();
248
249 painter.projectionMatrix().setToIdentity();
250 painter.projectionMatrix().ortho(widget->rect());
251 painter.modelViewMatrix().setToIdentity();
252
253 QVector2DArray vertices;
254 vertices.append(10, 100);
255 vertices.append(500, 100);
256 vertices.append(500, 500);
257
258 // Paint a green triangle.
259 QGLFlatColorEffect effect;
260 painter.setUserEffect(&effect);
261 painter.setColor(Qt::green);
262 painter.setVertexAttribute(QGL::Position, vertices);
263 painter.draw(QGL::Triangles, 3);
264
265 // Change the top part of the triangle to blue.
266 painter.setScissor
267 (QRect(0, 0, widget->width(), qMin(widget->height() / 2, 200)));
268 painter.setColor(Qt::blue);
269 painter.draw(QGL::Triangles, 3);
270
271 // Intersect and draw red over the blue section.
272 painter.intersectScissor
273 (QRect(0, 0, widget->width(), qMin(widget->height() / 4, 150)));
274 painter.setColor(Qt::red);
275 painter.draw(QGL::Triangles, 3);
276
277 // Change the bottom part of the triangle to yellow.
278 int y = qMin(widget->height() / 2, 350);
279 painter.setScissor
280 (QRect(0, y, 400, widget->height() - y));
281 painter.setColor(Qt::yellow);
282 painter.draw(QGL::Triangles, 3);
283
284 // Intersect and expand, to extend the yellow region.
285 painter.intersectScissor
286 (QRect(0, y + 20, 400, widget->height() - y - 20));
287 painter.expandScissor
288 (QRect(0, y + 20, 450, widget->height() - y - 20));
289 painter.setColor(Qt::yellow);
290 painter.draw(QGL::Triangles, 3);
291
292 painter.setUserEffect(0);
293
294 painter.setScissor(QRect());
295}
296
297void tst_QGLPainter::scissorPaintQ(QPainter *painter, const QSize& size)
298{
299 QGLSimulator sim(painter, size);
300
301 sim.clear();
302
303 QMatrix4x4 proj;
304 proj.ortho(widget->rect());
305 sim.setProjectionMatrix(proj);
306
307 QVector2DArray vertices;
308 vertices.append(10, 100);
309 vertices.append(500, 100);
310 vertices.append(500, 500);
311
312 // Paint a green triangle.
313 sim.setColor(Qt::green);
314 sim.drawTriangles(vertices);
315
316 // Change the top part of the triangle to blue.
317 sim.setScissor
318 (QRect(0, 0, widget->width(), qMin(widget->height() / 2, 200)));
319 sim.setColor(Qt::blue);
320 sim.drawTriangles(vertices);
321
322 // Intersect and draw red over the blue section.
323 sim.intersectScissor
324 (QRect(0, 0, widget->width(), qMin(widget->height() / 4, 150)));
325 sim.setColor(Qt::red);
326 sim.drawTriangles(vertices);
327
328 // Change the bottom part of the triangle to yellow.
329 int y = qMin(widget->height() / 2, 350);
330 sim.setScissor
331 (QRect(0, y, 400, widget->height() - y));
332 sim.setColor(Qt::yellow);
333 sim.drawTriangles(vertices);
334
335 // Intersect and expand, to extend the yellow region.
336 sim.intersectScissor
337 (QRect(0, y + 20, 400, widget->height() - y - 20));
338 sim.expandScissor
339 (QRect(0, y + 20, 450, widget->height() - y - 20));
340 sim.setColor(Qt::yellow);
154341 sim.drawTriangles(vertices);
155342}
156343
  
120120 backColorMaterial(0),
121121 fogParameters(0),
122122 viewingCube(QVector3D(-1, -1, -1), QVector3D(1, 1, 1)),
123 scissor(0, 0, -3, -3),
123124 color(255, 255, 255, 255),
124125 updates(QGLPainter::UpdateAll),
125126 pick(0)
628628}
629629
630630/*!
631 Returns the currently active scissor rectangle. The rectangle
632 will have zero size if scissoring is disabled.
631 Returns the currently active scissor rectangle; or a null rectangle
632 if scissoring is disabled.
633633
634 Performance note: if setScissorRect() has not been called on this
634 The special rectangle value of (0, 0, -2, -2) is returned to
635 indicate that scissoring is enabled but that the scissor
636 is empty, effectively clipping away all drawing requests.
637 This value is chosen so that it is distinguishable from
638 the null rectangle (0, 0, -1, -1).
639
640 Performance note: if setScissor() has not been called on this
635641 QGLPainter, then this function will have to perform a round-trip
636642 to the GL server to get the scissor rectangle. This round-trip
637 can be avoided by calling setScissorRect() before scissorRect().
643 can be avoided by calling setScissor() before scissor().
638644
639 \sa setScissorRect(), resetScissorRect()
645 Note that the returned rectangle will be in window co-ordinates,
646 with the origin at the top-left of the drawing surface.
647
648 \sa setScissor(), resetScissor()
640649*/
641QRect QGLPainter::scissorRect() const
650QRect QGLPainter::scissor() const
642651{
643652 Q_D(QGLPainter);
644 QGLPAINTER_CHECK_PRIVATE_RETURN(QRect(0, 0, 0, 0));
645 if (d->scissorRect.isNull()) {
653 QGLPAINTER_CHECK_PRIVATE_RETURN(QRect());
654 if (d->scissor.width() <= -3) {
646655 if (glIsEnabled(GL_SCISSOR_TEST)) {
656 QPaintDevice *device = d->context->device();
647657 GLint scissor[4];
648658 glGetIntegerv(GL_SCISSOR_BOX, scissor);
649 d->scissorRect =
650 QRect(scissor[0], scissor[1], scissor[2], scissor[3]);
659 if (scissor[2] != 0 && scissor[3] != 0) {
660 d->scissor = QRect
661 (scissor[0], device->height() - (scissor[1] + scissor[3]),
662 scissor[2], scissor[3]);
663 } else {
664 // Special value indicating an empty, but active, scissor.
665 d->scissor = QRect(0, 0, -2, -2);
666 }
651667 } else {
652 d->scissorRect = QRect(0, 0, 0, 0);
668 d->scissor = QRect();
653669 }
654670 }
655 return d->scissorRect;
671 return d->scissor;
656672}
657673
658674/*!
659675 Enables scissoring to the boundaries of \a rect if it has a
660 non-zero size; disables scissoring if \a rect has a zero size.
676 non-zero size; disables scissoring if \a rect is null.
661677
662 \sa scissorRect(), resetScissorRect()
678 The special rectangle value of (0, 0, -2, -2) is used to
679 indicate that scissoring is enabled but that the scissor
680 is empty, effectively clipping away all drawing requests.
681 This value is chosen so that it is distinguishable from
682 the null rectangle (0, 0, -1, -1).
683
684 The \a rect is assumed to be in window co-ordinates, with the
685 origin at the top-left of the drawing surface. It will be
686 intersected with the drawing surface's bounds before being
687 set in the GL server.
688
689 \sa scissor(), resetScissor(), intersectScissor()
663690*/
664void QGLPainter::setScissorRect(const QRect& rect)
691void QGLPainter::setScissor(const QRect& rect)
665692{
666693 Q_D(QGLPainter);
667694 QGLPAINTER_CHECK_PRIVATE();
668 if (rect.width() > 0 && rect.height() > 0) {
669 d->scissorRect = rect;
670 glScissor(rect.x(), rect.y(), rect.width(), rect.height());
695 if (rect.width() == -2) {
696 // Special value indicating an empty, but active, scissor.
697 d->scissor = rect;
698 glScissor(0, 0, 0, 0);
671699 glEnable(GL_SCISSOR_TEST);
700 } else if (!rect.isNull()) {
701 QPaintDevice *device = d->context->device();
702 int height = device->height();
703 QRect r = rect.intersected(QRect(0, 0, device->width(), height));
704 if (r.isValid()) {
705 d->scissor = r;
706 glScissor(r.x(), height - (r.y() + r.height()),
707 r.width(), r.height());
708 } else {
709 d->scissor = QRect(0, 0, -2, -2);
710 glScissor(0, 0, 0, 0);
711 }
712 glEnable(GL_SCISSOR_TEST);
672713 } else {
673 d->scissorRect = QRect(0, 0, 0, 0);
714 d->scissor = QRect();
674715 glDisable(GL_SCISSOR_TEST);
675716 }
676717}
677718
678719/*!
679 Resets this painter's notion of what the current scissorRect()
680 is set to. The next time scissorRect() is called, the actual
720 Intersects the current scissor rectangle with \a rect and sets
721 the intersection as the new scissor.
722
723 The \a rect is assumed to be in window co-ordinates, with the
724 origin at the top-left of the drawing surface.
725
726 \sa setScissor(), expandScissor()
727*/
728void QGLPainter::intersectScissor(const QRect& rect)
729{
730 Q_D(QGLPainter);
731 QGLPAINTER_CHECK_PRIVATE();
732 QRect current = scissor();
733 if (current.width() == -2) {
734 // Scissor is already active and empty: nothing to do.
735 return;
736 } else if (rect.isEmpty()) {
737 // Intersecting with an empty rectangle sets the scissor to empty.
738 // This includes the case where "rect" is (0, 0, -2, -2).
739 d->scissor = QRect(0, 0, -2, -2);
740 glScissor(0, 0, 0, 0);
741 glEnable(GL_SCISSOR_TEST);
742 return;
743 }
744 QPaintDevice *device = d->context->device();
745 QRect r;
746 if (current.isNull())
747 r = rect.intersected(QRect(0, 0, device->width(), device->height()));
748 else
749 r = current.intersected(rect);
750 if (r.isValid()) {
751 d->scissor = r;
752 glScissor(r.x(), device->height() - (r.y() + r.height()),
753 r.width(), r.height());
754 } else {
755 d->scissor = QRect(0, 0, -2, -2);
756 glScissor(0, 0, 0, 0);
757 }
758 glEnable(GL_SCISSOR_TEST);
759}
760
761/*!
762 Expands the current scissor rectangle to also include the region
763 defined by \a rect and sets the expanded region as the new scissor.
764 The \a rect will be ignored if it is empty, or if the scissor is
765 currently disabled.
766
767 The \a rect is assumed to be in window co-ordinates, with the
768 origin at the top-left of the drawing surface.
769
770 \sa setScissor(), intersectScissor()
771*/
772void QGLPainter::expandScissor(const QRect& rect)
773{
774 if (rect.isEmpty())
775 return;
776 QRect current = scissor();
777 if (current.width() == -2)
778 setScissor(rect);
779 else if (!current.isNull())
780 setScissor(rect.united(current));
781}
782
783/*!
784 Resets this painter's notion of what the current scissor()
785 is set to. The next time scissor() is called, the actual
681786 scissor rectangle will be fetched from the GL server.
682787
683788 This function is used to synchronize the state of the application
684789 with the GL server after the execution of raw GL commands that may
685790 have altered the scissor settings.
686791
687 \sa scissorRect(), setScissorRect()
792 \sa scissor(), setScissor()
688793*/
689void QGLPainter::resetScissorRect()
794void QGLPainter::resetScissor()
690795{
691796 Q_D(QGLPainter);
692797 QGLPAINTER_CHECK_PRIVATE();
693 d->scissorRect = QRect();
798 d->scissor = QRect(0, 0, -3, -3);
694799}
695800
696801/*!
  
116116 void setViewport(const QSize& size);
117117 void setViewport(int width, int height);
118118
119 QRect scissorRect() const;
120 void setScissorRect(const QRect& rect);
121 void resetScissorRect();
119 QRect scissor() const;
120 void setScissor(const QRect& rect);
121 void intersectScissor(const QRect& rect);
122 void expandScissor(const QRect& rect);
123 void resetScissor();
122124
123125 QGLMatrixStack& projectionMatrix();
124126 QGLMatrixStack& modelViewMatrix();
  
233233 QGLMaterialParameters *backColorMaterial;
234234 const QGLFogParameters *fogParameters;
235235 QBox3D viewingCube;
236 QRect scissorRect;
236 QRect scissor;
237237 QColor color;
238238 QGLPainter::Updates updates;
239239 GLuint currentBufferId;