singlebuffer.c revision 32001f49
1/*
2 * Demo of (nearly) flicker-free drawing with a single color buffer.
3 *
4 * Basically, draw the scene into the Z buffer first, then draw the
5 * scene into the color buffer.  Finally, "clear" the background by
6 * setting the fragments we didn't hit earlier.
7 *
8 * This won't work if you need blending.  The technique works best
9 * when the scene is relatively simple and can be rendered quickly
10 * (i.e. with hardware), and when the objects don't move too much from
11 * one frame to the next.
12 *
13 * Brian Paul
14 * 25 August 2005
15 *
16 * See Mesa license for terms.
17 */
18
19
20#include <stdio.h>
21#include <stdlib.h>
22#include "glut_wrap.h"
23
24
25#define FLICKER 0
26#define NO_FLICKER 1
27
28static GLint Mode = NO_FLICKER;
29static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
30static GLboolean Anim = GL_TRUE;
31static GLfloat ClearColor[4] = {0.2, 0.2, 0.9, 0.0};
32static GLfloat NearClip = 5.0, FarClip = 25.0, ViewDist = 7.0;
33static double PrevTime = -1;
34
35struct box {
36   float tx, ty, tz;
37   float rx, ry, rz, ra;
38   float sx, sy, sz;
39   float color[4];
40};
41
42#define NUM_BOXES 25
43
44struct box Boxes[NUM_BOXES];
45
46
47/* Return random float in [0,1] */
48static float
49Random(void)
50{
51   int i = rand();
52   return (float) (i % 1000) / 1000.0;
53}
54
55
56static void
57MakeBoxes(void)
58{
59   int i;
60   for (i = 0; i < NUM_BOXES; i++) {
61      Boxes[i].tx = -1.0 + 2.0 * Random();
62      Boxes[i].ty = -1.0 + 2.0 * Random();
63      Boxes[i].tz = -1.0 + 2.0 * Random();
64      Boxes[i].sx = 0.1 + Random() * 0.4;
65      Boxes[i].sy = 0.1 + Random() * 0.4;
66      Boxes[i].sz = 0.1 + Random() * 0.4;
67      Boxes[i].rx = Random();
68      Boxes[i].ry = Random();
69      Boxes[i].rz = Random();
70      Boxes[i].ra = Random() * 360.0;
71      Boxes[i].color[0] = Random();
72      Boxes[i].color[1] = Random();
73      Boxes[i].color[2] = Random();
74      Boxes[i].color[3] = 1.0;
75   }
76}
77
78
79static void
80DrawBoxes(void)
81{
82   int i;
83   for (i = 0; i < NUM_BOXES; i++) {
84      glPushMatrix();
85      glTranslatef(Boxes[i].tx, Boxes[i].ty, Boxes[i].tz);
86      glRotatef(Boxes[i].ra, Boxes[i].rx, Boxes[i].ry, Boxes[i].rz);
87      glScalef(Boxes[i].sx, Boxes[i].sy, Boxes[i].sz);
88      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, Boxes[i].color);
89      glutSolidCube(1.0);
90      glPopMatrix();
91   }
92}
93
94
95static void
96Idle(void)
97{
98   double dt, t = glutGet(GLUT_ELAPSED_TIME) * 0.001;
99   if (PrevTime < 0.0)
100      PrevTime = t;
101   dt = t - PrevTime;
102   PrevTime = t;
103   Xrot += 16.0 * dt;
104   Yrot += 12.0 * dt;
105   Zrot += 8.0 * dt;
106   glutPostRedisplay();
107}
108
109
110static void
111Draw(void)
112{
113   if (Mode == FLICKER) {
114      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
115   }
116   else {
117      /* don't clear color buffer */
118      glClear(GL_DEPTH_BUFFER_BIT);
119      /* update Z buffer only */
120      glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
121   }
122
123   glPushMatrix();
124   glRotatef(Xrot, 1, 0, 0);
125   glRotatef(Yrot, 0, 1, 0);
126   glRotatef(Zrot, 0, 0, 1);
127
128   DrawBoxes();
129
130   if (Mode == NO_FLICKER) {
131      /* update color buffer now */
132      glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
133      glDepthFunc(GL_EQUAL);
134      DrawBoxes();
135      glDepthFunc(GL_LESS);
136   }
137
138   glPopMatrix();
139
140   if (Mode == NO_FLICKER) {
141      /* "clear" the untouched pixels now.
142       * Note: if you comment-out this code you'll see something interesting.
143       */
144      GLfloat x = FarClip / NearClip;
145      GLfloat z = -(FarClip - ViewDist - 1.0);
146      glDisable(GL_LIGHTING);
147      glColor4fv(ClearColor);
148      glBegin(GL_POLYGON);
149      glVertex3f(-x, -x, z);
150      glVertex3f( x, -x, z);
151      glVertex3f( x,  x, z);
152      glVertex3f(-x,  x, z);
153      glEnd();
154      glEnable(GL_LIGHTING);
155   }
156
157   /* This is where you'd normally do SwapBuffers */
158   glFinish();
159}
160
161
162static void
163Reshape(int width, int height)
164{
165   glViewport(0, 0, width, height);
166   glMatrixMode(GL_PROJECTION);
167   glLoadIdentity();
168   glFrustum(-1.0, 1.0, -1.0, 1.0, NearClip, FarClip);
169   glMatrixMode(GL_MODELVIEW);
170   glLoadIdentity();
171   glTranslatef(0.0, 0.0, -ViewDist);
172}
173
174
175static void
176Key(unsigned char key, int x, int y)
177{
178   (void) x;
179   (void) y;
180   switch (key) {
181      case 'a':
182         Anim = !Anim;
183         if (Anim)
184            glutIdleFunc(Idle);
185         else
186            glutIdleFunc(NULL);
187         PrevTime = -1;
188         break;
189      case 'm':
190         Mode = !Mode;
191         break;
192      case 'b':
193         MakeBoxes();
194         break;
195      case 27:
196         exit(0);
197         break;
198   }
199   glutPostRedisplay();
200}
201
202
203static void
204SpecialKey(int key, int x, int y)
205{
206   const GLfloat step = 3.0;
207   (void) x;
208   (void) y;
209   switch (key) {
210      case GLUT_KEY_UP:
211         Xrot -= step;
212         break;
213      case GLUT_KEY_DOWN:
214         Xrot += step;
215         break;
216      case GLUT_KEY_LEFT:
217         Yrot -= step;
218         break;
219      case GLUT_KEY_RIGHT:
220         Yrot += step;
221         break;
222   }
223   glutPostRedisplay();
224}
225
226
227static void
228Init(void)
229{
230   glClearColor(ClearColor[0], ClearColor[1], ClearColor[2], ClearColor[3]);
231   glEnable(GL_DEPTH_TEST);
232   glEnable(GL_LIGHTING);
233   glEnable(GL_LIGHT0);
234   glEnable(GL_CULL_FACE);
235   glEnable(GL_NORMALIZE);
236   MakeBoxes();
237}
238
239
240static void
241Usage(void)
242{
243   printf("Keys:\n");
244   printf("  m       - toggle drawing mode (flicker vs. no flicker)\n");
245   printf("  a       - toggle animation\n");
246   printf("  b       - generate new boxes\n");
247   printf("  ARROWS  - rotate scene\n");
248   printf("  ESC     - exit\n");
249}
250
251
252int
253main(int argc, char *argv[])
254{
255   glutInit(&argc, argv);
256   glutInitWindowSize(800, 800);
257   glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH);
258   glutCreateWindow(argv[0]);
259   glutReshapeFunc(Reshape);
260   glutKeyboardFunc(Key);
261   glutSpecialFunc(SpecialKey);
262   glutDisplayFunc(Draw);
263   if (Anim)
264      glutIdleFunc(Idle);
265   Init();
266   Usage();
267   glutMainLoop();
268   return 0;
269}
270