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;
}

Bounce


This first lab was something like a big mountain for me to climb because I have no programming experience in OpenGL even though it was just C++. So, part of the time I was trying to conquer the difficulty of being unable to write a decent program. Oh well...it was an interesting venture though and it really felt like a million bucks when you actually your program and it works!


The task is for you to write a program called bounce that allows the user to induce circles into the console by clicking with the mouse inside the console. With the operation console, there should be another console that displays some information about the program and that indicates if the maximum number of circles has been reached. In addition, the circles shoud be able to bounce off the sides of the operation window even when the window has been shrunk, all the circles should be conpletely visible and none should be hidden. When the window has been enlarged, the circles should take up the newly given space and contiue with the bounce. The picture below would elaborate further and the next post contains the complete source code for the program that has bouncing fans. So, you would have to attempt at bounding circles.