/*

 *  main.cpp

 *  CompFormApp

 *

 */

 

#include <OpenGL/gl.h> //openGL lib

#include <GLUT/glut.h> //glut lib

 

#include <stdio.h> //input output lib

#include <stdlib.h> //standard lib

#include <math.h> //math lib

#include <time.h>//time lib

 

#include "shape.h"//shape includes vec2d

#include "grass.h"

 

int  windowW = 1440; //window Width

int  windowH = 900; //window Height

float     mouseX = windowW/2; //new variable, mouseX

float     mouseY = windowH/2; //mouseY

float     pmouseX=windowW/2;

float     pmouseY=windowH/2;

 

#define PI 3.14159265358979 //variable for pi

 

// stuff i use all the time

 

float radians(float n){

      n=n/360*PI*2;

      return n;

}

 

float dist(float x, float y, float xx,  float yy){

      float distance;

      distance=sqrt((xx-x)*(xx-x)+(yy-y)*(yy-y));

      return distance;

}

float constrain(float c, float a, float b){

      if (c<a) c=a;

      if (c>b) c=b;

      else c=c;

      return c;

}

 

Vec2d LERP(Vec2d a, Vec2d b, float p){  //(vec, vec, percentage)

      Vec2d c;

      c=a*(1.0-p)+b*p;

      return c;

}

 

void drawBezier(Vec2d A, Vec2d B, Vec2d C, Vec2d D){

      glBegin(GL_LINE_STRIP);

      for (float p=0;p<1.0;p=p+.1){

            float b=1.0-p;

            Vec2d y=A*b*b*b+B*b*b*p+C*p*p*b+D*p*p*p;

            glVertex2f(y.x,y.y);

      }

      glEnd();

}

 

float min (float a, float b){

      if (a<b)

            return a;

      else

            return b;

     

}

float max (float a, float b){

      if (a>b)

            return a;

      else

            return b;

}

 

int numPoints=0;

Vec2d pointList[1000];

 

//grass

# define nBlades 5000

 

int randomX[nBlades];

int rows[nBlades];

int randomHeight[nBlades];

float randomWindVelocity[nBlades];

float t[nBlades];

float distance[nBlades];

float angle[nBlades];

float sway[nBlades];

float shiftX[nBlades] ;

 

 

void drawBlade( float B1x, float B2x, float B3x, float B4x, int i, int tilt) // variables top x, top-middle x, bottom-middle x, bottom x, i used to control blade arc

{

     

      float thickness=randomHeight[i]/5.0;//rows[i]*.4;

     

      for (int k = 0; k <= thickness; k++ ) { // draw k bezier curves

           

            Vec2d BezierCurveA(B1x, randomHeight[i]+rows[i]); // top of grass blade; x is random, randomY used for variation in height

            Vec2d BezierCurveB(B2x+(k*0.4),randomHeight[i]*.75+rows[i]); // middle of glass blade, x is random, k widens blade

            Vec2d BezierCurveC(B3x+(k*0.45),randomHeight[i]*.25+rows[i]); // middle of glass blade, x is random, k widens blade

            Vec2d BezierCurveD(B4x+(k*0.3),rows[i]); // bottom of grass blade; x is random, y is fixed, k widens blade towards base

           

            glBegin (GL_LINE_STRIP);

            for (float p=0; p<=1.0; p+=.125) // creates individual bezier curve

            {          

 

                  float b = 1.0-p;

                  Vec2d CompleteCurve = BezierCurveA*(b*b*b) + BezierCurveB*(3*p*b*b) + BezierCurveC*(3*p*p*b) + BezierCurveD*(p*p*p); // lerp function  

                 

                  float GradientY = b*thickness/20; // gradient along the y axis

                  float nTilt=tilt/100.0*b;

 

                  if (k < thickness/2) {

                        glColor4f(0.04*k*GradientY+nTilt,.2+0.08*k*GradientY+nTilt,0.008*k*GradientY,.7); // k controls side gradient hue for blade, y controls downward gradient

                  }

                  else {

                        glColor4f(0.04*(thickness-k)*GradientY+nTilt,.2+0.08*(thickness-k)*GradientY+nTilt,0.008*(thickness-k)*GradientY,.7); // k controls an opposite side gradient hue for blade, y controls downward gradient

                  }

                                   

                  glVertex2f (CompleteCurve.x, CompleteCurve.y-75); // offset for grass

            }

           

            glEnd();

           

      }

     

}

 

