/*
 * Copyright(c) Live2D Inc. All rights reserved.
 *
 * Use of this source code is governed by the Live2D Open Software license
 * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html.
 */

#include "CubismViewMatrix.hpp"

namespace Live2D { namespace Cubism { namespace Framework {

CubismViewMatrix::CubismViewMatrix()
                                    : _screenLeft(0.0f)
                                    , _screenRight(0.0f)
                                    , _screenTop(0.0f)
                                    , _screenBottom(0.0f)
                                    , _maxLeft(0.0f)
                                    , _maxRight(0.0f)
                                    , _maxTop(0.0f)
                                    , _maxBottom(0.0f)
                                    , _maxScale(0.0f)
                                    , _minScale(0.0f)
{ }

CubismViewMatrix::~CubismViewMatrix()
{ }

csmFloat32 CubismViewMatrix::GetMaxScale() const
{
    return _maxScale;
}

csmFloat32 CubismViewMatrix::GetMinScale() const
{
    return _minScale;
}

csmFloat32 CubismViewMatrix::GetScreenLeft() const
{
    return _screenLeft;
}

csmFloat32 CubismViewMatrix::GetScreenRight() const
{
    return _screenRight;
}

csmFloat32 CubismViewMatrix::GetScreenBottom() const
{
    return _screenBottom;
}

csmFloat32 CubismViewMatrix::GetScreenTop() const
{
    return _screenTop;
}

csmFloat32 CubismViewMatrix::GetMaxLeft() const
{
    return _maxLeft;
}

csmFloat32 CubismViewMatrix::GetMaxRight() const
{
    return _maxRight;
}

csmFloat32 CubismViewMatrix::GetMaxBottom() const
{
    return _maxBottom;
}

csmFloat32 CubismViewMatrix::GetMaxTop() const
{
    return _maxTop;
}

csmBool CubismViewMatrix::IsMaxScale() const
{
    return GetScaleX() >= _maxScale;
}

csmBool CubismViewMatrix::IsMinScale() const
{
    return GetScaleX() <= _minScale;
}


void CubismViewMatrix::AdjustTranslate(csmFloat32 x, csmFloat32 y)
{
    if (_tr[0] * _maxLeft + (_tr[12] + x) > _screenLeft)
    {
        x = _screenLeft - _tr[0] * _maxLeft - _tr[12];
    }

    if (_tr[0] * _maxRight + (_tr[12] + x) < _screenRight)
    {
        x = _screenRight - _tr[0] * _maxRight - _tr[12];
    }


    if (_tr[5] * _maxTop + (_tr[13] + y) < _screenTop)
    {
        y = _screenTop - _tr[5] * _maxTop - _tr[13];
    }

    if (_tr[5] * _maxBottom + (_tr[13] + y) > _screenBottom)
    {
        y = _screenBottom - _tr[5] * _maxBottom - _tr[13];
    }

    csmFloat32 tr1[] = {
                        1.0f,   0.0f,   0.0f, 0.0f,
                        0.0f,   1.0f,   0.0f, 0.0f,
                        0.0f,   0.0f,   1.0f, 0.0f,
                        x,      y,      0.0f, 1.0f
                        };
    Multiply(tr1, _tr, _tr);
}

void CubismViewMatrix::AdjustScale(csmFloat32 cx, csmFloat32 cy, csmFloat32 scale)
{
    csmFloat32 MaxScale = GetMaxScale();
    csmFloat32 MinScale = GetMinScale();

    csmFloat32 targetScale = scale * _tr[0]; //

    if (targetScale < MinScale)
    {
        if (_tr[0] > 0.0f)
        {
            scale = MinScale / _tr[0];
        }
    }
    else if (targetScale > MaxScale)
    {
        if (_tr[0] > 0.0f)
        {
            scale = MaxScale / _tr[0];
        }
    }

    csmFloat32 tr1[16] = {
                          1.0f, 0.0f, 0.0f, 0.0f,
                          0.0f, 1.0f, 0.0f, 0.0f,
                          0.0f, 0.0f, 1.0f, 0.0f,
                          cx,   cy,   0.0f, 1.0f
                          };
    csmFloat32 tr2[16] = {
                          scale, 0.0f,  0.0f, 0.0f,
                          0.0f,  scale, 0.0f, 0.0f,
                          0.0f,  0.0f,  1.0f, 0.0f,
                          0.0f,  0.0f,  0.0f, 1.0f
                          };
    csmFloat32 tr3[16] = {
                          1.0f, 0.0f, 0.0f, 0.0f,
                          0.0f, 1.0f, 0.0f, 0.0f,
                          0.0f, 0.0f, 1.0f, 0.0f,
                          -cx,  -cy,  0.0f, 1.0f
                          };

    Multiply(tr3, _tr, _tr);
    Multiply(tr2, _tr, _tr);
    Multiply(tr1, _tr, _tr);
}

void CubismViewMatrix::SetScreenRect(csmFloat32 left, csmFloat32 right, csmFloat32 bottom, csmFloat32 top)
{
    _screenLeft = left;
    _screenRight = right;
    _screenTop = top;
    _screenBottom = bottom;
}

void CubismViewMatrix::SetMaxScreenRect(csmFloat32 left, csmFloat32 right, csmFloat32 bottom, csmFloat32 top)
{
    _maxLeft = left;
    _maxRight = right;
    _maxTop = top;
    _maxBottom = bottom;
}

void CubismViewMatrix::SetMaxScale(csmFloat32 maxScale)
{
    _maxScale = maxScale;
}

void CubismViewMatrix::SetMinScale(csmFloat32 minScale)
{
    _minScale = minScale;
}

}}}
