
/* Copyright (c) Mark J. Kilgard, 1994. */

/**
 * (c) Copyright 1993, Silicon Graphics, Inc.
 * ALL RIGHTS RESERVED 
 * Permission to use, copy, modify, and distribute this software for 
 * any purpose and without fee is hereby granted, provided that the above
 * copyright notice appear in all copies and that both the copyright notice
 * and this permission notice appear in supporting documentation, and that 
 * the name of Silicon Graphics, Inc. not be used in advertising
 * or publicity pertaining to distribution of the software without specific,
 * written prior permission. 
 *
 * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
 * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
 * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
 * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
 * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
 * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
 * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
 * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
 * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
 * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
 * 
 * US Government Users Restricted Rights 
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
 * (c)(1)(ii) of the Rights in Technical Data and Computer Software
 * clause at DFARS 252.227-7013 and/or in similar or successor
 * clauses in the FAR or the DOD or NASA FAR Supplement.
 * Unpublished-- rights reserved under the copyright laws of the
 * United States.  Contractor/manufacturer is Silicon Graphics,
 * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
 *
 * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
 */

//
// Bouncing ball demo. 
//
//
// Original: Brian Paul
// Conversion to GLUT by Mark J. Kilgard 
//

// Modified for use in cs4731 by Mark R. Stevens (February 12, 2000)
// contact: stevensm@cs.wpi.edu with comments / concerns
// 
// Additional Modifications for windows port
//     Paul Tessier
//
// C includes
#include <math.h>
#include <stdlib.h>

// C++ includes
#include <iostream>

// Paul Tessier <phernost@WPI.EDU>: Windows fix 
using namespace std;

// The local includes
#include "minigl.h"
#include "miniglut.h"
#include "stars.h"

// for simplicity
#define COS(X)   cos( (X) * 3.14159/180.0 )
#define SIN(X)   sin( (X) * 3.14159/180.0 )  

//--------------------------------------------------------------------------------
void stars::usage() {

  // tell the user what the keys do to the gears
  cout << "\nStars Usage:\n";
  cout << "\tKeys:\n";
  cout << "\t\ts\t\tAdvance the stars\n";
  cout << "\t\tescape\t\texit\n";
  cout << "\tMouse:\n";
  cout << "\t\tNone\n";
}
//--------------------------------------------------------------------------------

//--------------------------------------------------------------------------------
void stars::NewStar(int n, int d) {

  // there are two types of stars
  starrecs[n].x[0] = (float) (rand() % MAXPOS - MAXPOS / 2);
  starrecs[n].y[0] = (float) (rand() % MAXPOS - MAXPOS / 2);
  starrecs[n].z[0] = (float) (rand() % MAXPOS + d);
  starrecs[n].x[1] = starrecs[n].x[0];
  starrecs[n].y[1] = starrecs[n].y[0];
  starrecs[n].z[1] = starrecs[n].z[0];
  starrecs[n].offsetX = 0.0;
  starrecs[n].offsetY = 0.0;
}
//--------------------------------------------------------------------------------

//--------------------------------------------------------------------------------
void stars::MoveStars() {

  // go through and advance all of the stars
  float offset = 60.0;
  for (int n = 0; n < starCount; n++) {
    starrecs[n].x[1]      = starrecs[n].x[0];
    starrecs[n].y[1]      = starrecs[n].y[0];
    starrecs[n].z[1]      = starrecs[n].z[0];
    starrecs[n].x[0]     += starrecs[n].offsetX;
    starrecs[n].y[0]     += starrecs[n].offsetY;
    starrecs[n].z[0]     -= offset;
  }
}
//--------------------------------------------------------------------------------

//--------------------------------------------------------------------------------
bool stars::StarPoint(int n) {
  
  // compute the point in the window
  float x0 = starrecs[n].x[0] * windW / starrecs[n].z[0];
  float y0 = starrecs[n].y[0] * windH / starrecs[n].z[0];

  // offset to pixel coordinates
  x0 += windW / 2.0;
  y0 += windH / 2.0;

  // check if still on image
  return (x0 >= 0.0 && x0 < windW && y0 >= 0.0 && y0 < windH);

}
//--------------------------------------------------------------------------------

