132001f49Smrg/*
232001f49Smrg * Demo of (nearly) flicker-free drawing with a single color buffer.
332001f49Smrg *
432001f49Smrg * Basically, draw the scene into the Z buffer first, then draw the
532001f49Smrg * scene into the color buffer.  Finally, "clear" the background by
632001f49Smrg * setting the fragments we didn't hit earlier.
732001f49Smrg *
832001f49Smrg * This won't work if you need blending.  The technique works best
932001f49Smrg * when the scene is relatively simple and can be rendered quickly
1032001f49Smrg * (i.e. with hardware), and when the objects don't move too much from
1132001f49Smrg * one frame to the next.
1232001f49Smrg *
1332001f49Smrg * Brian Paul
1432001f49Smrg * 25 August 2005
1532001f49Smrg *
1632001f49Smrg * See Mesa license for terms.
1732001f49Smrg */
1832001f49Smrg
1932001f49Smrg
2032001f49Smrg#include <stdio.h>
2132001f49Smrg#include <stdlib.h>
2232001f49Smrg#include "glut_wrap.h"
2332001f49Smrg
2432001f49Smrg
2532001f49Smrg#define FLICKER 0
2632001f49Smrg#define NO_FLICKER 1
2732001f49Smrg
2832001f49Smrgstatic GLint Mode = NO_FLICKER;
2932001f49Smrgstatic GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
3032001f49Smrgstatic GLboolean Anim = GL_TRUE;
3132001f49Smrgstatic GLfloat ClearColor[4] = {0.2, 0.2, 0.9, 0.0};
3232001f49Smrgstatic GLfloat NearClip = 5.0, FarClip = 25.0, ViewDist = 7.0;
3332001f49Smrgstatic double PrevTime = -1;
3432001f49Smrg
3532001f49Smrgstruct box {
3632001f49Smrg   float tx, ty, tz;
3732001f49Smrg   float rx, ry, rz, ra;
3832001f49Smrg   float sx, sy, sz;
3932001f49Smrg   float color[4];
4032001f49Smrg};
4132001f49Smrg
4232001f49Smrg#define NUM_BOXES 25
4332001f49Smrg
4432001f49Smrgstruct box Boxes[NUM_BOXES];
4532001f49Smrg
4632001f49Smrg
4732001f49Smrg/* Return random float in [0,1] */
4832001f49Smrgstatic float
4932001f49SmrgRandom(void)
5032001f49Smrg{
5132001f49Smrg   int i = rand();
5232001f49Smrg   return (float) (i % 1000) / 1000.0;
5332001f49Smrg}
5432001f49Smrg
5532001f49Smrg
5632001f49Smrgstatic void
5732001f49SmrgMakeBoxes(void)
5832001f49Smrg{
5932001f49Smrg   int i;
6032001f49Smrg   for (i = 0; i < NUM_BOXES; i++) {
6132001f49Smrg      Boxes[i].tx = -1.0 + 2.0 * Random();
6232001f49Smrg      Boxes[i].ty = -1.0 + 2.0 * Random();
6332001f49Smrg      Boxes[i].tz = -1.0 + 2.0 * Random();
6432001f49Smrg      Boxes[i].sx = 0.1 + Random() * 0.4;
6532001f49Smrg      Boxes[i].sy = 0.1 + Random() * 0.4;
6632001f49Smrg      Boxes[i].sz = 0.1 + Random() * 0.4;
6732001f49Smrg      Boxes[i].rx = Random();
6832001f49Smrg      Boxes[i].ry = Random();
6932001f49Smrg      Boxes[i].rz = Random();
7032001f49Smrg      Boxes[i].ra = Random() * 360.0;
7132001f49Smrg      Boxes[i].color[0] = Random();
7232001f49Smrg      Boxes[i].color[1] = Random();
7332001f49Smrg      Boxes[i].color[2] = Random();
7432001f49Smrg      Boxes[i].color[3] = 1.0;
7532001f49Smrg   }
7632001f49Smrg}
7732001f49Smrg
7832001f49Smrg
7932001f49Smrgstatic void
8032001f49SmrgDrawBoxes(void)
8132001f49Smrg{
8232001f49Smrg   int i;
8332001f49Smrg   for (i = 0; i < NUM_BOXES; i++) {
8432001f49Smrg      glPushMatrix();
8532001f49Smrg      glTranslatef(Boxes[i].tx, Boxes[i].ty, Boxes[i].tz);
8632001f49Smrg      glRotatef(Boxes[i].ra, Boxes[i].rx, Boxes[i].ry, Boxes[i].rz);
8732001f49Smrg      glScalef(Boxes[i].sx, Boxes[i].sy, Boxes[i].sz);
8832001f49Smrg      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, Boxes[i].color);
8932001f49Smrg      glutSolidCube(1.0);
9032001f49Smrg      glPopMatrix();
9132001f49Smrg   }
9232001f49Smrg}
9332001f49Smrg
9432001f49Smrg
9532001f49Smrgstatic void
9632001f49SmrgIdle(void)
9732001f49Smrg{
9832001f49Smrg   double dt, t = glutGet(GLUT_ELAPSED_TIME) * 0.001;
9932001f49Smrg   if (PrevTime < 0.0)
10032001f49Smrg      PrevTime = t;
10132001f49Smrg   dt = t - PrevTime;
10232001f49Smrg   PrevTime = t;
10332001f49Smrg   Xrot += 16.0 * dt;
10432001f49Smrg   Yrot += 12.0 * dt;
10532001f49Smrg   Zrot += 8.0 * dt;
10632001f49Smrg   glutPostRedisplay();
10732001f49Smrg}
10832001f49Smrg
10932001f49Smrg
11032001f49Smrgstatic void
11132001f49SmrgDraw(void)
11232001f49Smrg{
11332001f49Smrg   if (Mode == FLICKER) {
11432001f49Smrg      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
11532001f49Smrg   }
11632001f49Smrg   else {
11732001f49Smrg      /* don't clear color buffer */
11832001f49Smrg      glClear(GL_DEPTH_BUFFER_BIT);
11932001f49Smrg      /* update Z buffer only */
12032001f49Smrg      glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
12132001f49Smrg   }
12232001f49Smrg
12332001f49Smrg   glPushMatrix();
12432001f49Smrg   glRotatef(Xrot, 1, 0, 0);
12532001f49Smrg   glRotatef(Yrot, 0, 1, 0);
12632001f49Smrg   glRotatef(Zrot, 0, 0, 1);
12732001f49Smrg
12832001f49Smrg   DrawBoxes();
12932001f49Smrg
13032001f49Smrg   if (Mode == NO_FLICKER) {
13132001f49Smrg      /* update color buffer now */
13232001f49Smrg      glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
13332001f49Smrg      glDepthFunc(GL_EQUAL);
13432001f49Smrg      DrawBoxes();
13532001f49Smrg      glDepthFunc(GL_LESS);
13632001f49Smrg   }
13732001f49Smrg
13832001f49Smrg   glPopMatrix();
13932001f49Smrg
14032001f49Smrg   if (Mode == NO_FLICKER) {
14132001f49Smrg      /* "clear" the untouched pixels now.
14232001f49Smrg       * Note: if you comment-out this code you'll see something interesting.
14332001f49Smrg       */
14432001f49Smrg      GLfloat x = FarClip / NearClip;
14532001f49Smrg      GLfloat z = -(FarClip - ViewDist - 1.0);
14632001f49Smrg      glDisable(GL_LIGHTING);
14732001f49Smrg      glColor4fv(ClearColor);
14832001f49Smrg      glBegin(GL_POLYGON);
14932001f49Smrg      glVertex3f(-x, -x, z);
15032001f49Smrg      glVertex3f( x, -x, z);
15132001f49Smrg      glVertex3f( x,  x, z);
15232001f49Smrg      glVertex3f(-x,  x, z);
15332001f49Smrg      glEnd();
15432001f49Smrg      glEnable(GL_LIGHTING);
15532001f49Smrg   }
15632001f49Smrg
15732001f49Smrg   /* This is where you'd normally do SwapBuffers */
15832001f49Smrg   glFinish();
15932001f49Smrg}
16032001f49Smrg
16132001f49Smrg
16232001f49Smrgstatic void
16332001f49SmrgReshape(int width, int height)
16432001f49Smrg{
16532001f49Smrg   glViewport(0, 0, width, height);
16632001f49Smrg   glMatrixMode(GL_PROJECTION);
16732001f49Smrg   glLoadIdentity();
16832001f49Smrg   glFrustum(-1.0, 1.0, -1.0, 1.0, NearClip, FarClip);
16932001f49Smrg   glMatrixMode(GL_MODELVIEW);
17032001f49Smrg   glLoadIdentity();
17132001f49Smrg   glTranslatef(0.0, 0.0, -ViewDist);
17232001f49Smrg}
17332001f49Smrg
17432001f49Smrg
17532001f49Smrgstatic void
17632001f49SmrgKey(unsigned char key, int x, int y)
17732001f49Smrg{
17832001f49Smrg   (void) x;
17932001f49Smrg   (void) y;
18032001f49Smrg   switch (key) {
18132001f49Smrg      case 'a':
18232001f49Smrg         Anim = !Anim;
18332001f49Smrg         if (Anim)
18432001f49Smrg            glutIdleFunc(Idle);
18532001f49Smrg         else
18632001f49Smrg            glutIdleFunc(NULL);
18732001f49Smrg         PrevTime = -1;
18832001f49Smrg         break;
18932001f49Smrg      case 'm':
19032001f49Smrg         Mode = !Mode;
19132001f49Smrg         break;
19232001f49Smrg      case 'b':
19332001f49Smrg         MakeBoxes();
19432001f49Smrg         break;
19532001f49Smrg      case 27:
19632001f49Smrg         exit(0);
19732001f49Smrg         break;
19832001f49Smrg   }
19932001f49Smrg   glutPostRedisplay();
20032001f49Smrg}
20132001f49Smrg
20232001f49Smrg
20332001f49Smrgstatic void
20432001f49SmrgSpecialKey(int key, int x, int y)
20532001f49Smrg{
20632001f49Smrg   const GLfloat step = 3.0;
20732001f49Smrg   (void) x;
20832001f49Smrg   (void) y;
20932001f49Smrg   switch (key) {
21032001f49Smrg      case GLUT_KEY_UP:
21132001f49Smrg         Xrot -= step;
21232001f49Smrg         break;
21332001f49Smrg      case GLUT_KEY_DOWN:
21432001f49Smrg         Xrot += step;
21532001f49Smrg         break;
21632001f49Smrg      case GLUT_KEY_LEFT:
21732001f49Smrg         Yrot -= step;
21832001f49Smrg         break;
21932001f49Smrg      case GLUT_KEY_RIGHT:
22032001f49Smrg         Yrot += step;
22132001f49Smrg         break;
22232001f49Smrg   }
22332001f49Smrg   glutPostRedisplay();
22432001f49Smrg}
22532001f49Smrg
22632001f49Smrg
22732001f49Smrgstatic void
22832001f49SmrgInit(void)
22932001f49Smrg{
23032001f49Smrg   glClearColor(ClearColor[0], ClearColor[1], ClearColor[2], ClearColor[3]);
23132001f49Smrg   glEnable(GL_DEPTH_TEST);
23232001f49Smrg   glEnable(GL_LIGHTING);
23332001f49Smrg   glEnable(GL_LIGHT0);
23432001f49Smrg   glEnable(GL_CULL_FACE);
23532001f49Smrg   glEnable(GL_NORMALIZE);
23632001f49Smrg   MakeBoxes();
23732001f49Smrg}
23832001f49Smrg
23932001f49Smrg
24032001f49Smrgstatic void
24132001f49SmrgUsage(void)
24232001f49Smrg{
24332001f49Smrg   printf("Keys:\n");
24432001f49Smrg   printf("  m       - toggle drawing mode (flicker vs. no flicker)\n");
24532001f49Smrg   printf("  a       - toggle animation\n");
24632001f49Smrg   printf("  b       - generate new boxes\n");
24732001f49Smrg   printf("  ARROWS  - rotate scene\n");
24832001f49Smrg   printf("  ESC     - exit\n");
24932001f49Smrg}
25032001f49Smrg
25132001f49Smrg
25232001f49Smrgint
25332001f49Smrgmain(int argc, char *argv[])
25432001f49Smrg{
25532001f49Smrg   glutInit(&argc, argv);
25632001f49Smrg   glutInitWindowSize(800, 800);
25732001f49Smrg   glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH);
25832001f49Smrg   glutCreateWindow(argv[0]);
25932001f49Smrg   glutReshapeFunc(Reshape);
26032001f49Smrg   glutKeyboardFunc(Key);
26132001f49Smrg   glutSpecialFunc(SpecialKey);
26232001f49Smrg   glutDisplayFunc(Draw);
26332001f49Smrg   if (Anim)
26432001f49Smrg      glutIdleFunc(Idle);
26532001f49Smrg   Init();
26632001f49Smrg   Usage();
26732001f49Smrg   glutMainLoop();
26832001f49Smrg   return 0;
26932001f49Smrg}
270