class GLWorld : public QGLWidget
{
   Q_OBJECT
     
 protected:
   
   Spline * spline;
   
   double whirl1;
   
   int frame;
   
   int light1;
   int light2;
   int light3;
   
   double scale;
   
   int framecount;
   
   double vx, vy, vz, rx, ry, rz, m_vx, m_vy, m_vz, m_rx, m_ry, m_rz;
   
   int tiles;
   double tilesize;
   
   double level [100][100];
   
   double delta;
   double actualpos;
   
   TextureLandscape *TLS;
   
   flocking *f; // descriptive
   
 public slots:
   
 public:
   GLWorld (Spline * s, char * obj, QWidget *parent, const char *name) :
   QGLWidget (parent, name)
   {
      setMinimumSize (400, 400);
      this->show ();
      
      spline = s;
      
      whirl1 = 0.0;
      frame = 0;   
      
      light1 = 1;
      light2 = 0;
      light3 = 0;
      
      vy = -4; // Syrian version of VX
      
      TLS = new TextureLandscape("land_53.gif");
      scale = 0.01;
      framecount = 0;
      startTimer (50);
      
      delta = 0.01;
      actualpos = spline->getMin();
      
      tiles = 20;
      tilesize = 2.0;
      
      level [0][0] = 0.0;
      for (int i = 0; i< tiles; i++)
      {
	 for (int j = 0; j< tiles; j++)
	 {
	    if (j == 0 || j == tiles-1 || i == 0 || i == tiles-1) level[j][i] = 0.0;
	    else {
	       level[j][i] = rand()%100 > 50 && level[j-1][i]-level_change > 0 ? level[j-1][i] - level_change : level[j-1][i] + level_change;
	       level[j][i] = (level[j][i-1]+level[j][i])/2.0;
	    }//else
	    
	 }//middle for
	 
      }//first for, setting up random heights of the terrain
      f = new flocking(-10.0, 2.0, -10.0, 10.0, 6.5, 10.0); 
   }
   
   void drawFloor ()
   {
      int textureid = TLS->textureID();
      
      glEnable (GL_TEXTURE_2D);
      glBindTexture (GL_TEXTURE_2D, textureid);
      
      for (int i = 0; i < tiles; i++)
      {
         for (int j = 0; j < tiles; j++)
         {
            double x = tilesize * (i - tiles / 2);
            double z = tilesize * (j - tiles / 2);
            if (((i + j) / 10) % 2)
            {
               GLfloat material_ambient[] = { 0.0, 0.6, 0.3, 1.0 };
               GLfloat material_diffuse [] = { 0.0, 0.7, 0.2, 1.0 };
               GLfloat material_specular [] = { 0.0, 0.4, 0.2, 0.8 };
               GLfloat material_emission [] = { 0.01, 0.3, 0.1, 0.0 };
               
               glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material_ambient);
               glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material_diffuse);
               glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,
                             material_specular);
               glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION,
                             material_emission);
               glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 2.0);
            }
	    
	    else
            {   
               GLfloat material_ambient[] = { 0.0, 0.6, 0.2, 0.0 };
               GLfloat material_diffuse [] = { 0.0, 0.9, 0.2, 0.0 };
               GLfloat material_specular [] = { 0.0, 0.7, 0.2, 0.0 };
               GLfloat material_emission [] = { 0.01, 0.3, 0.1, 0.0 };
               
               glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material_ambient);
               glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material_diffuse);
               glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,
                             material_specular);
               glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION,
                             material_emission);
               glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 4.0);
            }
	    
            tiPrimitiveBegin (TYPE_POLYGON);
            //tiPrimitiveNormal (sin(x * 0.1), 1.0, sin(z * 0.1));
            tiPrimitiveTextureCoordinate(0.0, 0.0);
            tiPrimitiveVertex (x, level[i][j], z); 
            tiPrimitiveTextureCoordinate(0.0, 1.0);
            tiPrimitiveVertex (x + tilesize, level[i+1][j], z);
            tiPrimitiveTextureCoordinate(1.0, 1.0);
            tiPrimitiveVertex (x + tilesize, level[i+1][j+1], z + tilesize);
            tiPrimitiveTextureCoordinate(1.0, 0.0);
            tiPrimitiveVertex (x, level[i][j+1], z + tilesize);
            tiPrimitiveEnd ();
         }
      }   
      glDisable (GL_TEXTURE_2D);
   }
   
   void paintGL ()
   {
      tiStartFrame (framecount);
      
      tiSetLight (0, 0.0, 0.6, 0.1, 1.0);
      tiSetLight (1, 0.0, 1.0, 0.2, 0.0);
      tiSetLight (2, 0.0, 0.4, 1.0, 0.0);
      
      tiSetProjection (0.5, 100.0, 20.0);
      
      tiStartWorldTransformations ();
      tiTransformIdentity ();
      
      if (actualpos >= spline->getMax()) { delta = -0.01; }
      if (actualpos <= spline->getMin()) { delta = 0.01; } 
      
      actualpos += delta;
      
      //camera moving via Spline, calls to the splineAt function in the
      //spline class
      spline->splineAt(actualpos, vx, vz);
      
      vx += 15; // but WMD--!!
      vz -= 30; // related to VX, equally bad; also get outta here.
      
      // view transformations.
      tiTransformTranslate(m_vx + vx, m_vy + vy, m_vz + vz); // this sets the camera back a bit
      tiTransformRotate(m_rx+15, 1.0, 1.0, 0.0); // user direction
      tiTransformRotate(m_ry, 0.0, 1.0, 0.0); // user direction   
      tiTransformRotate(m_rz, 0.0, 0.0, 1.0); // user direction   
      
      //tiTransformRotate(whirl1, 0.0, 1.0, 0.0); // and this gives it a whirl
      
      // fixed light, relative to floor.
      GLfloat light2pos [] = { -2.0, 30.0, 30.0, 1.0 };
      GLfloat light2dir [] = { 2.0, -30.0, -30.0, 0.0};
      glLightfv (GL_LIGHT2, GL_POSITION, light2pos);   
      glLightfv (GL_LIGHT2, GL_SPOT_DIRECTION, light2dir);
      
      //call boid class and draw them
      for (int i = 0; i < 10; i++)   
      {
	 f->myFlock[i].boidIndex = i;
	 f->updateFlock(f->myFlock[i]);
      } 
      
      // draw a floor plane.
      drawFloor ();
      
      whirl1 += 0.2;
      frame = frame + 1;
      
      tiStopFrame ();
      framecount++;  
   }
   
   void keyPressEvent(QKeyEvent* e) {
      switch (e->key()) {
       case Key_A: m_vy-=0.05; break;
       case Key_Z: m_vy+=0.05; break;
       case Key_X: m_vx+=0.05; break;
       case Key_C: m_vx-=0.05; break;
       case Key_K: m_vz+=0.05; break;
       case Key_M: m_vz-=0.05; break;
       case Key_T: m_rx+=1.0; break; 
       case Key_Y: m_rx-=1.0; break; 
       case Key_G: m_ry+=1.0; break; 
       case Key_H: m_ry-=1.0; break; 
       case Key_B: m_rz+=1.0; break; 
       case Key_N: m_rz-=1.0; break; 
      }
   }   
   
   void resizeGL (int w, int h)
   {
      glViewport (0, 0, (GLint)w, (GLint)h);
   }
   void initializeGL ()
   {
   }
   void timerEvent(QTimerEvent*) {
      updateGL();
   }
   
};  

