// Mike Gordon

/**************** PVM version of this piece of code ***************************/


#include <stdio.h>
#include <iostream.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "glaux.h"
#include "/usr/pvm3/include/pvm3.h"

#include "/home/atlas2/mgordon/src/glfuncwindow.cpp"

#define SLAVENAME "scrow2"

#define MAXNUMCOL 700 //maximum pixl size of row (number of coloums)

#define MAXNUMROW 700 //maximum pixl size of coloum (number of rows)
#define MAXTASKS MAXNUMROW //max tasks equal to max pixls in coloum (num rows)

/******************************************************************************/
/****************** Drawing (GL) functions ************************************/
/******************************************************************************/

void Reshape(int,int);

void glFuncWindow::makewindow()
{
  set_pixl_width( pixlx() );
  set_pixl_height( pixly() );
  auxInitDisplayMode( AUX_RGBA );
  auxInitPosition( pixlleft, pixltop, pixlwidth, pixlheight );
  if ( auxInitWindow(window_name) == GL_FALSE )
  {
    auxQuit();
  }
  glClearColor( bg_red, bg_green, bg_blue, 1.0 );
  glShadeModel( GL_FLAT );
  auxExposeFunc(Reshape);
  auxReshapeFunc(Reshape); 
}

void Reshape( int width, int height )  // Essential Magic again!
{
   glViewport(0, 0, (GLint)width, (GLint)height);
   win.set_pixl_width( width );
   win.set_pixl_height( height );
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
   glMatrixMode(GL_MODELVIEW);
}

void drawset();

void display()
{
  glClear( GL_COLOR_BUFFER_BIT );

  drawset();

  glFlush();
  auxSwapBuffers();
}

/******************************************************************************/
/********************** end of drawing (GL) functions *************************/
/******************************************************************************/

/******************************************************************************/
/******************** Key functions *******************************************/
/******************************************************************************/

#include "/home/atlas2/mgordon/src/keyfuncs.cpp"

/******************************************************************************/

void key_funcs()
{
  auxKeyFunc(AUX_UP,scroll_up);
  auxKeyFunc(AUX_DOWN,scroll_down);
  auxKeyFunc(AUX_LEFT,scroll_left);
  auxKeyFunc(AUX_RIGHT,scroll_right); 
  auxKeyFunc(AUX_I,zoom_in);
  auxKeyFunc(AUX_i,zoom_in);
  auxKeyFunc(AUX_O,zoom_out);
  auxKeyFunc(AUX_o,zoom_out);
  auxKeyFunc(AUX_Z,zoom_other);
  auxKeyFunc(AUX_z,zoom_other);
}

/******************************************************************************/
/*************************** end of key functions *****************************/
/******************************************************************************/

/******************************************************************************/
/**************** Missile struct***********************************************/
/******************************************************************************/

struct missiledata
{
  double dist;
  double range;
}Missile;

/******************************************************************************/
/**************** end of Missile struct ***************************************/
/******************************************************************************/

/******************************************************************************/
/***************** drawmissile routine ****************************************/
/******************************************************************************/

#define COLORCONST 500 // a number used to generate color spectrum

void getcolorval(int j)
// sets color based on time to hit, the greener the color, the quicker the hit
{
  double r,g,b;
  double i = (double)j;
  r = i / COLORCONST;
  if (r > 1)
  {
    r = 1;
  }
  g = 1;
  b = 2*i/COLORCONST;
  if (b > 1)
  {
    b = 1;
  }
  win.set_fg_color(r,g,b);
}

void drawset()  // The Drawing Routine
{
  // This is now the main pvm routine 

  // vars
  int nproc; // the number of slave processes
  int ncols; // the number of coloums
  int numt; // the number of tasks, should equal nproc
  int msgtype; // the type of message
  int iter; // the number of iterations to hit ( 0 for no hit )
  int i,j,x,y; // loop controls

  // arrays
  int tids[MAXTASKS];   /*slave task ids*/
  int result[MAXNUMCOL];

  // assign vars from missle struct to float vars
  float dist = Missile.dist;
  float range = Missile.range;

  /* set number of slaves to start */
  /* start one for each row (the height of window) */
  nproc = win.pixlheight;

  /* set number of points to calculate in each row (num of coloums) */
  ncols = win.pixlwidth;

  /* start slave tasks */
  numt = pvm_spawn(SLAVENAME,(char**)0,0,"",nproc,tids);
  if (numt < nproc)
  {
    for( i=0; i<numt; i++)
    {
      pvm_kill(tids[i]);
    }
    pvm_exit();
    exit(1);
  }

  // set vars to pass win size (user) data
  float xdist = win.distx();
  float ydist = win.disty();
  float minx = win.bottom_left.getX();
  float miny = win.bottom_left.getY();

/* brodcast data */
  pvm_initsend(PvmDataDefault);

  pvm_pkint(&nproc,1,1); // nproc also equal to number of rows
  pvm_pkint(&ncols,1,1); // size of result array
  pvm_pkint(tids,nproc,1); // tid array
  pvm_pkfloat(&dist,1,1); // distance
  pvm_pkfloat(&range,1,1); // range
  pvm_pkfloat(&xdist,1,1);
  pvm_pkfloat(&minx,1,1);
  pvm_pkfloat(&ydist,1,1);
  pvm_pkfloat(&miny,1,1); 

  msgtype=0;

  pvm_mcast(tids,nproc,msgtype);

/* Wait for results */
  msgtype=5; // message type waiting for

  for (i=0;i<nproc;i++) // for each slave task (each row)
  {
    pvm_recv(-1,msgtype);
    pvm_upkint(&y,1,1); // get row number
    pvm_upkint(result,ncols,1); // get result array

    // this line for debugging purposes
    cout<<"row "<<y<<" has reported"<<endl;
      
    for( x=0; x<ncols; x++) // for each pixl in row
    {
      iter=result[x];
      glBegin( GL_POINTS );
        if ( iter > 0 )
        {
          getcolorval(iter);
        }
        else
        {
          win.set_fg_color( 0.0, 0.0, 0.0 );
        }
        glColor3f( win.fg_red,win.fg_green,win.fg_blue );
        glVertex3f( win.scalewidth(x), win.scaleheight(y), 0.0 );
      glEnd();
    }
  }
} 

/******************************************************************************/
/************************** end of drawmissile routine ************************/
/******************************************************************************/

/******************************************************************************/
/******************* Main function ********************************************/
/******************************************************************************/

void main()
{
  int winsize,v,a;

  cout<<"enter distance to target (in units): ";
  cin>>Missile.dist;
  cout<<"enter range (in units): ";
  cin>>Missile.range;

  cout<<"enter window max pixl size: ";
  cin>>winsize;

  win.set_max_pixl(winsize);

  // start at velocity zero, angle zero
  win.bottom_left.assign( 0.0, 0.0 );

  cout<<"enter max velocity (in tens): ";
  cin>>v;
  cout<<"enter max angle: ";
  cin>>a;
  // end at velocity v, angle a
  win.top_right.assign( (double)v , (double)a );

  win.set_name("Missile hit set");

  win.makewindow();

  key_funcs();
  
  auxMainLoop(display);
  
  pvm_exit();
}

/******************************************************************************/
/****************************** end of main ***********************************/
/******************************************************************************/
