/*
	Asteroids
    Copyright (C) 2006  Darragh Coy.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*##############################################################################

Module name: Vec2D
Purpose:     Handles routine vector math operations, add , subtract, dot etc..

##############################################################################*/

#include "Vec2D.h"

/*******************************************************************************
Private module prototypes: Not for outside use!
*******************************************************************************/

   //..

/*******************************************************************************
Variables
*******************************************************************************/

   //..

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

Name:       Vec2D_Add
Purpose:    Adds vector 2 to vector 1
Parameters: Two vectors
Returns:    None

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

void Vec2D_Add ( Vec2D_t * vec1 , Vec2D_t * vec2 )
{
  vec1->x += vec2->x;
  vec1->y += vec2->y;
}

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

Name:       Vec2D_Sub
Purpose:    Subtracts vector 2 from vector 1
Parameters: Two vectors
Returns:    None

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

void Vec2D_Sub ( Vec2D_t * vec1 , Vec2D_t * vec2 )
{
  vec1->x -= vec2->x;
  vec1->y -= vec2->y;
}

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

Name:       Vec2D_Dot
Purpose:    Returns the dot product of two vectors
Parameters: Two vectors
Returns:    Dot product

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

float Vec2D_Dot ( Vec2D_t * vec1 , Vec2D_t * vec2 )
{
  return ( vec1->x * vec2->x + vec1->y * vec2->y );
}

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

Name:       Vec2D_Distance
Purpose:    Gets distance between two points
Parameters: Two vectors
Returns:    Distance

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

float Vec2D_Distance ( Vec2D_t * vec1 , Vec2D_t * vec2 )
{
    // Get a vector between the two vectors:

    float v[2] =
    {
        vec1->x - vec2->x,
        vec1->y - vec2->y
    };

    // Get squre lenght of vector: this is square distance between points

    float distSquared = v[0] * v[0] + v[1] * v[1];

    // Get square root to get the distance and return it:

    return sqrtf(distSquared);
}

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

Name:       Vec2D_Normalise
Purpose:    Normalises the input vector to unit lenght. Useful for getting a pure
            direction vector.
Parameters: A vector
Returns:    None

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

void Vec2D_Normalise ( Vec2D_t * vec1 )
{
     // Get the lenght of the vector

     float lenght = sqrtf( vec1->x * vec1->x + vec1->y * vec1->y );

     // Divide vector components by the lenght to normalise

     if ( lenght > 0 )
     {
         vec1->x /= lenght;
         vec1->y /= lenght;
     }
}

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

Name:       Vec2D_Rot
Purpose:    Rotates vector1 about vector2 by angle 'angle'
Parameters: Two vectors

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

void Vec2D_Rot ( Vec2D_t * vec1 , Vec2D_t * vec2 , float angle )
{
   // Convert angle to radians first

   angle *= TO_RADIANS;

   // Subtract vec2 from vec1 so that the point rotates about it

   vec1->x -= vec2->x;
   vec1->y -= vec2->y;

   // Create a new vector to hold rotation

   Vec2D_t rotated;

   // Do the rotations

   rotated.x = vec1->x * cos( angle) + vec1->y * sin(angle);
   rotated.y = vec1->x * sin(-angle) + vec1->y * cos(angle);

   // Set vec1 now as the rotated vector

   vec1->x = rotated.x;
   vec1->y = rotated.y;

   // undo the previous translation to get it back to where it is supposed to be

   vec1->x += vec2->x;
   vec1->y += vec2->y;
}

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

Name:       Vec2D_NormalTo
Purpose:    Changes the input vector into a vector perpendicular to it.
            Trés handy for per-vertex collision detection!
Parameters: A vector
Returns:    None

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

void Vec2D_NormalTo ( Vec2D_t * vector )
{
     // Save y component

     float y = vector->y;

     // Swap x component into y

     vector->y = vector->x;

     // Swap y component into x and negate

     vector->x = -y;
}

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

Name:       Vec2D_InsideTri
Purpose:    Tells if a point is inside a triangle
Parameters: Pointer to a vector, pointer to vector array representing triangle.
Returns:    True if inside, false if not..

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

bool Vec2D_InsideTri ( Vec2D_t * checkPoint , Vec2D_t * triangle )
{
     /**************************************************************************
     Vectors representing a lineNormal and the check point (local to line coordinate system)
     **************************************************************************/

     Vec2D_t lineNormal ;
     Vec2D_t point;

     /**************************************************************************
     Check what side the check point is on of the first line. If it is on the
     right side then the dot product with the line normal will be < 0
     **************************************************************************/

     // Get vector from start to end of the line

     lineNormal.x = - (triangle)->x + (triangle+1)->x;
     lineNormal.y = - (triangle)->y + (triangle+1)->y;

     // Get normal to line

     Vec2D_NormalTo(&lineNormal);

     // Get vector from start of the line to the check point

     point.x = - (triangle)->x + checkPoint->x;
     point.y = - (triangle)->y + checkPoint->y;

     // Do a dot product between the two: if < 0 then return false because
     // point is on left side of line and consequently not inside triangle:

     if ( Vec2D_Dot(&lineNormal,&point) < 0 ) return false;

     /**************************************************************************
     Check what side the check point is on of the second line. If it is on the
     right side then the dot product with the line normal will be < 0
     **************************************************************************/

     // Get vector from start to end of the line

     lineNormal.x = - (triangle+1)->x + (triangle+2)->x;
     lineNormal.y = - (triangle+1)->y + (triangle+2)->y;

     // Get normal to line

     Vec2D_NormalTo(&lineNormal);

     // Get vector from start of the line to the check point

     point.x = - (triangle+1)->x + checkPoint->x;
     point.y = - (triangle+1)->y + checkPoint->y;

     // Do a dot product between the two: if < 0 then return false because
     // point is on left side of line and consequently not inside triangle:

     if ( Vec2D_Dot(&lineNormal,&point) < 0 ) return false;

     /**************************************************************************
     Check what side the check point is on of the third line. If it is on the
     right side then the dot product with the line normal will be < 0
     **************************************************************************/

     // Get vector from start to end of the line

     lineNormal.x = - (triangle+2)->x + (triangle)->x;
     lineNormal.y = - (triangle+2)->y + (triangle)->y;

     // Get normal to line

     Vec2D_NormalTo(&lineNormal);

     // Get vector from start of the line to the check point

     point.x = - (triangle+2)->x + checkPoint->x;
     point.y = - (triangle+2)->y + checkPoint->y;

     // Do a dot product between the two: if < 0 then return false because
     // point is on left side of line and consequently not inside triangle:

     if ( Vec2D_Dot(&lineNormal,&point) < 0 ) return false;

     /**************************************************************************
     If we have reached this far then we can conclude that the point is inside
     the triangle. Return true
     **************************************************************************/

     return true;
}
