Wednesday, December 10, 2008

Bounce Source Code

#include
#include
#include
#ifdef __APPLE__
#include
#else
#include
#endif

/////////////////////////////////////////////////////////////////////////////
// CONSTANTS
/////////////////////////////////////////////////////////////////////////////

#define PI 3.1415926535897932384626433832795
#define MAX_NUM_OF_DISCS 100 // Limit the number of discs.
#define MAX_RADIUS 40.0 // Maximum radius of disc.
#define NUM_OF_SIDES 18 // Number of polygon sides to approximate a disc.
#define MAX_X_SPEED 20.0 // Maximum speed of disc in X direction.
#define MAX_Y_SPEED 20.0 // Maximum speed of disc in Y direction.
#define DESIRED_FPS 30 // Approximate desired number of frames per second.

/////////////////////////////////////////////////////////////////////////////
// GLOBAL VARIABLES
/////////////////////////////////////////////////////////////////////////////

typedef struct discType
{
double pos[2]; // The X and Y coordinates of the center of the disc.
double speed[2]; // The velocity of the disc in X and Y directions. Can be negative.
double radius; // Radius of the disc.
unsigned char color[3]; // R, G, B colors of the disc.
} discType;

int numDiscs = 0; // Number of discs that have been added.
discType disc[ MAX_NUM_OF_DISCS ]; // Array for storing discs.
bool drawWireframe = false; // Draw polygons in wireframe if true, otherwise
// otherwise polygons are filled.
int winWidth = 600; // Window width in pixels.
int winHeight = 600; // Window height in pixels.

/////////////////////////////////////////////////////////////////////////////
// Draw the disc in its color using GL_TRIANGLE_FAN.
/////////////////////////////////////////////////////////////////////////////

void DrawDisc( const discType *d )
{
int i;
int sections = 20; //number of triangles to use to estimate a circle
// (a higher number yields a more perfect circle)
GLfloat twoPi = 2.0f * PI;
glBegin(GL_TRIANGLE_FAN);
glVertex2f(d->pos[0], d->pos[1]);//define the fixed vertex for the fan
glColor3ub(d->color[0], d->color[1], d->color[2]);//colour the circle
for(i = 0; i <= sections;i++) { // make $section number of circles
//define the other two vertices for each triangle in the fan
glVertex2f(d->pos[0] + d->radius * cos(i * twoPi / sections),
d->pos[1] + d->radius * sin(i * twoPi / sections));
glVertex2f(d->pos[0] + d->radius,
d->pos[1] + d->radius);
}
glEnd();
}

/////////////////////////////////////////////////////////////////////////////
// The display callback function.
/////////////////////////////////////////////////////////////////////////////

void MyDisplay( void )
{
glClear( GL_COLOR_BUFFER_BIT );
if ( drawWireframe )
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
else
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
for ( int i = 0; i < numDiscs; i++ ) DrawDisc( &disc[i] );
glutSwapBuffers();
}

/////////////////////////////////////////////////////////////////////////////
// The mouse callback function.
// If mouse left button is pressed, a new disc is created with its center
// at the mouse cursor position. The new disc is assigned the followings:
// (1) a random radius less than or equal to MAX_RADIUS,
// (2) a random speed in X direction in the range -MAX_X_SPEED to MAX_X_SPEED.
// (3) a random speed in Y direction in the range -MAX_Y_SPEED to MAX_Y_SPEED.
// (4) R, G, B color, each ranges from 0 to 255.
/////////////////////////////////////////////////////////////////////////////

