270 lines
5.6 KiB
C
270 lines
5.6 KiB
C
|
/*
|
||
|
* 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;
|
||
|
}
|