Merge remote branch 'origin/7.8'
[mesa.git] / progs / demos / singlebuffer.c
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 <GL/glut.h>
23
24
25 #define FLICKER 0
26 #define NO_FLICKER 1
27
28 static GLint Mode = NO_FLICKER;
29 static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
30 static GLboolean Anim = GL_TRUE;
31 static GLfloat ClearColor[4] = {0.2, 0.2, 0.9, 0.0};
32 static GLfloat NearClip = 5.0, FarClip = 25.0, ViewDist = 7.0;
33 static double PrevTime = -1;
34
35 struct 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
44 struct box Boxes[NUM_BOXES];
45
46
47 /* Return random float in [0,1] */
48 static float
49 Random(void)
50 {
51 int i = rand();
52 return (float) (i % 1000) / 1000.0;
53 }
54
55
56 static void
57 MakeBoxes(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
79 static void
80 DrawBoxes(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
95 static void
96 Idle(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
110 static void
111 Draw(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
162 static void
163 Reshape(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
175 static void
176 Key(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
203 static void
204 SpecialKey(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
227 static void
228 Init(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
240 static void
241 Usage(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
252 int
253 main(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 }