/* * Copyright (c) 2011 VMware, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * on the rights to use, copy, modify, merge, publish, distribute, sub * license, and/or sell copies of the Software, and to permit persons to whom * the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT. IN NO EVENT SHALL VMWARE AND/OR THEIR SUPPLIERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Tests glPolygonMode. * Brian Paul * April 2011 */ #include "piglit-util-gl.h" PIGLIT_GL_TEST_CONFIG_BEGIN config.supports_gl_compat_version = 10; config.window_width = 500; config.window_height = 100; config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE; config.khr_no_error_support = PIGLIT_NO_ERRORS; PIGLIT_GL_TEST_CONFIG_END static float ortho_left = -1, ortho_right = 8, ortho_bottom = -2, ortho_top = 2; static const char *TestName = "polygon-mode"; #define VERTS 16 static const GLfloat Positions[VERTS][2] = { /* counter-clockwise, front facing */ { 0, -1 }, { 1, -1 }, { 1, 1 }, { 0, 1 }, /* clockwise, back facing */ { 2, -1 }, { 2, 1 }, { 3, 1 }, { 3, -1 }, /* counter-clockwise, front facing */ { 4, -1 }, { 5, -1 }, { 5, 1 }, { 4, 1 }, /* clockwise, back facing */ { 6, -1 }, { 6, 1 }, { 7, 1 }, { 7, -1 } }; static const GLfloat Colors[VERTS][4] = { {1, 0, 0, 1}, {1, 0, 0, 1}, {1, 0, 0, 1}, {1, 0, 0, 1}, {0, 1, 0, 1}, {0, 1, 0, 1}, {0, 1, 0, 1}, {0, 1, 0, 1}, {0, 0, 1, 1}, {0, 0, 1, 1}, {0, 0, 1, 1}, {0, 0, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} }; static GLenum get_prim_mode(GLenum mode) { switch (mode) { case GL_POINT: return GL_POINTS; case GL_LINE: return GL_LINE_LOOP; case GL_FILL: return GL_QUADS; default: return 0; } } static void obj_pos_to_win_pos(float x, float y, int *wx, int *wy) { float ortho_width = ortho_right - ortho_left; float ortho_height = ortho_top - ortho_bottom; *wx = (int) ((x - ortho_left) / ortho_width * piglit_width); *wy = (int) ((y - ortho_bottom) / ortho_height * piglit_height); } /** * Probe a 3x3 pixel region to see if any of the pixels matches the * expected color. */ static GLboolean probe_region(float px, float py, const GLfloat expectedColor[4]) { GLfloat img[3][3][4]; int i, j; int wx, wy; obj_pos_to_win_pos(px, py, &wx, &wy); glReadPixels(wx-1, wy-1, 3, 3, GL_RGBA, GL_FLOAT, img); /* see if any of the pixels matches the expected color */ for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { if (img[i][j][0] == expectedColor[0] && img[i][j][1] == expectedColor[1] && img[i][j][2] == expectedColor[2] && img[i][j][3] == expectedColor[3]) { return GL_TRUE; } } } return GL_FALSE; } /** * Examine the pixels drawn by a rect using the four vertex positions * and determine if it was drawn filled, outlined, or as four points. * \return GL_FILL, GL_LINE, GL_POINT or GL_NONE */ static GLenum identify_primitive(const GLfloat positions[4][2], const GLfloat expectedColor[4]) { /* center */ float cx = (positions[0][0] + positions[2][0]) / 2.0; float cy = (positions[0][1] + positions[2][1]) / 2.0; /* left edge */ float lx = positions[0][0]; float ly = cy; /* right edge */ float rx = positions[2][0]; float ry = cy; /* bottom edge */ float bx = cx; float by = positions[0][1]; /* bottom edge */ float tx = cx; float ty = positions[2][1]; /* probe center */ if (probe_region(cx, cy, expectedColor)) return GL_FILL; /* probe left edge */ if (probe_region(lx, ly, expectedColor)) { /* and bottom edge */ if (probe_region(bx, by, expectedColor)) { /* and right edge */ if (probe_region(rx, ry, expectedColor)) { /* and top edge */ if (probe_region(tx, ty, expectedColor)) { return GL_LINE; } } } } /* probe lower-left corner */ if (probe_region(lx, by, expectedColor)) { /* probe lower-right corner */ if (probe_region(rx, by, expectedColor)) { /* probe top-left corner */ if (probe_region(lx, ty, expectedColor)) { /* probe top-right corner */ if (probe_region(rx, ty, expectedColor)) { return GL_POINT; } } } } return GL_NONE; } static GLboolean test_combo(GLenum frontMode, GLenum backMode, GLenum cullMode) { GLenum frontPrim = get_prim_mode(frontMode); GLenum backPrim = get_prim_mode(backMode); GLboolean pass = GL_TRUE; GLenum expectedPrims[4]; int i; glDisable(GL_CULL_FACE); /* Draw reference image */ glClear(GL_COLOR_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (cullMode == GL_NONE || cullMode == GL_BACK) { glDrawArrays(frontPrim, 0, 4); } if (cullMode == GL_NONE || cullMode == GL_FRONT) { glDrawArrays(backPrim, 4, 4); } if (cullMode == GL_NONE || cullMode == GL_BACK) { glDrawArrays(frontPrim, 8, 4); } if (cullMode == GL_NONE || cullMode == GL_FRONT) { glDrawArrays(backPrim, 12, 4); } /* determine what kind of primitives were drawn */ for (i = 0; i < 4; i++) { GLenum testMode = GL_NONE; if (i & 1) { /* back-facing quad */ if (cullMode == GL_NONE || cullMode == GL_FRONT) { testMode = backMode; } } else { /* front-facing quad */ if (cullMode == GL_NONE || cullMode == GL_BACK) { testMode = frontMode; } } expectedPrims[i] = identify_primitive(&Positions[4 * i], Colors[4 * i]); if (expectedPrims[i] != testMode) { /* we didn't get the expected reference primitive */ fprintf(stderr, "%s: reference drawing failed for frontPrim=%s, backPrim=%s, cull=%s\n", TestName, piglit_get_gl_enum_name(frontMode), piglit_get_gl_enum_name(backMode), piglit_get_gl_enum_name(cullMode)); fprintf(stderr, "At position %d, found prim %s instead of %s\n", i, piglit_get_gl_enum_name(expectedPrims[i]), piglit_get_gl_enum_name(testMode)); return GL_FALSE; } } /* Draw test image */ glClear(GL_COLOR_BUFFER_BIT); glPolygonMode(GL_FRONT, frontMode); glPolygonMode(GL_BACK, backMode); if (cullMode == GL_NONE) { glDisable(GL_CULL_FACE); } else { glEnable(GL_CULL_FACE); glCullFace(cullMode); } glDrawArrays(GL_QUADS, 0, 16); /* check that these prims match the reference prims */ for (i = 0; i < 4; i++) { GLenum prim = identify_primitive(&Positions[4 * i], Colors[4 * i]); if (prim != expectedPrims[i]) { fprintf(stderr, "%s: glPolygonMode(front=%s, back=%s), glCullMode(%s) failed\n", TestName, piglit_get_gl_enum_name(frontMode), piglit_get_gl_enum_name(backMode), piglit_get_gl_enum_name(cullMode)); fprintf(stderr, "At position %d, found prim %s instead of %s\n", i, piglit_get_gl_enum_name(prim), piglit_get_gl_enum_name(expectedPrims[i])); pass = GL_FALSE; } } piglit_present_results(); return pass; } static GLboolean test_polygonmode(void) { static const GLenum cullModes[] = { GL_NONE, GL_FRONT, GL_BACK, GL_FRONT_AND_BACK }; static const GLenum fillModes[] = { GL_FILL, GL_LINE, GL_POINT }; GLenum pass = GL_TRUE; int i, j, k; glVertexPointer(2, GL_FLOAT, 0, Positions); glColorPointer(4, GL_FLOAT, 0, Colors); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); for (i = 0; i < ARRAY_SIZE(cullModes); i++) { for (j = 0; j < ARRAY_SIZE(fillModes); j++) { for (k = 0; k < ARRAY_SIZE(fillModes); k++) { if (!test_combo(fillModes[k], fillModes[j], cullModes[i])) { pass = GL_FALSE; } } } } return pass; } enum piglit_result piglit_display(void) { if (!test_polygonmode()) return PIGLIT_FAIL; return PIGLIT_PASS; } void piglit_init(int argc, char **argv) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(ortho_left, ortho_right, ortho_bottom, ortho_top, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); }