void drawField(float x, float y, int i){

      angle[i]=atan2(mouseX-x,mouseY-y); //angle to mouse

      distance[i]=dist(x,y,mouseX,mouseY); //distance to mouse

      float tilt=sin(radians(t[i]))*randomHeight[i]/5;//sway distance

            Vec2d mouse=Vec2d(mouseX,mouseY);

           

            float brushSize=dist(pmouseX,pmouseY,mouseX,mouseY)+50;

           

                              if( distance[i]<brushSize){

                                    sway[i]=randomWindVelocity[i]/distance[i]*9*(constrain(angle[i],-2,2));//random velocity * direction in relation to mouse

                              }

                              t[i]=t[i]+sway[i]; //sway speed

                             

                              //decay

                              if (t[i]>.1|| t[i]<-.1){

                                    t[i]=t[i]*.999;

                              }

                             

 

                              drawBlade(randomX[i]+tilt,randomX[i],randomX[i],randomX[i],i,tilt); // variable i used as blade counter and to vary bezier arcs as blade accumulate

}

 

shape* myShape;

void displayFunc ( void )

{

      //first line in displayFunc

      glClearColor(.07,.2,.05,0);//background color

     

      glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); //clears screen, color and depth, | binary OR

     

      //place your drawing code here

     

                  for (int i = 0; i < nBlades; i++) {

                        drawField(randomX[i],rows[i],i);

                  }

           

            //myShape->draw(); //-> for pointers

           

           

            glutPostRedisplay(); //repeat, redraw

            glutSwapBuffers(); //swaps offscreen buffer, offscreen to onscreen

}

 

void reshapeFunc ( int w, int h )

{

      //windowW = w;  //window width

      //windowH = h; //window height

     

      windowW = 1440;

      windowH = 900;

     

      //camera setup

      glViewport( 0, 0, w, h ); //camera view, drawing region (x,y,x,y)

      glMatrixMode( GL_PROJECTION );//camera operations matrix

            glLoadIdentity();//load projection

                  gluOrtho2D( 0,w,0,h ); //set camera to ortho, 2d

                  glMatrixMode( GL_MODELVIEW );//drawing space matrix

                        glLoadIdentity();//load model space

}

 

 

//mouse functions

void mouseDownFunc ( int button, int state, int x, int y )

{

      mouseX = x;

      mouseY = windowH - y;//y=0 at bottom of screen

                                     //printf("%d %d\n",x,y);//print mouse x,y loc        

}

 

void mouseMoveFunc ( int x, int y )//if mouse is moved

{     pmouseX=mouseX;

      pmouseY=mouseY;

      mouseX = x;

      mouseY = windowH - y;

}

 

void mouseDragFunc ( int x, int y )//if mouse is dragged

{

      mouseX = x;

      mouseY = windowH - y;

      if(numPoints<1000){

            pointList[numPoints].x=mouseX;

            pointList[numPoints].y=mouseY;

            numPoints++;

      }

}

 

//keyboard functions

void keyboardFunc ( unsigned char key, int x, int y )

{

 

}

 

void arrowKeyFunc ( int a_keys, int x, int y )

{

}

 

 

void init ( GLvoid )

{

      glShadeModel( GL_SMOOTH ); // flat or smooth shading

      glClearColor( 1.0, 1.0, 1.0, 1.0 ); //specify clear values for the color buffers

      glEnable ( GL_COLOR_MATERIAL );//enable server side color material tracking

            glEnable( GL_BLEND );//enable server side blend of rgb values

                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//specify pixel rgb math

                       

                       

                        //grass init()

                        int i=0;

                        for (int row = 900/*windowH*/+50; row>0; row--) {

                              for (int col=0;col<nBlades/1440/*windowW*/;col++){

                                   

                                    randomX[i] = (rand()% 1440/*windowW*/); //top

                 

                                    rows[i] = row;//rand()%windowH;

                              randomHeight[i]=rand() % 60 + 90;//random height from 30 to 80

                              randomWindVelocity[i]=rand() % 15 + 1; //random velocity from 2 to 20

                             

                              i++;

                             

                              }

                        }

                       

}

 

 

//main function at bottom

int main ( int argc, char** argv )

{

           

      glutInit( &argc, argv ); //init GLUT library (& take the address of)

     

      glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE ); //display mode

      glutInitWindowSize( windowW, windowH ); //initialization of window using window sizes

      glutCreateWindow( "CompFormApp" ); // create a window with name

     

      //callback functions

      glutDisplayFunc( displayFunc ); //draws window 30fps

      glutReshapeFunc( reshapeFunc ); //resizing window

      glutMouseFunc( mouseDownFunc ); //mousepressed

      glutMotionFunc( mouseDragFunc ); //mousedragged

      glutPassiveMotionFunc( mouseMoveFunc ); //mouseMoved

      glutKeyboardFunc( keyboardFunc ); //keyPressed

      glutSpecialFunc( arrowKeyFunc ); //arrow,shift,etc. keyPressed

     

      init();//call void init func

            myShape=new shape();

            myShape->addPoint(Vec2d(100,100));

            myShape->addPoint(Vec2d(400,400));

            myShape->addPoint(Vec2d(100,300));

 

            glutFullScreen();//fullscreen

            glutSetCursor( GLUT_CURSOR_NONE );//hides mouse NOT WORKING

            glutMainLoop( );//main event loop, calls custom functions when even occurs

                 

                  return 0; //returns main=0

}