//--------------------------------------------------------------------------------
void stars::UpdateStars() {

  // check to see if the stars go off the window and replace with new stars
  for (int n = 0; n < starCount; n++) {
    if (! StarPoint(n)) NewStar(n, MAXPOS);
  }
}
//--------------------------------------------------------------------------------

//--------------------------------------------------------------------------------
void stars::init(minigl &mgl, miniglut &mglut) {

  // The timings 
  T0 = 0;
  Frames = 0;

  // set up all of the defaults
  MAXSTARS  = 400;
  MAXPOS    = 10000;
  MAXANGLES = 6000;

  // setup the star count
  starCount = MAXSTARS / 2;

  // allocate the stars
  starrecs = new starRec[400];

  // seed the random number generator with a constant (all star
  // patterns will look the same).
  srand(1234567890);

  // allocate the stars
  for (int n = 0; n < MAXSTARS; n++) NewStar(n, 100);

  // set the clear color
  mgl.mglClearColor(0.0, 0.0, 0.0, 0.0);

  // make sure everything is ready for rendering
  MoveStars();
  UpdateStars();    

}
//--------------------------------------------------------------------------------

//--------------------------------------------------------------------------------
void stars::reshape(minigl &mgl, miniglut &mglut, int width, int height) {
  
  // store the dimensions
  windW = width;
  windH = height;
  
  // set the camera matrix
  mgl.mglMatrixMode(minigl::MGL_PROJECTION);
  mgl.mglLoadIdentity();
  mgl.mglOrtho(-0.5, windW + 0.5, -0.5, windH + 0.5, -1, 1);
  mgl.mglMatrixMode(minigl::MGL_MODELVIEW);

  // set the viewport
  mgl.mglViewport(0, 0, windW, windH);

}
//--------------------------------------------------------------------------------

//--------------------------------------------------------------------------------
void stars::key(minigl &mgl, miniglut &mglut, unsigned char k, int x, int y) {

  // deal with the key
  switch (k) {
  case 's':
    MoveStars();
    UpdateStars();    
    break;
  case 27:
    exit(0);
  }

  // update the display
  mglut.mglutPostRedisplay();  


}
//--------------------------------------------------------------------------------
void stars::mouse (minigl &mgl, miniglut &mglut, int button, int state, int x, int y){

	mglut.mglutPostRedisplay( );
}

//--------------------------------------------------------------------------------
void stars::draw(minigl &mgl, miniglut &mglut) {

  // clear the screen
  mgl.mglClear(minigl::MGL_COLOR_BUFFER_BIT);

  // draw the stars
  for (int n = 0; n < starCount; n++) {
    
    // update the point
    float x0 = starrecs[n].x[0] * windW / starrecs[n].z[0] + windW / 2.0;;
    float y0 = starrecs[n].y[0] * windH / starrecs[n].z[0] + windH / 2.0;
    
    // draw as a gl point
    if (x0 >= 0.0 && x0 < windW && y0 >= 0.0 && y0 < windH) {
      mgl.mglColor3f(1.0, 1.0, 1.0);
      mgl.mglBegin(minigl::MGL_POINTS);
      mgl.mglVertex3f(x0, y0, 0);
      mgl.mglEnd();
    }
  }

  // swap the buffers
  mglut.mglutSwapBuffers();

  // count frames and output the frame rate
  Frames++;
  int t = mglut.mglutGet(miniglut::MGLUT_ELAPSED_TIME);
  if (t - T0 >= 5000) {
    float seconds = (t - T0) / 1000.0;
    float fps = Frames / seconds;
    cout << "\t" << Frames << " frames in ";
    cout << seconds << " seconds = " << fps << " fps\n";
    T0 = t;
    Frames = 0;
  }

}
//--------------------------------------------------------------------------------

//--------------------------------------------------------------------------------
void stars::special(minigl &mgl, miniglut &mglut, int k, int x, int y) {

}
//--------------------------------------------------------------------------------
