| /* |
| * Automatic primitive rasterization precision test. |
| * |
| * Draw prims at various sub-pixel offsets and examine where the quad is |
| * actually drawn. |
| * Check if the range of offsets which paint the right pixels falls within |
| * OpenGL's specification. |
| * In case of failures, report the coordinate bias needed to fix the problem. |
| * |
| * Note that even Mesa/swrast fails some line tests. This is because some |
| * window coordinates wind up as 53.9999 instead of 54, for example. Enabling |
| * the small translation factor below fixes that. Revisit someday... |
| * |
| * Brian Paul |
| * 28 Feb 2008 |
| */ |
| |
| |
| #include <assert.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <GL/glut.h> |
| |
| |
| static int Width = 100, Height = 100; |
| static int Win; |
| static float Step = 0.125; |
| #if 0 |
| /* This tiny offset fixes errors in Mesa/Xlib */ |
| static float Xtrans = 0.5 * 0.125; |
| static float Ytrans = 0.5 * 0.125; |
| #else |
| static float Xtrans = 0.0; |
| static float Ytrans = 0.0; |
| #endif |
| |
| |
| static void |
| PointCalibrate(int xpos, int ypos) |
| { |
| GLfloat rgba[4]; |
| float x, y; |
| float xmin, ymin, xmax, ymax; |
| |
| xmin = ymin = 1000.0; |
| xmax = ymax = -1000.0; |
| |
| for (y = -1.0; y <= 1.0; y += Step) { |
| for (x = -1.0; x <= 1.0; x += Step) { |
| glClear(GL_COLOR_BUFFER_BIT); |
| glBegin(GL_POINTS); |
| glVertex2f(xpos + x, ypos + y); |
| glEnd(); |
| glReadPixels(xpos, ypos, 1, 1, GL_RGBA, GL_FLOAT, rgba); |
| if (rgba[0] == 1.0 && rgba[1] == 1.0 && rgba[2] == 1.0) { |
| /* hit */ |
| if (x < xmin) |
| xmin = x; |
| if (y < ymin) |
| ymin = y; |
| if (x > xmax) |
| xmax = x; |
| if (y > ymax) |
| ymax = y; |
| } |
| } |
| } |
| |
| printf("Point at (%2d, %2d) drawn for x in [%6.3f, %6.3f] and y in [%6.3f, %6.3f]\n", |
| xpos, ypos, |
| xpos + xmin, xpos + xmax, |
| ypos + ymin, ypos + ymax); |
| |
| if (xmax - xmin != 1.0 - Step) { |
| printf(" => Inconsistant X-axis rasterization!\n"); |
| } |
| if (ymax - ymin != 1.0 - Step) { |
| printf(" => Inconsistant Y-axis rasterization!\n"); |
| } |
| if (xmin < 0.0) { |
| printf(" => Points should be X biased by about %f\n", xmin); |
| } |
| if (ymin < 0.0) { |
| printf(" => Points should be Y biased by about %f\n", ymin); |
| } |
| if (xmax > 1.0) { |
| printf(" => Points should be X biased by about %f\n", 1.0 - xmax); |
| } |
| if (ymax > 1.0) { |
| printf(" => Points should be Y biased by about %f\n", 1.0 - ymax); |
| } |
| |
| } |
| |
| |
| /** |
| * XXX Implement VLineCalibrate() someday |
| */ |
| static void |
| HLineCalibrate(int xpos, int ypos, int len) |
| { |
| GLfloat rgba[2][4]; |
| float x, y; |
| float ymin, ymax; |
| float xmin_left, xmax_left, xmin_right, xmax_right; |
| |
| xmin_left = xmin_right = 1000.0; |
| xmax_left = xmax_right = -1000.0; |
| ymin = 1000; |
| ymax = -1000.0; |
| |
| /* |
| * First, check vertical positioning of the horizontal line |
| */ |
| for (y = -1.0; y <= 1.0; y += Step) { |
| glClear(GL_COLOR_BUFFER_BIT); |
| glBegin(GL_LINES); |
| glVertex2f(xpos, ypos + y); |
| glVertex2f(xpos + len, ypos + y); |
| glEnd(); |
| |
| glReadPixels(xpos + len / 2, ypos, 1, 1, GL_RGBA, GL_FLOAT, rgba); |
| if (rgba[0][0] == 1.0) { |
| /* hit */ |
| if (y < ymin) |
| ymin = y; |
| if (y > ymax) |
| ymax = y; |
| } |
| } |
| |
| printf("H-line at Y=%2d drawn for y in [%6.3f, %6.3f]\n", |
| ypos, |
| ypos + ymin, ypos + ymax); |
| |
| if (ymax - ymin != 1.0 - Step) { |
| printf(" => Inconsistant Y-axis rasterization!\n"); |
| } |
| |
| if (ymin > 0.5 ) { |
| printf(" => Lines should be Y biased by about %f\n", ymin - 0.5); |
| } |
| |
| if (ymax < 0.5 ) { |
| printf(" => Lines should be Y biased by about %f\n", 0.5 - ymax); |
| } |
| |
| /* |
| * Second, check endpoints (for Y at 1/2 pixel) |
| */ |
| for (x = -1.0; x <= 1.0; x += Step) { |
| glClear(GL_COLOR_BUFFER_BIT); |
| glBegin(GL_LINES); |
| glVertex2f(xpos + x, ypos + 0.5f); |
| glVertex2f(xpos + x + len, ypos + 0.5f); |
| glEnd(); |
| |
| /* left end */ |
| glReadPixels(xpos - 1, ypos, 2, 1, GL_RGBA, GL_FLOAT, rgba); |
| if (rgba[0][0] == 0.0 && rgba[1][0] == 1.0) { |
| /* hit */ |
| if (x < xmin_left) |
| xmin_left = x; |
| if (x > xmax_left) |
| xmax_left = x; |
| } |
| |
| /* right end */ |
| glReadPixels(xpos + len - 1, ypos, 2, 1, GL_RGBA, GL_FLOAT, rgba); |
| if (rgba[0][0] == 1.0 && rgba[1][0] == 0.0) { |
| /* hit */ |
| if (x < xmin_right) |
| xmin_right = x; |
| if (x > xmax_right) |
| xmax_right = x; |
| } |
| } |
| |
| printf("H-line [%d..%d) hit left end for x in [%6.3f, %6.3f] " |
| "hit right end for x in [%6.3f, %6.3f]\n", |
| xpos, xpos + len, |
| xpos + xmin_left, xpos + xmax_left, |
| xpos + len + xmin_right, xpos + len + xmax_right); |
| |
| if (xmax_left - xmin_left > 1.0 - Step) { |
| printf(" => Inconsistant left-end rasterization!\n"); |
| } |
| if (xmax_right - xmin_right > 1.0 - Step) { |
| printf(" => Inconsistant right-end rasterization!\n"); |
| } |
| |
| if (xmin_left != xmin_right || |
| xmax_left != xmax_right) { |
| printf(" => Inconsistant length!\n"); |
| } |
| |
| if (xmin_left < 0.0) { |
| printf(" => Coords should be X biased by about %f\n", xmin_left ); |
| } |
| if (xmin_right < 0.0) { |
| printf(" => Coords should be X biased by about %f\n", xmin_right ); |
| } |
| if (xmax_left >= 1.0) { |
| printf(" => Coords should be X biased by about %f\n", -xmax_right + 1.0); |
| } |
| if (xmax_right >= 1.0) { |
| printf(" => Coords should be X biased by about %f\n", -xmax_right + 1.0); |
| } |
| |
| } |
| |
| |
| static void |
| QuadCalibrate(int xpos, int ypos, int width, int height) |
| { |
| GLfloat rgba1[2][4]; |
| GLfloat rgba2[2][4]; |
| float x, y; |
| float xmin, ymin, xmax, ymax; |
| |
| xmin = ymin = 1000.0; |
| xmax = ymax = -1000.0; |
| |
| for (y = -1.0; y <= 1.0; y += Step) { |
| for (x = -1.0; x <= 1.0; x += Step) { |
| glClear(GL_COLOR_BUFFER_BIT); |
| glBegin(GL_QUADS); |
| glVertex2f(xpos + x, ypos + y); |
| glVertex2f(xpos + x + width, ypos + y); |
| glVertex2f(xpos + x + width, ypos + y + height); |
| glVertex2f(xpos + x, ypos + y + height); |
| glEnd(); |
| |
| /* horizontal measurement */ |
| glReadPixels(xpos - 1, ypos + 2, 2, 1, GL_RGBA, GL_FLOAT, rgba1); |
| glReadPixels(xpos + width - 1, ypos + 2, 2, 1, GL_RGBA, GL_FLOAT, rgba2); |
| if (rgba1[0][0] == 0.0 && rgba1[1][0] == 1.0 && |
| rgba2[0][0] == 1.0 && rgba2[1][0] == 0.0) { |
| if (x < xmin) |
| xmin = x; |
| if (x > xmax) |
| xmax = x; |
| } |
| |
| /* vertical measurement */ |
| glReadPixels(xpos + 2, ypos - 1, 1, 2, GL_RGBA, GL_FLOAT, rgba1); |
| glReadPixels(xpos + 2, ypos + height - 1, 1, 2, GL_RGBA, GL_FLOAT, rgba2); |
| if (rgba1[0][0] == 0.0 && rgba1[1][0] == 1.0 && |
| rgba2[0][0] == 1.0 && rgba2[1][0] == 0.0) { |
| if (y < ymin) |
| ymin = y; |
| if (y > ymax) |
| ymax = y; |
| } |
| } |
| } |
| |
| printf("Quad at (%2d, %2d)..(%2d, %2d) drawn" |
| " for x in [%6.3f, %6.3f] and y in [%6.3f, %6.3f]\n", |
| xpos, ypos, |
| xpos + width, ypos + height, |
| xpos + xmin, xpos + xmax, |
| ypos + ymin, ypos + ymax); |
| |
| if (xmax - xmin != 1.0 - Step) { |
| printf(" => Inconsistant X-axis rasterization/size!\n"); |
| } |
| if (ymax - ymin != 1.0 - Step) { |
| printf(" => Inconsistant Y-axis rasterization/size!\n"); |
| } |
| |
| if (xmin < -0.5) { |
| printf(" => Coords should be X biased by about %f\n", 0.5 + xmin ); |
| } |
| if (ymin < -0.5) { |
| printf(" => Coords should be Y biased by about %f\n", 0.5 + ymin); |
| } |
| if (xmax > 0.5) { |
| printf(" => Coords should be X biased by about %f\n", -xmax + 0.5); |
| } |
| if (ymax > 0.5) { |
| printf(" => Coords should be Y biased by about %f\n", -ymax + 0.5); |
| } |
| } |
| |
| |
| /** |
| * Misc/disabled code for debugging. |
| */ |
| static void |
| DebugTest(void) |
| { |
| glClear(GL_COLOR_BUFFER_BIT); |
| glEnable(GL_BLEND); |
| glBlendFunc(GL_ONE, GL_ONE); |
| |
| glColor3f(.5, .5, .5); |
| |
| glBegin(GL_LINES); |
| glVertex2f(30, 35.5); |
| glVertex2f(54, 35.5); |
| glVertex2f(54, 35.5); |
| glVertex2f(66, 35.5); |
| glEnd(); |
| |
| glDisable(GL_BLEND); |
| glColor3f(1,1,1); |
| } |
| |
| |
| static void |
| Draw(void) |
| { |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| glPushMatrix(); |
| glTranslatef(Xtrans, Ytrans, 0); |
| |
| PointCalibrate(1, 1); |
| PointCalibrate(50, 50); |
| PointCalibrate(28, 17); |
| PointCalibrate(17, 18); |
| printf("\n"); |
| |
| HLineCalibrate(5, 10, 10); |
| HLineCalibrate(25, 22, 12); |
| HLineCalibrate(54, 33, 12); |
| HLineCalibrate(54+12, 33, 12); |
| printf("\n"); |
| |
| QuadCalibrate(2, 2, 10, 10); |
| QuadCalibrate(50, 50, 10, 10); |
| QuadCalibrate(28, 17, 12, 12); |
| QuadCalibrate(17, 28, 12, 12); |
| |
| (void) DebugTest; |
| |
| glPopMatrix(); |
| |
| glutSwapBuffers(); |
| } |
| |
| |
| static void |
| Reshape(int width, int height) |
| { |
| Width = width; |
| Height = height; |
| glViewport(0, 0, width, height); |
| glMatrixMode(GL_PROJECTION); |
| glLoadIdentity(); |
| glOrtho(0, width, 0, height, -1, 1); |
| glMatrixMode(GL_MODELVIEW); |
| glLoadIdentity(); |
| } |
| |
| |
| static void |
| Key(unsigned char key, int x, int y) |
| { |
| (void) x; |
| (void) y; |
| switch (key) { |
| case 27: |
| glutDestroyWindow(Win); |
| exit(0); |
| break; |
| } |
| glutPostRedisplay(); |
| } |
| |
| |
| static void |
| Init(void) |
| { |
| printf("Measurement/callibration for basic prim rasterization...\n"); |
| printf("GL_RENDERER: %s\n", (char*) glGetString(GL_RENDERER)); |
| } |
| |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| glutInit(&argc, argv); |
| glutInitWindowPosition(0, 0); |
| glutInitWindowSize(Width, Height); |
| glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); |
| Win = glutCreateWindow(argv[0]); |
| glutReshapeFunc(Reshape); |
| glutKeyboardFunc(Key); |
| glutDisplayFunc(Draw); |
| Init(); |
| glutMainLoop(); |
| return 0; |
| } |