/*****************************************************************
  bounce.cpp
  by Dave Pape
  3 March 2003

  This example shows movement using a potentially varying velocity
  vector.  The starting value of the velocity is controlled with
  the mouse, as in motion.cpp.  The ball also bounces off of the
  edges of the window, causing its velocity to change.
 
*****************************************************************/
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <dms/dms.h>

void drawEverything(void);
void key(unsigned char k, int x, int y);
void mousebutton(int button, int state, int x, int y);
void mousemotion(int x, int y);
void idle(void);
void launchBall(void);
void checkForBounce(void);


/*************** CODE OF INTEREST ******************************/
/* Variables needed to compute the ball's motion - its starting*/
/* position & velocity, and current position & velocity.       */
/*                                                             */
dms::Vector3 startPosition(0, 0, 0);
dms::Vector3 startVelocity;
dms::Vector3 position;
dms::Vector3 velocity;

dms::OrthoCamera camera(-20, 20, -20, 20);
dms::QuadricObject ball;


int main(int argc, char *argv[])
    {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(512,512);
    glutCreateWindow("example");
    glutDisplayFunc(drawEverything);
    glutKeyboardFunc(key);
    glutMouseFunc(mousebutton);
    glutMotionFunc(mousemotion);
    glutIdleFunc(idle);
    glLineWidth(2);
    glutMainLoop();
    return 0;
    }


void drawEverything(void)
    {
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    
    camera.apply();
    
    glColor3f(1, 1, 1);
    startVelocity.drawLine();
    
    glColor3f(1.0, 0.9, 0.0);
    glTranslatef(position[0], position[1], position[2]);
    ball.draw();
    velocity.drawLine();

    glutSwapBuffers();
    }


/*************** CODE OF INTEREST ******************************/
/* launchBall() sets the current position & velocity to the    */
/* starting position & velocity, to re-start the ball's motion */
/* from that point.                                            */
/*                                                             */
void launchBall(void)
    {
    position = startPosition;
    velocity = startVelocity;
    }


void key(unsigned char k, int x, int y)
    {
    if (k == 27)
        exit(0);
    else if (k == ' ')
        launchBall();
    }



void mousebutton(int button, int state, int x, int y)
    {
    startVelocity[0] = ((float)x / glutGet(GLUT_WINDOW_WIDTH) - 0.5) * 10.0;
    startVelocity[1] = -((float)y / glutGet(GLUT_WINDOW_HEIGHT) - 0.5) * 10.0;
    }


void mousemotion(int x, int y)
    {
    startVelocity[0] = ((float)x / glutGet(GLUT_WINDOW_WIDTH) - 0.5) * 10.0;
    startVelocity[1] = -((float)y / glutGet(GLUT_WINDOW_HEIGHT) - 0.5) * 10.0;
    }



/*************** CODE OF INTEREST ******************************/
/* Compute the ball's new position & velocity.  dms::beginFrame*/
/* is called in order to use dms::deltaTime() for the time-step*/
/* value in the movement.                                      */
/*                                                             */
void idle(void)
    {
    dms::beginFrame();
    position += velocity * dms::deltaTime();
    checkForBounce();
    glutPostRedisplay();
    }


/*************** CODE OF INTEREST ******************************/
/* Check whether the ball has passed any of the edges of the   */
/* window; if so, bounce it by reversing the velocity in the   */
/* corresponding direction.  (The ball must also be moved back */
/* inside the window region, to avoid a possible infinite cycle*/
/* of the ball being stuck in the wall.)                       */
/*                                                             */
void checkForBounce(void)
    {
    if (position[0] > 20.0)
        {
        velocity[0] = -velocity[0];
        position[0] = 20.0 - (position[0] - 20.0);
        }
    if (position[0] < -20.0)
        {
        velocity[0] = -velocity[0];
        position[0] = -20.0 + (-20.0 - position[0]);
        }
    if (position[1] > 20.0)
        {
        velocity[1] = -velocity[1];
        position[1] = 20.0 - (position[1] - 20.0);
        }
    if (position[1] < -20.0)
        {
        velocity[1] = -velocity[1];
        position[1] = -20.0 + (-20.0 - position[1]);
        }
    }