void MyMouse( int btn, int state, int x, int y )
{
if ( btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
{
if ( numDiscs >= MAX_NUM_OF_DISCS )
printf( "Already reached maximum number of discs.\n" );
else
{
//defining the position of the disc at mouse click
disc[numDiscs].pos[0] = x;//x-coordinate of vertex
disc[numDiscs].pos[1] = winHeight - 1 - y;//y-coordinate of vertex
//generate random colours for the discs
disc[numDiscs].color[0] = (int)(rand() % 256);//R-value
disc[numDiscs].color[1] = (int)(rand() % 256);//G-value
disc[numDiscs].color[2] = (int)(rand() % 256);//B-value
//generate random size and speed of the discs
disc[numDiscs].radius = rand() % (int)MAX_RADIUS;
disc[numDiscs].speed[0] = rand() % (int)MAX_X_SPEED;//x-coordinate speed
disc[numDiscs].speed[1] = rand() % (int)MAX_Y_SPEED;//y-coordinate speed
numDiscs++;
glutPostRedisplay();
}
}
}

/////////////////////////////////////////////////////////////////////////////
// The reshape callback function.
// It also sets up the viewing.
/////////////////////////////////////////////////////////////////////////////

void MyReshape( int w, int h )
{
winWidth = w;
winHeight = h;
glViewport( 0, 0, w, h );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();//for projection
gluOrtho2D( 0, w - 1, 0, h - 1);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();//to recreate viewport
}

/////////////////////////////////////////////////////////////////////////////
// The keyboard callback function.
/////////////////////////////////////////////////////////////////////////////

void MyKeyboard( unsigned char key, int x, int y )
{
switch ( key )
{
// Quit program.
case 'q':
case 'Q': exit(0);
break;
// Toggle wireframe or filled polygons.
case 'w':
case 'W': drawWireframe = !drawWireframe;
glutPostRedisplay();
break;
// Reset and erase all discs.
case 'r':
case 'R': numDiscs = 0;
glutPostRedisplay();
break;
}
}

/////////////////////////////////////////////////////////////////////////////
// Updates the positions of all the discs.
//
// Increments the position of each disc by its speed in each of the
// X and Y directions. Note that the speeds can be negative.
// At its new position, if the disc is entirely or partially outside the
// left window boundary, then shift it right so that it is inside the
// window and just touches the left window boundary. Its speed in the X
// direction must now be reversed (negated). Similar approach is
// applied for the cases of the right, top, and bottom window boundaries.
/////////////////////////////////////////////////////////////////////////////

void UpdateAllDiscPos( int )
{
for ( int i = 0; i < numDiscs; i++ )
{
//setting the right boundary bounce
if(disc[i].pos[0] + disc[i].radius >= winWidth){
disc[i].speed[0] = -disc[i].speed[0];
//setting the right boundary reshape
disc[i].pos[0] = winWidth - disc[i].radius;
}
//setting the left boundary bounce
if(disc[i].pos[0] - disc[i].radius < 0){
disc[i].speed[0] = -disc[i].speed[0];
//setting the left boundary reshape
disc[i].pos[0] = disc[i].radius;
}
//setting the bottom boundary bounce
if(disc[i].pos[1] + disc[i].radius >= winHeight){
disc[i].speed[1] = -disc[i].speed[1];
//setting the bottom boundary reshape
disc[i].pos[1] = winHeight - disc[i].radius;
}
//setting the top boundary bounce
if(disc[i].pos[1] - disc[i].radius < 0){
disc[i].speed[1] = -disc[i].speed[1];
//setting the top boundary reshape
disc[i].pos[1] = disc[i].radius;
}
//generating the new position
disc[i].pos[0] = disc[i].pos[0] + disc[i].speed[0];
disc[i].pos[1] = disc[i].pos[1] + disc[i].speed[1];
}
glutPostRedisplay();
glutTimerFunc(1000.00/DESIRED_FPS, UpdateAllDiscPos , 0);
}

/////////////////////////////////////////////////////////////////////////////
// The init function.
// It initializes some OpenGL states.
/////////////////////////////////////////////////////////////////////////////

void MyInit( void )
{
glClearColor( 0.0, 0.0, 0.0, 1.0 ); // Black background color.
glShadeModel( GL_FLAT );
}

/////////////////////////////////////////////////////////////////////////////
// The main function.
/////////////////////////////////////////////////////////////////////////////

int main( int argc, char** argv )
{
glutInit( &argc, argv );
glutInitDisplayMode ( GLUT_RGB GLUT_DOUBLE);
glutInitWindowSize( winWidth, winHeight );
glutCreateWindow( "Bounce" );
MyInit();
// Register the callback functions.
glutDisplayFunc( MyDisplay );
glutReshapeFunc( MyReshape );
glutMouseFunc( MyMouse );
glutKeyboardFunc( MyKeyboard );
glutTimerFunc(1000.00/DESIRED_FPS, UpdateAllDiscPos , 0);
// Display user instructions in console window.
printf( "Click LEFT MOUSE BUTTON in window to add new disc.\n" );
printf( "Press 'w' to toggle wireframe.\n" );
printf( "Press 'r' to erase all discs.\n" );
printf( "Press 'q' to quit.\n\n" );
// Enter GLUT event loop.
glutMainLoop();
return 0;
}

No comments: