/* Computer Graphics, Assignment, Translations, Rotations and Scaling
 *
 * Filename ........ transformations.c
 * Description ..... Contains the re-programmed translation, rotation and scaling functions
 * Date ............ 27-08-2009
 *
 * Student name .... Sander van Veen & Taddeus Kroes
 * Student email ... sandervv@gmail.com & taddeuskroes@hotmail.com
 * Collegekaart .... 6167969 & 6054129
 * Date ............ 22.09.2010
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/gl.h>
#include "transformations.h"
#include "vectors.h"

/* ANSI C/ISO C89 does not specify this constant (?) */
#ifndef M_PI
#define M_PI           3.14159265358979323846  /* pi */
#endif

void myScalef(GLfloat x, GLfloat y, GLfloat z)
{
    GLfloat M[16] =
    {
        x, 0.0, 0.0, 0.0,
        0.0, y, 0.0, 0.0,
        0.0, 0.0, z, 0.0,
        0.0, 0.0, 0.0, 1.0
    };
	
    glMultMatrixf(M);
}


void myTranslatef(GLfloat x, GLfloat y, GLfloat z)
{
    GLfloat M[16] =
    {
        1.0, 0.0, 0.0, 0.0,
        0.0, 1.0, 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0,
        x, y, z, 1.0
    };

    glMultMatrixf(M);
}

void myRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
{
    //GLfloat u[3], v[3], w[3], t[3];
	vector u, v, w, t;
	
    //
    // 1. Create the orthonormal basis
    //
	
    // Store the incoming rotation axis in w and normalize w
	w = normalizeVector(createVector(x, y, z));
	
    // Compute the value of t, based on w
	t = w;
	
	if( t.x < t.y )
	{
		if( t.x < t.z )
			t.x = 1;
		else
			t.z = 1;
	}
	else
	{
		if( t.y < t.z )
			t.y = 1;
		else
			t.z = 1;
	}
	
    // Compute u = t x w
	u = crossProduct(t, w);
	
    // Normalize u
	u = normalizeVector(u);
	
    // Compute v = w x u
	v = crossProduct(w, u);
	
    // At this point u, v and w should form an orthonormal basis.
    // If your routine does not seem to work correctly it might be
    // a good idea to the check the vector values.
	
    //
    // 2. Set up the three matrices making up the rotation
    //
	
    // Specify matrix A
	
    GLfloat A[16] =
    {
        u.x, u.y, u.z, 0.0,
        v.x, v.y, v.z, 0.0,
        w.x, w.y, w.z, 0.0,
        0.0, 0.0, 0.0, 1.0
    };

    // Convert 'angle' to radians
    angle = angle * M_PI / 180;

    // Specify matrix B

    GLfloat B[16] =
    {
        cosf(angle), sinf(angle), 0.0, 0.0,
        -sinf(angle), cosf(angle), 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0,
        0.0, 0.0, 0.0, 1.0
    };

    // Specify matrix C

    GLfloat C[16] =
    {
        u.x, v.x, w.x, 0.0,
        u.y, v.y, w.y, 0.0,
        u.z, v.z, w.z, 0.0,
        0.0, 0.0, 0.0, 1.0
    };

    //
    // 3. Apply the matrices to get the combined rotation
    //

    glMultMatrixf(A);
    glMultMatrixf(B);
    glMultMatrixf(C);
}

/*
 * Some help functions to calculate with vectors
 */

vector createVector(GLfloat x, GLfloat y, GLfloat z)
{
	vector p = {x, y, z};
	return p;
}

vector normalizeVector(vector p)
{
	return scalarMultiply(p, 1 / VECTOR_LENGTH(p));
}

vector scalarMultiply(vector p, GLfloat scalar)
{
	return createVector(p.x * scalar, p.y * scalar, p.z * scalar);
}

GLfloat dotProduct(vector p1, vector p2)
{
	return p1.x * p2.x + p1.y * p2.y + p1.z * p2.z;
}

vector crossProduct(vector p1, vector p2)
{
	return createVector( p1.y * p2.z - p1.z * p2.y,
	                     p1.z * p2.x - p1.x * p2.z,
	                     p1.x * p2.y - p1.y * p2.x );
}
