void GsMat::operator *= ( const GsMat& m )
 {
   GsMat* t = (this==&m)? new GsMat(GsMat::NoInit) : this;

   t->setl1 ( E11*m.E11 + E12*m.E21 + E13*m.E31 + E14*m.E41,
              E11*m.E12 + E12*m.E22 + E13*m.E32 + E14*m.E42,
              E11*m.E13 + E12*m.E23 + E13*m.E33 + E14*m.E43,
              E11*m.E14 + E12*m.E24 + E13*m.E34 + E14*m.E44 );

   t->setl2 ( E21*m.E11 + E22*m.E21 + E23*m.E31 + E24*m.E41,
              E21*m.E12 + E22*m.E22 + E23*m.E32 + E24*m.E42,
              E21*m.E13 + E22*m.E23 + E23*m.E33 + E24*m.E43,
              E21*m.E14 + E22*m.E24 + E23*m.E34 + E24*m.E44 );

   t->setl3 ( E31*m.E11 + E32*m.E21 + E33*m.E31 + E34*m.E41,
              E31*m.E12 + E32*m.E22 + E33*m.E32 + E34*m.E42,
              E31*m.E13 + E32*m.E23 + E33*m.E33 + E34*m.E43,
              E31*m.E14 + E32*m.E24 + E33*m.E34 + E34*m.E44 );

   t->setl4 ( E41*m.E11 + E42*m.E21 + E43*m.E31 + E44*m.E41,
              E41*m.E12 + E42*m.E22 + E43*m.E32 + E44*m.E42,
              E41*m.E13 + E42*m.E23 + E43*m.E33 + E44*m.E43,
              E41*m.E14 + E42*m.E24 + E43*m.E34 + E44*m.E44 );

   if ( t!=this ) { *this=*t; delete t; }
 }
void GsMat::mult ( const GsMat& m1, const GsMat& m2 )
 {
   GsMat* m = (this==&m1||this==&m2)? new GsMat(GsMat::NoInit) : this;

   m->setl1 ( m1.E11*m2.E11 + m1.E12*m2.E21 + m1.E13*m2.E31 + m1.E14*m2.E41,
              m1.E11*m2.E12 + m1.E12*m2.E22 + m1.E13*m2.E32 + m1.E14*m2.E42,
              m1.E11*m2.E13 + m1.E12*m2.E23 + m1.E13*m2.E33 + m1.E14*m2.E43,
              m1.E11*m2.E14 + m1.E12*m2.E24 + m1.E13*m2.E34 + m1.E14*m2.E44 );

   m->setl2 ( m1.E21*m2.E11 + m1.E22*m2.E21 + m1.E23*m2.E31 + m1.E24*m2.E41,
              m1.E21*m2.E12 + m1.E22*m2.E22 + m1.E23*m2.E32 + m1.E24*m2.E42,
              m1.E21*m2.E13 + m1.E22*m2.E23 + m1.E23*m2.E33 + m1.E24*m2.E43,
              m1.E21*m2.E14 + m1.E22*m2.E24 + m1.E23*m2.E34 + m1.E24*m2.E44 );

   m->setl3 ( m1.E31*m2.E11 + m1.E32*m2.E21 + m1.E33*m2.E31 + m1.E34*m2.E41,
              m1.E31*m2.E12 + m1.E32*m2.E22 + m1.E33*m2.E32 + m1.E34*m2.E42,
              m1.E31*m2.E13 + m1.E32*m2.E23 + m1.E33*m2.E33 + m1.E34*m2.E43,
              m1.E31*m2.E14 + m1.E32*m2.E24 + m1.E33*m2.E34 + m1.E34*m2.E44 );

   m->setl4 ( m1.E41*m2.E11 + m1.E42*m2.E21 + m1.E43*m2.E31 + m1.E44*m2.E41,
              m1.E41*m2.E12 + m1.E42*m2.E22 + m1.E43*m2.E32 + m1.E44*m2.E42,
              m1.E41*m2.E13 + m1.E42*m2.E23 + m1.E43*m2.E33 + m1.E44*m2.E43,
              m1.E41*m2.E14 + m1.E42*m2.E24 + m1.E43*m2.E34 + m1.E44*m2.E44 );

   if ( m!=this ) { *this=*m; delete m; }
 }
