Demo of how to do (nearly) flicker-free rendering with a single color buffer.
authorBrian Paul <brian.paul@tungstengraphics.com>
Thu, 25 Aug 2005 23:25:25 +0000 (23:25 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Thu, 25 Aug 2005 23:25:25 +0000 (23:25 +0000)
progs/demos/Makefile
progs/demos/singlebuffer.c [new file with mode: 0644]

index 4bd72d8..109d0ac 100644 (file)
@@ -44,6 +44,7 @@ PROGS = \
        reflect \
        renormal \
        shadowtex \
+       singlebuffer \
        spectex \
        spriteblast \
        stex3d \
diff --git a/progs/demos/singlebuffer.c b/progs/demos/singlebuffer.c
new file mode 100644 (file)
index 0000000..9899c24
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Demo of (nearly) flicker-free drawing with a single color buffer.
+ *
+ * Basically, draw the scene into the Z buffer first, then draw the
+ * scene into the color buffer.  Finally, "clear" the background by
+ * setting the fragments we didn't hit earlier.
+ *
+ * This won't work if you need blending.  The technique works best
+ * when the scene is relatively simple and can be rendered quickly
+ * (i.e. with hardware), and when the objects don't move too much from
+ * one frame to the next.
+ *
+ * Brian Paul
+ * 25 August 2005
+ *
+ * See Mesa license for terms.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glut.h>
+
+
+#define FLICKER 0
+#define NO_FLICKER 1
+
+static GLint Mode = NO_FLICKER;
+static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
+static GLboolean Anim = GL_TRUE;
+static GLfloat ClearColor[4] = {0.2, 0.2, 0.9, 0.0};
+static GLfloat NearClip = 5.0, FarClip = 25.0, ViewDist = 7.0;
+static double PrevTime = -1;
+
+struct box {
+   float tx, ty, tz;
+   float rx, ry, rz, ra;
+   float sx, sy, sz;
+   float color[4];
+};
+
+#define NUM_BOXES 25
+
+struct box Boxes[NUM_BOXES];
+
+
+/* Return random float in [0,1] */
+static float
+Random(void)
+{
+   int i = rand();
+   return (float) (i % 1000) / 1000.0;
+}
+
+
+static void
+MakeBoxes(void)
+{
+   int i;
+   for (i = 0; i < NUM_BOXES; i++) {
+      Boxes[i].tx = -1.0 + 2.0 * Random();
+      Boxes[i].ty = -1.0 + 2.0 * Random();
+      Boxes[i].tz = -1.0 + 2.0 * Random();
+      Boxes[i].sx = 0.1 + Random() * 0.4;
+      Boxes[i].sy = 0.1 + Random() * 0.4;
+      Boxes[i].sz = 0.1 + Random() * 0.4;
+      Boxes[i].rx = Random();
+      Boxes[i].ry = Random();
+      Boxes[i].rz = Random();
+      Boxes[i].ra = Random() * 360.0;
+      Boxes[i].color[0] = Random();
+      Boxes[i].color[1] = Random();
+      Boxes[i].color[2] = Random();
+      Boxes[i].color[3] = 1.0;
+   }
+}
+
+
+static void
+DrawBoxes(void)
+{
+   int i;
+   for (i = 0; i < NUM_BOXES; i++) {
+      glPushMatrix();
+      glTranslatef(Boxes[i].tx, Boxes[i].ty, Boxes[i].tz);
+      glRotatef(Boxes[i].ra, Boxes[i].rx, Boxes[i].ry, Boxes[i].rz);
+      glScalef(Boxes[i].sx, Boxes[i].sy, Boxes[i].sz);
+      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, Boxes[i].color);
+      glutSolidCube(1.0);
+      glPopMatrix();
+   }
+}
+
+
+static void
+Idle(void)
+{
+   double dt, t = glutGet(GLUT_ELAPSED_TIME) * 0.001;
+   if (PrevTime < 0.0)
+      PrevTime = t;
+   dt = t - PrevTime;
+   PrevTime = t;
+   Xrot += 16.0 * dt;
+   Yrot += 12.0 * dt;
+   Zrot += 8.0 * dt;
+   glutPostRedisplay();
+}
+
+
+static void
+Draw(void)
+{
+   if (Mode == FLICKER) {
+      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+   }
+   else {
+      /* don't clear color buffer */
+      glClear(GL_DEPTH_BUFFER_BIT);
+      /* update Z buffer only */
+      glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+   }
+
+   glPushMatrix();
+   glRotatef(Xrot, 1, 0, 0);
+   glRotatef(Yrot, 0, 1, 0);
+   glRotatef(Zrot, 0, 0, 1);
+
+   DrawBoxes();
+
+   if (Mode == NO_FLICKER) {
+      /* update color buffer now */
+      glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+      glDepthFunc(GL_EQUAL);
+      DrawBoxes();
+      glDepthFunc(GL_LESS);
+   }
+
+   glPopMatrix();
+
+   if (Mode == NO_FLICKER) {
+      /* "clear" the untouched pixels now.
+       * Note: if you comment-out this code you'll see something interesting.
+       */
+      GLfloat x = FarClip / NearClip;
+      GLfloat z = -(FarClip - ViewDist - 1.0);
+      glDisable(GL_LIGHTING);
+      glColor4fv(ClearColor);
+      glBegin(GL_POLYGON);
+      glVertex3f(-x, -x, z);
+      glVertex3f( x, -x, z);
+      glVertex3f( x,  x, z);
+      glVertex3f(-x,  x, z);
+      glEnd();
+      glEnable(GL_LIGHTING);
+   }
+
+   /* This is where you'd normally do SwapBuffers */
+   glFinish();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+   glViewport(0, 0, width, height);
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glFrustum(-1.0, 1.0, -1.0, 1.0, NearClip, FarClip);
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glTranslatef(0.0, 0.0, -ViewDist);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+   (void) x;
+   (void) y;
+   switch (key) {
+      case 'a':
+         Anim = !Anim;
+         if (Anim)
+            glutIdleFunc(Idle);
+         else
+            glutIdleFunc(NULL);
+         PrevTime = -1;
+         break;
+      case 'm':
+         Mode = !Mode;
+         break;
+      case 'b':
+         MakeBoxes();
+         break;
+      case 27:
+         exit(0);
+         break;
+   }
+   glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+   const GLfloat step = 3.0;
+   (void) x;
+   (void) y;
+   switch (key) {
+      case GLUT_KEY_UP:
+         Xrot -= step;
+         break;
+      case GLUT_KEY_DOWN:
+         Xrot += step;
+         break;
+      case GLUT_KEY_LEFT:
+         Yrot -= step;
+         break;
+      case GLUT_KEY_RIGHT:
+         Yrot += step;
+         break;
+   }
+   glutPostRedisplay();
+}
+
+
+static void
+Init(void)
+{
+   glClearColor(ClearColor[0], ClearColor[1], ClearColor[2], ClearColor[3]);
+   glEnable(GL_DEPTH_TEST);
+   glEnable(GL_LIGHTING);
+   glEnable(GL_LIGHT0);
+   glEnable(GL_CULL_FACE);
+   glEnable(GL_NORMALIZE);
+   MakeBoxes();
+}
+
+
+static void
+Usage(void)
+{
+   printf("Keys:\n");
+   printf("  m       - toggle drawing mode (flicker vs. no flicker)\n");
+   printf("  a       - toggle animation\n");
+   printf("  b       - generate new boxes\n");
+   printf("  ARROWS  - rotate scene\n");
+   printf("  ESC     - exit\n");
+}
+
+
+int
+main(int argc, char *argv[])
+{
+   glutInit(&argc, argv);
+   glutInitWindowSize(800, 800);
+   glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH);
+   glutCreateWindow(argv[0]);
+   glutReshapeFunc(Reshape);
+   glutKeyboardFunc(Key);
+   glutSpecialFunc(SpecialKey);
+   glutDisplayFunc(Draw);
+   if (Anim)
+      glutIdleFunc(Idle);
+   Init();
+   Usage();
+   glutMainLoop();
+   return 0;
+}