--- /dev/null
+/**
+ * Test for exact point/line/polygon rasterization, or at least rasterization
+ * that fits the tolerance of the OpenGL spec.
+ *
+ * Brian Paul
+ * 9 Nov 2007
+ */
+
+/*
+ * Notes:
+ * - 'm' to cycle through point, hline, vline and quad drawing
+ * - Use cursor keys to translate coordinates (z to reset)
+ * - Resize window to check for proper rasterization
+ * - Make sure your LCD is running in its native resolution
+ *
+ * If translation is (0,0):
+ * a point will be drawn where x%2==0 and y%2==0,
+ * a horizontal line will be drawn where x%2==0,
+ * a vertical line will be drawn where y%2==0,
+ * for quads, pixels will be set where (x%4)!=3 and (y%4)!=3
+ *
+ * XXX todo: do glReadPixels and test that the results are what's expected.
+ * Upon failure, iterate over sub-pixel translations to find the ideal offset.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glut.h>
+
+static int Width = 400, Height = 400;
+static int Win;
+static float Xtrans = 0, Ytrans = 0;
+static float Step = 0.125;
+
+enum {
+ POINTS,
+ HLINES,
+ VLINES,
+ QUADS,
+ NUM_MODES
+};
+
+static int Mode = POINTS;
+
+
+static void
+Draw(void)
+{
+ /* See the OpenGL Programming Guide, Appendix H, "OpenGL Correctness Tips"
+ * for information about the 0.375 translation factor.
+ */
+ float tx = 0.375, ty = 0.375;
+ int i, j;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glTranslatef(tx + Xtrans, ty + Ytrans, 0);
+
+ if (Mode == POINTS) {
+ glBegin(GL_POINTS);
+ for (j = 0; j < Height; j += 2) {
+ for (i = 0; i < Width; i += 2) {
+ glVertex2f(i, j);
+ }
+ }
+ glEnd();
+ }
+ else if (Mode == HLINES) {
+ glBegin(GL_LINES);
+ for (i = 0; i < Height; i += 2) {
+ glVertex2f(0, i);
+ glVertex2f(Width, i);
+ }
+ glEnd();
+ }
+ else if (Mode == VLINES) {
+ glBegin(GL_LINES);
+ for (i = 0; i < Width; i += 2) {
+ glVertex2f(i, 0 );
+ glVertex2f(i, Height);
+ }
+ glEnd();
+ }
+ else if (Mode == QUADS) {
+ glBegin(GL_QUADS);
+ for (j = 0; j < Height; j += 4) {
+ for (i = 0; i < Width; i += 4) {
+ glVertex2f(i, j );
+ glVertex2f(i + 3, j );
+ glVertex2f(i + 3, j + 3);
+ glVertex2f(i, j + 3);
+ }
+ }
+ glEnd();
+ }
+
+ 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 'm':
+ case 'M':
+ Mode = (Mode + 1) % NUM_MODES;
+ break;
+ case 'z':
+ case 'Z':
+ Xtrans = Ytrans = 0;
+ printf("Translation: %f, %f\n", Xtrans, Ytrans);
+ break;
+ case 27:
+ glutDestroyWindow(Win);
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case GLUT_KEY_UP:
+ Ytrans += Step;
+ break;
+ case GLUT_KEY_DOWN:
+ Ytrans -= Step;
+ break;
+ case GLUT_KEY_LEFT:
+ Xtrans -= Step;
+ break;
+ case GLUT_KEY_RIGHT:
+ Xtrans += Step;
+ break;
+ }
+ glutPostRedisplay();
+ printf("Translation: %f, %f\n", Xtrans, Ytrans);
+}
+
+
+static void
+Init(void)
+{
+}
+
+
+static void
+Usage(void)
+{
+ printf("Keys:\n");
+ printf(" up/down/left/right - translate by %f\n", Step);
+ printf(" z - reset translation to zero\n");
+ printf(" m - change rendering mode (points, hlines, vlines, quads)\n");
+ printf(" Esc - exit\n");
+}
+
+
+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);
+ glutSpecialFunc(SpecialKey);
+ glutDisplayFunc(Draw);
+ Init();
+ Usage();
+ glutMainLoop();
+ return 0;
+}