#include "Drawing3D.h"

using namespace Framework;

// Contents of the Drawable3D class

// Constructor
Drawable3D::Drawable3D()
    : ReferenceCounter()
{
    welt = welt.identity();
    pos = Vec3<float>(0, 0, 0);
    angle = Vec3<float>(0, 0, 0);
    rend = 0;
    alpha = 0;
    radius = 0;
    size = 1.f;
}

Drawable3D::~Drawable3D() {}

// Sets the position of the drawing in the world
//  p: The position
void Drawable3D::setPosition(const Vec3<float>& p)
{
    pos = p;
    rend = 1;
}

// Sets the position of the drawing in the world
//  x: The x position
//  y: The y position
//  z: The z position
void Drawable3D::setPosition(float x, float y, float z)
{
    pos.x = x;
    pos.y = y;
    pos.z = z;
    rend = 1;
}

// Sets the position of the drawing in the world
//  x: The x position
void Drawable3D::setX(float x)
{
    pos.x = x;
    rend = 1;
}

// Sets the position of the drawing in the world
//  y: The y position
void Drawable3D::setY(float y)
{
    pos.y = y;
    rend = 1;
}

// Sets the position of the drawing in the world
//  z: The z position
void Drawable3D::setZ(float z)
{
    pos.z = z;
    rend = 1;
}

// Sets the rotation of the drawing in the world
//  d: The rotation around the x, y and z axis
void Drawable3D::setRotation(const Vec3<float>& d)
{
    angle = d;
    rend = 1;
}

// Sets the rotation of the drawing in the world
//  xWinkel: The rotation around the x axis
//  yWinkel: The rotation around the y axis
//  zWinkel: The rotation around the z axis
void Drawable3D::setRotation(float xWinkel, float yWinkel, float zWinkel)
{
    angle.x = xWinkel;
    angle.y = yWinkel;
    angle.z = zWinkel;
    rend = 1;
}

// Sets the rotation of the drawing in the world
//  winkel: The rotation around the x axis
void Drawable3D::setRotationX(float winkel)
{
    angle.x = winkel;
    rend = 1;
}

// Sets the rotation of the drawing in the world
//  winkel: The rotation around the y axis
void Drawable3D::setRotationY(float winkel)
{
    angle.y = winkel;
    rend = 1;
}

// Sets the rotation of the drawing in the world
//  winkel: The rotation around the z axis
void Drawable3D::setRotationZ(float winkel)
{
    angle.z = winkel;
    rend = 1;
}

// Sets whether the object contains partially or fully transparent areas
//  a: true if partially or fully transparent areas are present
void Drawable3D::setAlpha(bool a)
{
    alpha = a;
    rend = 1;
}

//! Sets the scaling
void Drawable3D::setSize(float size)
{
    this->size = size;
    rend = 1;
}

// Calculates the matrices of all bones of the drawing's skeleton
//  viewProj: The multiplied camera matrices
//  matBuffer: An array of matrices to be filled
//  return: The number of matrices the drawing requires
int Drawable3D::calculateMatrices(
    const Mat4<float>& viewProj, Mat4<float>* matBuffer)
{
    matBuffer[0] = viewProj * welt;
    return 1;
}

// Processes a mouse event
//  me: The mouse event to be processed
void Drawable3D::doMouseEvent(MouseEvent3D& me) {}

// Processes a keyboard event
//  te: The keyboard event to be processed
void Drawable3D::doKeyboardEvent(KeyboardEvent& te) {}

// Processes the elapsed time
//  tickval: The time in seconds since the last call of the function
//  return: true if the object has changed, false
//  otherwise.
bool Drawable3D::tick(double tickval)
{
    if (rend)
    {
        welt = welt.translation(pos) * welt.rotationZ(angle.z)
             * welt.rotationX(angle.x) * welt.rotationY(angle.y)
             * welt.scaling(size);
        rend = 0;
        return 1;
    }
    return 0;
}

// Returns whether the object contains partially or fully transparent areas
bool Drawable3D::hasAlpha() const
{
    return alpha;
}

// Returns the radius of a sphere that encloses the entire model
float Drawable3D::getRadius() const
{
    return radius;
}

// Returns a point representing the position of the drawing in the world
const Vec3<float>& Drawable3D::getPos() const
{
    return pos;
}

// Returns the X position of the drawing in the world
float Drawable3D::getX() const
{
    return pos.x;
}

// Returns the Y position of the drawing in the world
float Drawable3D::getY() const
{
    return pos.y;
}

// Returns the Z position of the drawing in the world
float Drawable3D::getZ() const
{
    return pos.z;
}

// Returns a vector representing the rotation of the drawing in the world.
// x is the rotation around the X axis in radians, etc.
const Vec3<float>& Drawable3D::getRotation() const
{
    return angle;
}

// Returns the rotation around the X axis in radians
float Drawable3D::getXRotation() const
{
    return angle.x;
}

// Returns the rotation around the Y axis in radians
float Drawable3D::getYRotation() const
{
    return angle.y;
}

// Returns the rotation around the Z axis in radians
float Drawable3D::getZRotation() const
{
    return angle.z;
}

// Returns the matrix that translates the drawing into world space
const Mat4<float>& Drawable3D::getMatrix() const
{
    return welt;
}

//! Calculates for a point in local drawing coordinates the point in
//! world coordinates by applying rotation, scaling and translation
Vec3<float> Drawable3D::applyWorldTransformation(
    const Vec3<float>& modelPos) const
{
    return welt * modelPos;
}