#include "cTriangle.h"
#include <math.h>

cTriangle::cTriangle() 
{ 
    hasBeenAddedToCollisionList_ = false;
 } 

void cTriangle::draw()
{
    glBegin(GL_TRIANGLES);
        
        //glNormal3f(normal_.x_, normal_.y_, normal_.z_);
        
        glNormal3f(v0_->normal_.x_, v0_->normal_.y_, v0_->normal_.z_);
        v0_->textureCoord_.setGLCoord();
	//v0Color.setGLColor();
	glVertex3f(v0_->x_, v0_->y_, v0_->z_);
        
        glNormal3f(v1_->normal_.x_, v1_->normal_.y_, v1_->normal_.z_);
        v1_->textureCoord_.setGLCoord();
	//v1Color.setGLColor();	
        glVertex3f(v1_->x_, v1_->y_, v1_->z_);
        
        glNormal3f(v2_->normal_.x_, v2_->normal_.y_, v2_->normal_.z_);
        v2_->textureCoord_.setGLCoord();
	//v2Color.setGLColor();
        glVertex3f(v2_->x_, v2_->y_, v2_->z_);
        
    glEnd();
}

void cTriangle::computeNormal()
{ 
    cVector edge1 = *v1_ - *v0_;
    cVector edge2 = *v2_ - *v0_;
    
    normal_ =  edge1.cross(edge2); 
    normal_.normalize();
}	

cVector& cTriangle::getNormal() { return normal_; }

void cTriangle::standardizeVertices()
{
    // create the new standardized face and 
    // properly set up all of its data fields
    standardized_.v0_ = *v0_;
    standardized_.v1_ = *v1_;
    standardized_.v2_ = *v2_;
    
    // rotate our triangle to align last edge with the x axis
    // first we find the axis of rotation v
    // then we find the angle through which we need to rotate phi
    float sigma, phi;		// angles of rotation
    cVector rotAxis;		// axis of rotation
    cVector xAxis(1, 0, 0);	// the x-axis
    
    glPushMatrix(); 		// save the current matrix
    
    // translate our triangle so v0_ is at the origin
    standardized_.v1_ -= standardized_.v0_;
    standardized_.v2_ -= standardized_.v0_;
    standardized_.v0_ = cVector(0, 0, 0);
    
    // rotate our triangle to align last edge with the x axis
    // first we find the axis of rotation v
    // then we find the angle through which we need to rotate phi
    cVector w = standardized_.v2_;
    w.normalize();
    
    if(w != xAxis && w != -xAxis) // w is not on the x axis
    {
        rotAxis = w.cross(xAxis);
        rotAxis.normalize();
        
        // the angle of rotation is found by taking the arcos of
        // the dot product of w and x we then convert to degrees
            phi = (float) acos((double) w.dot(xAxis));
            phi *= 360.f/(2.0f*3.14159f);	
    }
    else // w is on the x axis
    {
        rotAxis = cVector(0, 1, 0);
        if(w == xAxis) phi = 0;
        else phi = 180;
    }
    
    // have OpenGL compute the rotation transformation and write it into 
    // vertexTransformation_
    glLoadIdentity();
    glRotatef(phi, rotAxis.x_, rotAxis.y_, rotAxis.z_);
    glGetFloatv(GL_MODELVIEW_MATRIX, vertexTransform_);
    
    // update the v1_ and v2_. v0_ wont change
    standardized_.v1_ = standardized_.v1_.matrixMultiply(vertexTransform_);
    standardized_.v2_ = standardized_.v2_.matrixMultiply(vertexTransform_);
    
    // correct for rounding errors. v2_ should be on the x-axis
    standardized_.v2_.y_ = 0;
    standardized_.v2_.z_ = 0;
    
    // rotate the triangle around the x axis to bring it into the y = 0 plane
    w = standardized_.v1_;
    w.x_ = 0.0f;
    
    sigma= (float) acos((double) (w.z_/w.length()));
    sigma *= 360.f/(2.0f*3.14159f);
    
    // axis of rotation is either +x or -x
    if(w.y_ < 0) xAxis *= -1.0f;
    
    // compute the angle of rotation sigma in degrees
    //cVector zAxis(0,0,1);
    //cVector v1Prime = cVector(0, standardized_.v1_.y_, standardized_.v1_.z_);
    //v1Prime.normalize();
    //sigma = zAxis.dot(v1Prime);
    
    // have OpenGl compute the transform matrix and write it to vertexTransform_
    glLoadIdentity();
    glRotatef(sigma, xAxis.x_, xAxis.y_, xAxis.z_);
    glGetFloatv(GL_MODELVIEW_MATRIX, vertexTransform_);
    
    // update v1_, v0_ and v2_ wont change
    standardized_.v1_ = standardized_.v1_.matrixMultiply(vertexTransform_);
    
    // correct for round off
    standardized_.v1_.y_ = 0;
    
    // compute the final vertexTranform matrix that will be used to transform
    // the ball's path into standardized space for the face intersection test
    glLoadIdentity();
    glRotatef(sigma, xAxis.x_, xAxis.y_, xAxis.z_);
    glRotatef(phi, rotAxis.x_, rotAxis.y_, rotAxis.z_);
    glTranslatef( -v0_->x_, -v0_->y_, -v0_->z_); 
    glGetFloatv(GL_MODELVIEW_MATRIX, vertexTransform_);
    
    glPopMatrix(); // restore current matrix
}

cStandardizedTriangle& cTriangle::getStandardized() { return standardized_; }

float* cTriangle::getStandardVertexTranform() { return vertexTransform_; }

bool cTriangle::forwardFacing(cVector incident) { return incident.dot(normal_) <= 0; }

void cTriangle::addToTextureList(vector<cTextureImage*>& textures)
{
    if(materialIndex_ == -1)
        cout << "error, triangle has fucked up material index" << endl;
    
    textures[materialIndex_]->trianglesWithThisTexture_.push_back(this);
}
