/*
 * @topic T0L120 GLM examples
 * @brief program using various GLM functions
*/

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <string>

// Assuming this source file is located in
//      playground/Week08math/src/glm_examples.cpp
// use the following relative include paths:
#include "../../../external/glm/glm/glm.hpp"
#include "../../../external/glm/glm/gtc/matrix_transform.hpp"

using namespace std;

// function to display 4x4 matrix
void display_4x4( string tag, glm::mat4 m4 )
{
    cout << tag << '\n';
    for (int col = 0; col < 4; ++col) {
        cout << "| ";
        for (int row = 0; row < 4; ++row) {
            cout << m4[row][col] << '\t';
        }
        cout << '\n';
    }
    cout << '\n';
}


// function to display 3-component vector
void display_v3(string tag, glm::vec3 v3)
{
    cout
        << tag
        << "\n| "
        << v3.x << '\t'
        << v3.y << '\t'
        << v3.z << '\t'
        << "\n"
        ;
}


// function to display 4-component vector
void display_v4(string tag, glm::vec4 v4)
{
    cout
        << tag
        << "\n| "
        << v4.x << '\t'
        << v4.y << '\t'
        << v4.z << '\t'
        << v4.w
        << "\n"
        ;
}

// various examples using GLM functions:
int main()
{
    // create 4-component vector
    glm::vec4 v4{ 2, 5, 1, 8 };

    display_v4( "v4", v4 );

    /*
    To populate 4x4 matrix with these values...
    1  2  3  4
    5  6  7  8
    9 10 11 12
    0  0  0  1
    */
    glm::mat4 m4 {  // ...use this order:
        1, 0, 0, 6, // 1, 5, 9, 0,
        0, 3, 0, 0, // 2, 6, 10, 0,
        2, 0, 5, 0, // 3, 7, 11, 0,
        0, 4, 0, 7  // 4, 8, 12, 1
    };

    display_4x4( "m4", m4 );

    display_v4( "m4 * v4", m4 * v4 );

    glm::mat4 i4( 1.0 ); // identity matrix
    display_v4( "i4 * v4", i4 * i4 * i4 * i4 * v4 );

    glm::vec4 Position = glm::vec4( glm::vec3( 0.0f ), 1.0f ); // origin point
    // To translate once:
    // glm::mat4 Model = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f, 2.0f, 3.0f));
    glm::mat4 Model = glm::mat4( 1.0f ); // suppose no transformations are needed

    // rotate around Z axis:
    Model = glm::rotate( Model, glm::radians( 45.0f ), glm::vec3( 0.0f, 0.0f, 1.0f ) );

    // cumulative translations along Z, Y, and X axis:
    Model = glm::translate( Model, glm::vec3( 1.0f, 0.0f, 0.0f ) );
    Model = glm::translate( Model, glm::vec3( 0.0f, 2.0f, 0.0f ) );
    Model = glm::translate( Model, glm::vec3( 0.0f, 0.0f, 3.0f ) );

    // move from origin and then rotate:
    glm::vec4 Transformed = Model * Position;

    Transformed = glm::normalize( Transformed );
    Transformed = -Transformed;
    display_v4( "translated, rotated, and reversed", Transformed );

    glm::vec3 vCross = glm::cross(
        glm::vec3( 1.0f, 0.0f, 0.0f ), // unit-size vector along the x axis
        glm::vec3( 0.0f, 1.0f, 0.0f )  // unit-size vector along the y axis
    );
    display_v3( "cross( x, y )", vCross );

    vCross = glm::cross(
        glm::vec3( 0.0f, 1.0f, 0.0f ), // unit-size vector along the y axis
        glm::vec3( 1.0f, 0.0f, 0.0f )  // unit-size vector along the x axis
        );
    display_v3( "cross( y, x )", vCross );

    glm::vec3 vA( 1.0f, 0.0f, 0.0f );
    glm::vec3 vB( 0.0f, 1.0f, 0.0f );
    float dot_product = glm::dot( vA, vA );
    cout << "dot-product: " << dot_product << "\n\n";

    // create perspective projection matrix:
    glm::mat4 Perspective = glm::perspective( 60.0f/*fov*/, 1.0f/*aspect = screen width / height*/, 0.1f/*near*/, 1000.0f/*far*/);

    system("pause");
    return 0;
}