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