/*****************************************************************************
*
* sierpinski.cpp
*
* Draws a Sierpinski triangle bounded by the first three left button clicks.
*****************************************************************************/
#include <GL/glut.h>
#include <vector>
using namespace std;
// Simple 2-D point class.
class Point {
GLfloat x, y;
public:
Point(GLfloat x = 0, GLfloat y = 0): x(x), y(y) {}
void draw() {glBegin(GL_POINTS); glVertex2f(x, y); glEnd();}
Point midpoint(Point p) {return Point((x + p.x) / 2.0, (y + p.y) / 2.0);}
bool operator <(Point p) const {return x*x + y*y < p.x*p.x + p.y*p.y;}
bool operator ==(Point p) const {return x == p.x && y == p.y;}
};
// The vertices of the triangle, and the last point in the sequence.
static vector<Point> vertices(3);
static Point lastPoint;
// Set the drawing state to a new random color.
void newColor() {
glColor3f((GLfloat)rand()/RAND_MAX,
(GLfloat)rand()/RAND_MAX,
(GLfloat)rand()/RAND_MAX);
}
// Display a help window.
void about() {
#ifdef WIN32
MessageBox(0, "Sierpinski\nTriangle\n\n(c) 2002", "About", MB_OK);
#endif
}
// Keep the world coordinates equal to the screen coordinates.
void reshape(GLint w, GLint h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, h, 0);
glMatrixMode(GL_MODELVIEW);
}
// All drawing will be done on th idle callback, so just clear the window
// when asked to display anything.
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}
// Draw the next batch of points during idle.
void idle() {
for (int k = 0; k < 200; k++) {
lastPoint = lastPoint.midpoint(vertices[rand() % 3]);
lastPoint.draw();
}
glFlush();
}
// Mouse callback:
void mouse(int button, int state, int x, int y) {
static int numClicks = 0;
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
cout << numClicks;
if (numClicks < 3) {
vertices[numClicks++] = Point(x, y);
if (numClicks == 3) {
lastPoint = vertices[2];
glutIdleFunc(idle);
}
} else {
newColor();
}
} else if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP) {
about();
}
}
// Keyboard callback:
void keyboard(unsigned char key, int x, int y) {
if (key == ' ') {
newColor();
} else if (key == 27) {
about();
}
}
// The usual main() for a GLUT application.
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(640, 400);
glutCreateWindow("Sierpinski Triangle");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutMainLoop();
}/*****************************************************************************
*
* shapeshooter.cpp
*
* A trivial little program animating little colored balls being shot out
* of a cone and falling through a torus. The cone is centered at (-2,0,0),
* the torus is centered at (2,0,0) and the balls move along the curve
* \u.(u,4-u^2), starting at the cone center, meaning u = -2.
*
*****************************************************************************/
#include <GL/glut.h>
#include <cmath>
using namespace std;
// Colors
GLfloat WHITE[] = {1, 1, 1, 1};
GLfloat RED[] = {1, 0, 0, 1};
GLfloat GREEN[] = {0, 1, 0, 1};
GLfloat MAGENTA[] = {1, 0, 1, 1};
// A camera. It moves horizontally in a circle centered at the origin with a
// given radius. It moves vertically straight up and down.
class Camera {
double theta; // determines the x and z positions
double y; // the current y position
double dTheta; // increment in theta for swinging the camera around
double dy; // increment in y for moving the camera up/down
double radius;
public:
Camera(int r): theta(1.57), y(5), dTheta(0.04), dy(0.4), radius(r) {}
double getX() {return radius * cos(theta);}
double getY() {return y;}
double getZ() {return radius * sin(theta);}
void moveRight() {theta += dTheta;}
void moveLeft() {theta -= dTheta;}
void moveUp() {y += dy;}
void moveDown() {y -= dy;}
};
// A ball. A ball has a radius, a color, and moves along the parabola
// \u.(u, 4-u^2) from u in -2..2
class Ball {
double radius;
GLfloat* color;
double u;
public:
Ball(double r, GLfloat* c): radius(r), color(c), u(-2) {}
double getU() {return u;}
void update() {
u += 0.05;
}
void draw() {
glPushMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
glTranslated(u, 4.0 - u * u, 0);
glutSolidSphere(radius, 30, 30);
glPopMatrix();
}
};
// A global camera for the scene.
Camera camera(10);
// A scene object ot manage all the balls. We allow 20 balls at one time.
// The balls are kept in a fixed size array. To add a ball, we look for
// an empty array slot and put a new ball there, and if there is no empty
// slot we refuse to add the ball. Every time we have to draw the scene
// we update the positions of all the balls in the scene and draw them.
// If any of the balls pass u = 3, we deallocate them from memory and
// remove them from the array.
class Scene {
Ball* balls[20];
public:
Scene() {
for (int i = 0; i < sizeof balls / sizeof (Ball*); i++) {
balls[i] == 0;
}
}
void addBall() {
for (int i = 0; i < sizeof balls / sizeof (Ball*); i++) {
if (balls[i] == 0) {
balls[i] = new Ball(0.3, MAGENTA);
break;
}
}
}
void draw() {
glLoadIdentity();
gluLookAt(camera.getX(), camera.getY(), camera.getZ(), 0, 2, 0, 0, 1, 0);
// Update and draw each ball, and delete the ones that went too far.
for (int i = 0; i < sizeof balls / sizeof (Ball*); i++) {
if (balls[i] != 0) {
balls[i]->update();
balls[i]->draw();
if (balls[i]->getU() > 3) {
delete balls[i];
balls[i] = 0;
}
}
}
// A cone that the balls will be shot out of.
glPushMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, RED);
glTranslatef(-2, 1, 0);
glRotatef(90, 1.0, 0.0, 0.0);
glutSolidCone(1, 2, 50, 4);
glPopMatrix();
// A torus that the balls will fall through.
glPushMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, GREEN);
glTranslatef(2, 0, 0);
glRotatef(90, 1, 0, 0);
glutSolidTorus(0.3, 1, 50, 30);
glPopMatrix();
}
};
// A scene object.
Scene scene;
// Reshape callback: construct a camera that perfectly fits the window.
void reshape(GLint w, GLint h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0, GLfloat(w) / GLfloat(h), 1.0, 150.0);
glMatrixMode(GL_MODELVIEW);
}
// Display callback: draws the scene.
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
scene.draw();
glFlush();
glutSwapBuffers();
}
// Idle callback: just draw the next frame.
void idle() {
glutPostRedisplay();
}
// Keyboard handler: move the camera, then refresh display.
void special(int key, int, int) {
switch (key) {
case GLUT_KEY_LEFT: camera.moveLeft(); break;
case GLUT_KEY_RIGHT: camera.moveRight(); break;
case GLUT_KEY_UP: camera.moveUp(); break;
case GLUT_KEY_DOWN: camera.moveDown(); break;
}
glutPostRedisplay();
}
// Mouse callback: the left button will launch a ball.
void mouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
scene.addBall();
}
}
// Non-GLUT initialization best left out of main().
void myInit() {
glEnable(GL_DEPTH_TEST);
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glLightfv(GL_LIGHT0, GL_DIFFUSE, WHITE);
glLightfv(GL_LIGHT0, GL_SPECULAR, WHITE);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, WHITE);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 30);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}
// The usual main() for a GLUT application.
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition(80, 80);
glutInitWindowSize(520, 390);
glutCreateWindow("Click to shoot some balls");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutSpecialFunc(special);
glutIdleFunc(idle);
myInit();
glutMainLoop();
}
/*****************************************************************************
*
* stippledcircle.cpp
*
* This program animates a stippled circle bouncing around the window. The
* purpose of the program is to illustrate that stippling is relative to
* pixel coordinates and not to the polygon.
*
*****************************************************************************/
#include <GL/glut.h>
#include <cmath>
using namespace std;
// We will be bouncing a ball off the edges of the window so we have to keep
// track of the window size.
static GLint windowWidth = 500;
static GLint windowHeight = 500;
// This is a ball that keeps track of its own size, position and direction,
// and knows how to update itself during an animation, and knows how to
// draw itself (using a display list of course).
class Ball {
int x, y;
int dx, dy;
int radius;
int displayListId;
public:
Ball(): x(200), y(200), dx(3), dy(2), radius(80) {
}
void create() {
displayListId = glGenLists(1);
glNewList(displayListId, GL_COMPILE);
glBegin(GL_POLYGON);
for (double theta = 0; theta < 6.28; theta += 0.05){
glVertex3f(radius * cos(theta), radius * sin(theta), 0);
}
glEnd();
glEndList();
}
void update() {
x += dx;
y += dy;
if (x - radius < 0) x = 0 + radius, dx = -dx;
if (y - radius < 0) y = 0 + radius, dy = -dy;
if (x + radius > windowWidth) x = windowWidth - radius, dx = -dx;
if (y + radius > windowHeight) y = windowHeight - radius, dy = -dy;
}
void draw() {
glLoadIdentity();
glTranslatef(x, y, 0);
glCallList(displayListId);
}
};
// The one and only ball.
Ball ball;
// The stipple pattern from the OpenGL Red Book.
GLubyte fly[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x80, 0x01, 0xC0, 0x06, 0xC0, 0x03, 0x60,
0x04, 0x60, 0x06, 0x20, 0x04, 0x30, 0x0C, 0x20,
0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20,
0x04, 0x06, 0x60, 0x20, 0x44, 0x03, 0xC0, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x66, 0x01, 0x80, 0x66, 0x33, 0x01, 0x80, 0xCC,
0x19, 0x81, 0x81, 0x98, 0x0C, 0xC1, 0x83, 0x30,
0x07, 0xe1, 0x87, 0xe0, 0x03, 0x3f, 0xfc, 0xc0,
0x03, 0x31, 0x8c, 0xc0, 0x03, 0x33, 0xcc, 0xc0,
0x06, 0x64, 0x26, 0x60, 0x0c, 0xcc, 0x33, 0x30,
0x18, 0xcc, 0x33, 0x18, 0x10, 0xc4, 0x23, 0x08,
0x10, 0x63, 0xC6, 0x08, 0x10, 0x30, 0x0c, 0x08,
0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08
};
// Simple double buffered drawing callback.
void display() {
glClear(GL_COLOR_BUFFER_BIT);
ball.draw();
glFlush();
glutSwapBuffers();
}
// The ball just keeps bouncing around....
void idle() {
ball.update();
glutPostRedisplay();
}
// Keep the world coordinates equal to the screen coordinates.
void reshape(GLint w, GLint h) {
windowWidth = w;
windowHeight = h;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, 0, h);
glMatrixMode(GL_MODELVIEW);
}
// Non-GLUT initialization that we don't want to clutter main() with.
void myInit() {
glShadeModel(GL_FLAT);
glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple(fly);
ball.create();
}
// The usual main() for a GLUT application.
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(windowWidth, windowHeight);
glutCreateWindow("Bounce");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
myInit();
glutMainLoop();
}
/*****************************************************************************
*
* forest.cpp
*
* This program simulates a walk in the forest at night holding a flashlight.
* The ground has a grassy texture and there are many randomly placed trees.
* Walk forward and backward with the up and down arrow keys; turn with the
* left and right arrow keys.
*
*****************************************************************************/
#include <GL/glut.h>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include "ship.h"
#include "BMPloader.h"
using namespace std;
// Colors and points.
GLfloat BLACK[] = {0, 0, 0, 1};
GLfloat WHITE[] = {1, 1, 1, 1};
GLfloat DARK_GREY[] = {0.2, 0.2, 0.2, 1};
GLfloat GREEN[] = {0, 1, 0, 1};
GLfloat BROWN[] = {.4, .4, .1, 1};
GLfloat LEAF_COLOR[] = {0.22, 0.92, 0.22 ,1};
GLfloat ORIGIN[] = {0, 0, 0, 1};
// A tree class. A tree is made up of a green sphere sitting on top of
// a brown cone. The base of the cone is always on the xz plane.
class Tree {
GLdouble trunkRadius;
GLdouble trunkHeight;
GLdouble greenRadius;
GLdouble x;
GLdouble z;
public:
Tree(GLdouble r, GLdouble h, GLdouble g, GLdouble x, GLdouble z):
trunkRadius(r), trunkHeight(h), greenRadius(g), x(x), z(z) {
}
void draw() {
glPushMatrix();
glTranslated(x, 0, z);
// Trunk (note rotation because GLUT cone is aligned on z by default)
glPushMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, BROWN);
glRotated(-90.0, 1, 0, 0);
glutSolidCone(trunkRadius, trunkHeight + greenRadius*2, 24, 32);
glPopMatrix();
// Leaves
glPushMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, LEAF_COLOR);
glTranslated(0, trunkHeight + greenRadius, 0);
glutSolidSphere(greenRadius, 15, 5);
glPopMatrix();
glPopMatrix();
}
};
// A ground class. The ground is a large square on the xz plane with one
// corner at (0, 0, 0) and its opposite at (side, 0, side). The ground
// has a grass texture and a bunch of trees on it.
class Ground {
GLdouble side;
int displayListId;
vector<Tree> trees;
GLuint textureId;
public:
void create(int side, int numberOfTrees) {
this->side = side;
loadOpenGL2DTextureBMP("grass.bmp", &textureId);
displayListId = glGenLists(1);
glNewList(displayListId, GL_COMPILE);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);
glBegin(GL_QUADS);
glNormal3f(0, 1, 0);
glTexCoord2d(0.0, 15.0); glVertex3d(0, 0, side);
glTexCoord2d(15.0, 15.0); glVertex3d(side, 0, side);
glTexCoord2d(15.0, 0.0); glVertex3d(side, 0, 0);
glTexCoord2d(0.0, 0.0); glVertex3d(0, 0, 0);
glEnd();
glDisable(GL_TEXTURE_2D);
glEndList();
for (int i = 0; i < numberOfTrees; i++){
trees.push_back(Tree(0.5, 4, 2.5, rand()%side, rand()%side));
}
}
void draw() {
glCallList(displayListId);
for (int i = 0; i < trees.size(); i++) {
trees[i].draw();
}
}
};
// Globals: a ground and a ship to navigate through it.
Ground ground;
Ship ship(Point(50, 3, 100));
// Reshape callback: construct a camera that perfectly fits the window.
void reshape(GLint w, GLint h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, GLfloat(w) / GLfloat(h), 0.1, 150.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// On idle, just advance the ship and redraw.
void idle() {
ship.fly();
Point eye(ship.getPosition());
Point at(ship.getPosition() + ship.getDirection());
Vector up(ship.getVertical());
glLoadIdentity();
gluLookAt(eye.x, eye.y, eye.z, at.x, at.y, at.z, up.i, up.j, up.k);
glutPostRedisplay();
}
// Draw the scene and swap buffers.
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ground.draw();
glFlush();
glutSwapBuffers();
}
// Speeds up and slows down with up and down arrows; turns on right and left
// arrows.
void navigateShip(int key, int, int) {
const double turnAngle = 0.1;
const double deltaSpeed = 0.2;
switch (key) {
case GLUT_KEY_LEFT: ship.yaw(turnAngle); break;
case GLUT_KEY_RIGHT: ship.yaw(-turnAngle); break;
case GLUT_KEY_UP: ship.setSpeed(ship.getSpeed() + deltaSpeed); break;
case GLUT_KEY_DOWN: ship.setSpeed(ship.getSpeed() - deltaSpeed); break;
}
}
// Non-GLUT initialization that we don't want to clutter main() with.
void myInit() {
glClearColor(0.2, 0.2, 0.2, 1.0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
// glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
// Setup the spotlight. By including the position and direction
// of the spotlight here in myInit(), before we ever call gluLookAt(),
// we ensure the light source moves with the viewer. By positioning
// the light at the origin and pointing it along -z, we make it look
// like the viewer is holding a flashlight.
glEnable(GL_LIGHT1);
glLightfv(GL_LIGHT1, GL_AMBIENT, BLACK);
glLightfv(GL_LIGHT1, GL_DIFFUSE, WHITE);
glLightfv(GL_LIGHT1, GL_POSITION, ORIGIN);
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 128.0);
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 3.0);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0);
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.075);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0);
// Setup fog
glEnable(GL_FOG);
glFogi(GL_FOG_MODE, GL_EXP2);
glFogfv(GL_FOG_COLOR, DARK_GREY);
glFogf(GL_FOG_DENSITY, 0.0125);
glHint(GL_FOG_HINT, GL_DONT_CARE);
glFogf(GL_FOG_START, 50.0);
glFogf(GL_FOG_END, 60.0);
// Setup ground
ground.create(100, 175);
}
// The usual main() for a GLUT application.
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(640, 400);
glutCreateWindow("A Walk in the Forest");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutSpecialFunc(navigateShip);
glutIdleFunc(idle);
myInit();
glutMainLoop();
}
This program makes use of the Geometry and Ship classes from the courseware distribution, as well as the BMPLoader utility written by Jacob Marner.