// here we will redraw the scene according to the current state of the application.
void AppWindow::glutDisplay ()
 {
   // Clear the rendering window
   glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

   // Build a cross with some lines (if not built yet):
   if ( _axis.changed ) // needs update
    { _axis.build(1.0f); // axis has radius 1.0
    }
   if (sunanim) {
	   sunx = 2 * (cos(2 * M_PI*sunxc / 360) + sin(2 * M_PI*sunxc / 360)); suny = 20.0f; sunz = 2 * (-sin(2 * M_PI*sunxz / 360) + cos(2 * M_PI*sunxz / 360));
   }
   else {
	   sunx = 0.0; suny = 1; sunz = -.5;
   }

   // Define our scene transformation:
   GsMat rx, ry, stransf, barrelroll, leftright, transf, updown, rightwing, leftwing, offsety, centerrwing, centerlwing, rl, rr, backR, backL, centerbackl, centerbackr, br, bl;
   GsMat rfrot, lfrot, rbrot, lbrot, rollyawpitch, ShadowT;
   rx.rotx ( _rotx );
   ry.roty ( _roty );
   stransf = rx*ry; // set the scene transformation matrix

   offsety.translation(GsVec(0.0f, -5.7f, 0.0f));

   //Rotate many degrees
   barrelroll.rotz(2 * M_PI * rotate / 360);
   leftright.roty(2 * M_PI * _turnlr / 360);
   updown.rotx(2 * M_PI * _turnud / 360);

   rollyawpitch = leftright*updown*barrelroll;

   //Translate front wings to center
   centerrwing.translation(GsVec(-0.1f,-0.15f,0.0f)); centerlwing.translation(GsVec(0.1f, -0.15f, 0.0f));
   //Translate front wings back to airplane
   rr.translation(GsVec(0.1f, 0.15f, 0.0f)); rl.translation(GsVec(-0.1f, 0.15f, 0.0f));
   //Translate back wings to center
   centerbackl.translation(GsVec(-0.05f, -0.2f, 0.0f)); centerbackr.translation(GsVec(0.05f, -0.2f, 0.0f));
   //Translate back wings to airplane
   bl.translation(GsVec(0.05f, 0.2f, 0.0f)); br.translation(GsVec(-0.05f, 0.2f, 0.0f));
   //Rotate front wings
   rightwing.rotz(2 * M_PI * _wingsflyR / 360); leftwing.rotz(2 * M_PI * -_wingsflyL / 360);
   //Rotate back wings
   backR.rotz(2 * M_PI * _backR / 360); backL.rotz(2 * M_PI * -_backL / 360);
   //Clean up draw function
   rfrot = rr*rightwing*centerrwing;
   lfrot = rl*leftwing*centerlwing;
   rbrot = br*backR*centerbackr;
   lbrot = bl*backL*centerbackl;

	//speed is fast
	GsVec P = GsVec(0.0f, 0.0f, speed);
	GsVec bd = leftright*updown*barrelroll*P;
	R = R + bd;
	transf.setrans(R);

	GsVec sbd = leftright*P;
	SR = SR + sbd;
	ShadowT.setrans(SR);

   // Define our projection transformation:
   // (see demo program in gltutors-projection.7z, we are replicating the same behavior here)
   GsMat camview, camview2, _birdseye, persp, sproj;

   GsVec eye(0,0,0), center(0,0,0), up(0,1,0);
   GsVec eye2(0, 10, 0), center2(0, 0, 0), up2(0, 0, 1);
   eye += R + leftright*updown*barrelroll*GsVec(0,0,2);
   center += R + GsVec(0, 0, 0);

   _sun.build(1.0f, sunx, suny, sunz);
   float ground[4] = { 0, 1, 0, 4.99 };
   float light[4] = { sunx, suny, sunz, 0 };
   float  dot;
   GsMat shadowMat;

   dot = ground[0] * light[0] +
	   ground[1] * light[1] +
	   ground[2] * light[2] +
	   ground[3] * light[3];
    
   shadowMat.setl1(dot - light[0] * ground[0], 0.0 - light[0] * ground[1], 0.0 - light[0] * ground[2], 0.0 - light[0] * ground[3]);
   shadowMat.setl2(0.0 - light[1] * ground[0], dot - light[1] * ground[1], 0.0 - light[1] * ground[2], 0.0 - light[1] * ground[3]);
   shadowMat.setl3(0.0 - light[2] * ground[0], 0.0 - light[2] * ground[1], dot - light[2] * ground[2], 0.0 - light[2] * ground[3]);
   shadowMat.setl4(0.0 - light[3] * ground[0], 0.0 - light[3] * ground[1], 0.0 - light[3] * ground[2], dot - light[3] * ground[3]);
   
   //shadowMat = shadowMat*ry*rx;
   camview.lookat ( eye, center, up ); // set our 4x4 "camera" matrix
   camview2.lookat(eye2, center2, up2);

   float aspect=1.0f, znear=0.1f, zfar=5000.0f;
   persp.perspective ( _fovy, aspect, znear, zfar ); // set our 4x4 perspective matrix

   // Our matrices are in "line-major" format, so vertices should be multiplied on the 
   // right side of a matrix multiplication, therefore in the expression below camview will
   // affect the vertex before persp, because v' = (persp*camview)*v = (persp)*(camview*v).
   if (camera) {
	   sproj = persp * camview; // set final scene projection
   }
   else {
	   sproj = persp * camview2;
   }

   //  Note however that when the shader receives a matrix it will store it in column-major 
   //  format, what will cause our values to be transposed, and we will then have in our 
   //  shaders vectors on the left side of a multiplication to a matrix.
   float col = 1;
   // Draw:
   //if ( _viewaxis ) _axis.draw ( stransf, sproj );
	_model.draw(stransf*transf*rollyawpitch, sproj, _light, 0);
	_model2.draw(stransf*transf*rollyawpitch*rfrot, sproj, _light, 0);
	_model3.draw(stransf*transf*rollyawpitch*lfrot, sproj, _light, 0);
	_model4.draw(stransf*transf*rollyawpitch, sproj, _light, 0);
	_model5.draw(stransf*transf*rollyawpitch*rbrot, sproj, _light, 0);
	_model6.draw(stransf*transf*rollyawpitch*lbrot, sproj, _light, 0);
	_floor.draw(stransf, sproj, _light, textures);
	_city.draw(stransf*offsety, sproj, _light, 0);
	_city.draw(stransf*shadowMat*offsety, sproj, _shadow, 0);
	//Shadow
	_model.draw(stransf*ShadowT*shadowMat*rollyawpitch, sproj, _shadow, 1);
	_model2.draw(stransf*ShadowT*shadowMat*rollyawpitch, sproj, _shadow, 1);
	_model3.draw(stransf*ShadowT*shadowMat*rollyawpitch, sproj, _shadow, 1);
	_model4.draw(stransf*ShadowT*shadowMat*rollyawpitch, sproj, _shadow, 1);
	_model5.draw(stransf*ShadowT*shadowMat*rollyawpitch, sproj, _shadow, 1);
	_model6.draw(stransf*ShadowT*shadowMat*rollyawpitch, sproj, _shadow, 1);
	_side.draw(stransf, sproj, _light, col, textures);
	_sun.draw(stransf, sproj);


   // Swap buffers and draw:
   glFlush();         // flush the pipeline (usually not necessary)
   glutSwapBuffers(); // we were drawing to the back buffer, now bring it to the front
}