1 // BEGIN_COPYRIGHT -*- glean -*-
3 // Copyright (C) 2009 VMware, Inc. All Rights Reserved.
5 // Permission is hereby granted, free of charge, to any person
6 // obtaining a copy of this software and associated documentation
7 // files (the "Software"), to deal in the Software without
8 // restriction, including without limitation the rights to use,
9 // copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL VMWARE BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
30 // Test that the correct provoking vertex is used when a tri/quad/polygon
31 // is clipped for glShadeModel(GL_FLAT).
33 // Test with glDrawArrays and glBegin/End. Test GL_CCW and GL_CW winding.
34 // Back-face polygon culling is enabled so if the winding order of any
35 // primitive is incorrect, nothing may be drawn.
37 // XXX We should also test with two-sided lighting.
39 // If GL_ARB/EXT_provoking_vertex is supported, that feature is tested as well.
46 #include "tclipflat.h"
51 static PFNGLPROVOKINGVERTEXEXTPROC ProvokingVertex_func
= NULL
;
54 // Note: all correctly rendered tris/quad/polygons will be green.
55 // Any other color indicates that the wrong vertex color was used.
58 // GL_TRIANGLES: provoking vertex = last of tri
59 static const GLfloat TriVerts
[6][5] =
64 { 0, 1, 0, 1, 1 }, // PV
68 { 0, 1, 0, -1, -1 } // PV
71 // GL_TRIANGLES: first provoking vertex
72 static const GLfloat TriVertsFirstPV
[6][5] =
74 { 0, 1, 0, 1, 1 }, // PV
78 { 0, 1, 0, -1, -1 }, // PV
84 // GL_TRIANGLE_STRIP: provoking vertex = last of tri
85 static const GLfloat TriStripVerts
[6][5] =
89 { 0, 1, 0, -1, 0 }, // PV
90 { 0, 1, 0, 1, 0 }, // PV
91 { 0, 1, 0, -1, 1 }, // PV
92 { 0, 1, 0, 1, 1 } // PV
95 // GL_TRIANGLE_STRIP: first provoking vertex
96 static const GLfloat TriStripVertsFirstPV
[6][5] =
98 { 0, 1, 0, -1, -1 }, // PV
99 { 0, 1, 0, 1, -1 }, // PV
100 { 0, 1, 0, -1, 0 }, // PV
101 { 0, 1, 0, 1, 0 }, // PV
107 // GL_TRIANGLE_FAN: provoking vertex = last of tri
108 static const GLfloat TriFanVerts
[4][5] =
112 { 0, 1, 0, 1, 1 }, // PV
113 { 0, 1, 0, -1, 1 } // PV
116 // GL_TRIANGLE_FAN: first provoking vertex
117 static const GLfloat TriFanVertsFirstPV
[4][5] =
120 { 0, 1, 0, 1, 1 }, // PV
121 { 0, 1, 0, -1, 1 }, // PV
126 // GL_QUADS: provoking vertex = last of quad
127 static const GLfloat QuadVerts
[4][5] =
132 { 0, 1, 0, -1, 1 } // PV
135 // GL_QUADS: first provoking vertex
136 static const GLfloat QuadVertsFirstPV
[4][5] =
138 { 0, 1, 0, -1, 1 }, // PV
145 // GL_QUAD_STRIP: provoking vertex = last of quad
146 static const GLfloat QuadStripVerts
[6][5] =
151 { 0, 1, 0, 1, 0 }, // PV
153 { 0, 1, 0, 1, 1 } // PV
156 // GL_QUAD_STRIP: first provoking vertex
157 static const GLfloat QuadStripVertsFirstPV
[6][5] =
159 { 0, 1, 0, -1, -1 }, // PV
161 { 0, 1, 0, -1, 0 }, // PV
168 // GL_POLYGON: provoking vertex = first vertex
169 static const GLfloat PolygonVerts
[4][5] =
171 { 0, 1, 0, -1, -1 }, // PV
178 #define Elements(array) (sizeof(array) / sizeof(array[0]))
189 ClipFlatResult::ClipFlatResult()
196 ClipFlatTest::setup(void)
198 glDisable(GL_DITHER
);
200 glMatrixMode(GL_PROJECTION
);
202 glOrtho(-1.25, 1.25, -1.25, 1.25, -1, 1);
203 glMatrixMode(GL_MODELVIEW
);
206 glShadeModel(GL_FLAT
);
207 glPixelStorei(GL_PACK_ALIGNMENT
, 1);
210 glCullFace(GL_FRONT
);
211 glEnable(GL_CULL_FACE
);
213 if (GLUtils::haveExtension("GL_ARB_provoking_vertex")) {
214 ProvokingVertex_func
= reinterpret_cast<PFNGLPROVOKINGVERTEXPROC
>
215 (GLUtils::getProcAddress("glProvokingVertex"));
216 provoking_vertex_first
= true;
218 else if (GLUtils::haveExtension("GL_EXT_provoking_vertex")) {
219 ProvokingVertex_func
= reinterpret_cast<PFNGLPROVOKINGVERTEXEXTPROC
>
220 (GLUtils::getProcAddress("glProvokingVertexEXT"));
221 provoking_vertex_first
= true;
224 if (provoking_vertex_first
) {
226 glGetBooleanv(GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT
, &k
);
227 quads_follows_pv_convention
= k
;
232 // Draw with glDrawArrays()
234 ClipFlatTest::drawArrays(GLenum mode
, const GLfloat
*verts
, GLuint count
)
236 glColorPointer(3, GL_FLOAT
, 5 * sizeof(GLfloat
), verts
+ 0);
237 glVertexPointer(2, GL_FLOAT
, 5 * sizeof(GLfloat
), verts
+ 3);
238 glEnableClientState(GL_COLOR_ARRAY
);
239 glEnableClientState(GL_VERTEX_ARRAY
);
241 glDrawArrays(mode
, 0, count
);
243 glDisableClientState(GL_COLOR_ARRAY
);
244 glDisableClientState(GL_VERTEX_ARRAY
);
248 // Draw with glDrawElements()
250 ClipFlatTest::drawElements(GLenum mode
, const GLfloat
*verts
, GLuint count
)
252 static const GLuint elements
[6] = { 0, 1, 2, 3, 4, 5 };
253 glColorPointer(3, GL_FLOAT
, 5 * sizeof(GLfloat
), verts
+ 0);
254 glVertexPointer(2, GL_FLOAT
, 5 * sizeof(GLfloat
), verts
+ 3);
255 glEnableClientState(GL_COLOR_ARRAY
);
256 glEnableClientState(GL_VERTEX_ARRAY
);
258 assert(count
<= Elements(elements
));
260 glDrawElements(mode
, count
, GL_UNSIGNED_INT
, elements
);
262 glDisableClientState(GL_COLOR_ARRAY
);
263 glDisableClientState(GL_VERTEX_ARRAY
);
267 // Draw with glBegin/End()
269 ClipFlatTest::drawBeginEnd(GLenum mode
, const GLfloat
*verts
, GLuint count
)
274 for (i
= 0; i
< count
; i
++) {
275 glColor3fv(verts
+ i
* 5);
276 glVertex2fv(verts
+ i
* 5 + 3);
282 // Read pixels and check pixels. All pixels should be green or black.
283 // Any other color indicates a failure.
285 ClipFlatTest::checkResult(Window
&w
, GLfloat badColor
[3])
287 GLubyte image
[windowSize
* windowSize
* 3];
289 GLboolean anyGreen
= GL_FALSE
;
291 badColor
[0] = badColor
[1] = badColor
[2] = 0.0f
;
293 glReadPixels(0, 0, windowSize
, windowSize
,
294 GL_RGB
, GL_UNSIGNED_BYTE
, image
);
298 for (i
= 0; i
< windowSize
; i
++) {
299 for (j
= 0; j
< windowSize
; j
++) {
300 GLuint k
= (i
* windowSize
+ j
) * 3;
302 if (image
[k
+ 0] == 0 &&
307 else if (image
[k
+ 0] == 0 &&
308 image
[k
+ 1] >= 254 &&
314 // any other color = failure
315 badColor
[0] = image
[k
+ 0] / 255.0;
316 badColor
[1] = image
[k
+ 1] / 255.0;
317 badColor
[2] = image
[k
+ 2] / 255.0;
328 ClipFlatTest::reportFailure(GLenum mode
, int drawMode
, GLuint facing
,
330 const GLfloat badColor
[3], GLfloat x
, GLfloat y
)
332 const char *m
, *d
, *f
, *p
;
338 case GL_TRIANGLE_STRIP
:
339 m
= "GL_TRIANGLE_STRIP";
341 case GL_TRIANGLE_FAN
:
342 m
= "GL_TRIANGLE_FAN";
365 d
= "glDrawElements";
381 env
->log
<< name
<< ": Failure for "
382 << d
<< "(" << m
<< "), glFrontFace(" << f
383 << "), glPolygonMode(" << p
<< ")\n";
385 env
->log
<< "\tTranslation: " << x
<< ", " << y
<< "\n";
387 if (testing_first_pv
)
388 env
->log
<< "\tGL_EXT_provoking_vertex test: GL_FIRST_VERTEX_CONVENTION_EXT mode\n";
390 env
->log
<< "\tExpected color (0, 1, 0) but found ("
391 << badColor
[0] << ", "
392 << badColor
[1] << ", "
393 << badColor
[2] << ")\n";
397 // Test drawing/clipping at nine positions of which 8 will be clipped.
399 ClipFlatTest::testPositions(Window
&w
, GLenum mode
,
400 const GLfloat
*verts
, GLuint count
)
406 // Loop over polygon mode: filled vs. outline
407 for (fill
= 0; fill
< 2; fill
++) {
409 glPolygonMode(GL_FRONT_AND_BACK
, fill
? GL_LINE
: GL_FILL
);
411 // Loop over drawing mode: glBegin/End vs glDrawArrays vs glDrawElements
412 for (drawMode
= 0; drawMode
< NUM_DRAW_MODES
; drawMode
++) {
414 // Loop over CW vs. CCW winding (should make no difference)
415 for (facing
= 0; facing
< 2; facing
++) {
423 glCullFace(GL_FRONT
);
426 // Position the geometry at 9 different locations to test
427 // clipping against the left, right, bottom and top edges of
429 // Only the center location will be unclipped.
430 for (y
= -1.0; y
<= 1.0; y
+= 1.0) {
431 for (x
= -1.0; x
<= 1.0; x
+= 1.0) {
433 glTranslatef(x
, y
, 0.0);
435 glClear(GL_COLOR_BUFFER_BIT
);
439 drawBeginEnd(mode
, verts
, count
);
442 drawArrays(mode
, verts
, count
);
445 drawElements(mode
, verts
, count
);
454 if (!checkResult(w
, badColor
)) {
455 reportFailure(mode
, drawMode
, facing
, fill
, badColor
, x
, y
);
457 //sleep(25); // enable for debugging
460 //usleep(50000); // enable for debugging
471 ClipFlatTest::runOne(ClipFlatResult
&r
, Window
&w
)
475 testing_first_pv
= false;
479 r
.pass
= testPositions(w
, GL_TRIANGLES
,
480 (GLfloat
*) TriVerts
,
484 r
.pass
= testPositions(w
, GL_TRIANGLE_STRIP
,
485 (GLfloat
*) TriStripVerts
,
486 Elements(TriStripVerts
));
489 r
.pass
= testPositions(w
, GL_TRIANGLE_FAN
,
490 (GLfloat
*) TriFanVerts
,
491 Elements(TriFanVerts
));
494 r
.pass
= testPositions(w
, GL_QUADS
,
495 (GLfloat
*) QuadVerts
,
496 Elements(QuadVerts
));
499 r
.pass
= testPositions(w
, GL_QUAD_STRIP
,
500 (GLfloat
*) QuadStripVerts
,
501 Elements(QuadStripVerts
));
504 r
.pass
= testPositions(w
, GL_POLYGON
,
505 (GLfloat
*) PolygonVerts
,
506 Elements(PolygonVerts
));
508 if (provoking_vertex_first
) {
509 ProvokingVertex_func(GL_FIRST_VERTEX_CONVENTION_EXT
);
510 testing_first_pv
= true;
513 r
.pass
= testPositions(w
, GL_TRIANGLES
,
514 (GLfloat
*) TriVertsFirstPV
,
515 Elements(TriVertsFirstPV
));
518 r
.pass
= testPositions(w
, GL_TRIANGLE_STRIP
,
519 (GLfloat
*) TriStripVertsFirstPV
,
520 Elements(TriStripVertsFirstPV
));
523 r
.pass
= testPositions(w
, GL_TRIANGLE_FAN
,
524 (GLfloat
*) TriFanVertsFirstPV
,
525 Elements(TriFanVertsFirstPV
));
528 if (quads_follows_pv_convention
)
529 r
.pass
= testPositions(w
, GL_QUADS
,
530 (GLfloat
*) QuadVertsFirstPV
,
531 Elements(QuadVertsFirstPV
));
533 r
.pass
= testPositions(w
, GL_QUADS
,
534 (GLfloat
*) QuadVerts
,
535 Elements(QuadVerts
));
539 if (quads_follows_pv_convention
)
540 r
.pass
= testPositions(w
, GL_QUAD_STRIP
,
541 (GLfloat
*) QuadStripVertsFirstPV
,
542 Elements(QuadStripVertsFirstPV
));
544 r
.pass
= testPositions(w
, GL_QUAD_STRIP
,
545 (GLfloat
*) QuadStripVerts
,
546 Elements(QuadStripVerts
));
550 r
.pass
= testPositions(w
, GL_POLYGON
,
551 (GLfloat
*) PolygonVerts
,
552 Elements(PolygonVerts
));
559 ClipFlatTest::logOne(ClipFlatResult
&r
)
567 ClipFlatTest::compareOne(ClipFlatResult
&oldR
,
568 ClipFlatResult
&newR
)
570 comparePassFail(oldR
, newR
);
575 ClipFlatResult::putresults(ostream
&s
) const
587 ClipFlatResult::getresults(istream
&s
)
592 if (strcmp(result
, "FAIL") == 0) {
602 // The test object itself:
603 ClipFlatTest
newTest("clipFlat", "window, rgb",
605 "Test clipping with flat shading (provoking vertex).\n");