1. 4FIPS
  2. PHOTOS
  3. VIDEOS
  4. APPS
  5. CODE
  6. FORUMS
  7. ABOUT
/*
(c) 2004-14 Filip Stoklas, aka FipS, www.4FipS.com
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
*/

#include "fs_math_func.h"
#include "fs_common.h"

#define FS_CHECK FS_ASSERT

//--- COLOR3 ---

void test_color3() FS_NOEXCEPT
{
    using namespace fs::math;

    // color3_make(r, g, b)
    {
        const auto res = color3_make(1, 2, 3);
        FS_CHECK(res.r == 1 && res.g == 2 && res.b == 3);
    }
}

//--- COLOR4 ---

void test_color4() FS_NOEXCEPT
{
    using namespace fs::math;

    // color4_make(r, g, b, a)
    {
        const auto res = color4_make(1, 2, 3, 4);
        FS_CHECK(res.r == 1 && res.g == 2 && res.b == 3 && res.a == 4);
    }
}

//--- VEC2 ---

void test_vec2() FS_NOEXCEPT
{
    using namespace fs::math;

    // vec2_make(x, y)
    {
        const auto res = vec2_make(1.f, 2.f);
        FS_CHECK(res.x == 1.f && res.y == 2.f);
    }

    // += v
    {
        const auto v = vec2_make(10.f, 100.f);
        auto res = vec2_make(1.f, 2.f);
        res += v;
        FS_CHECK(res.x == 11.f && res.y == 102.f);
    }

    // += t
    {
        const auto t = 10.f;
        auto res = vec2_make(1.f, 2.f);
        res += t;
        FS_CHECK(res.x == 11.f && res.y == 12.f);
    }

    // -= v
    {
        const auto v = vec2_make(10.f, 100.f);
        auto res = vec2_make(1.f, 2.f);
        res -= v;
        FS_CHECK(res.x == -9.f && res.y == -98.f);
    }

    // -= t
    {
        const auto t = 10.f;
        auto res = vec2_make(1.f, 2.f);
        res -= t;
        FS_CHECK(res.x == -9.f && res.y == -8.f);
    }

    // *= v
    {
        const auto v = vec2_make(10.f, 100.f);
        auto res = vec2_make(1.f, 2.f);
        res *= v;
        FS_CHECK(res.x == 10.f && res.y == 200.f);
    }

    // *= t
    {
        const auto t = 10.f;
        auto res = vec2_make(1.f, 2.f);
        res *= t;
        FS_CHECK(res.x == 10.f && res.y == 20.f);
    }

    // /= v
    {
        const auto v = vec2_make(10.f, 100.f);
        auto res = vec2_make(1.f, 2.f);
        res /= v;
        FS_CHECK(res.x == .1f && res.y == .02f);
    }

    // /= t
    {
        const auto t = 10.f;
        auto res = vec2_make(1.f, 2.f);
        res /= t;
        FS_CHECK(res.x == .1f && res.y == .2f);
    }

    // [] const
    {
        const auto res = vec2_make(1.f, 2.f);
        FS_CHECK(res[0] == res.x && res[1] == res.y);
    }

    // []
    {
        auto res = vec2_make(1.f, 2.f);
        FS_CHECK(res[0] == res.x && res[1] == res.y);
    }

    // v1 == v2
    {
        FS_CHECK(vec2_make(1.f, 2.f) == vec2_make(1.f, 2.f));
    }

    // v1 != v2
    {
        FS_CHECK(vec2_make(1.f, 2.f) != vec2_make(10.f, 20.f));
    }

    // -v
    {
        const auto v = vec2_make(1.f, 2.f);
        const auto res = -v;
        FS_CHECK(res.x == -1.f && res.y == -2.f);
    }

    // v1 + v2
    {
        const auto v1 = vec2_make(1.f, 2.f);
        const auto v2 = vec2_make(10.f, 100.f);
        const auto res = v1 + v2;
        FS_CHECK(res.x == 11.f && res.y == 102.f);
    }

    // v + t
    {
        const auto v = vec2_make(1.f, 2.f);
        const auto t = 10.f;
        const auto res = v + t;
        FS_CHECK(res.x == 11.f && res.y == 12.f);
    }

    // t + v
    {
        const auto v = vec2_make(1.f, 2.f);
        const auto t = 10.f;
        const auto res = t + v;
        FS_CHECK(res.x == 11.f && res.y == 12.f);
    }

    // v1 - v2
    {
        const auto v1 = vec2_make(1.f, 2.f);
        const auto v2 = vec2_make(10.f, 100.f);
        const auto res = v1 - v2;
        FS_CHECK(res.x == -9.f && res.y == -98.f);
    }

    // v - t
    {
        const auto v = vec2_make(1.f, 2.f);
        const auto t = 10.f;
        const auto res = v - t;
        FS_CHECK(res.x == -9.f && res.y == -8.f);
    }

    // t - v
    {
        const auto v = vec2_make(1.f, 2.f);
        const auto t = 10.f;
        const auto res = t - v;
        FS_CHECK(res.x == -9.f && res.y == -8.f);
    }

    // v1 * v2
    {
        const auto v1 = vec2_make(1.f, 2.f);
        const auto v2 = vec2_make(10.f, 100.f);
        const auto res = v1 * v2;
        FS_CHECK(res.x == 10.f && res.y == 200.f);
    }

    // v * t
    {
        const auto v = vec2_make(1.f, 2.f);
        const auto t = 10.f;
        const auto res = v * t;
        FS_CHECK(res.x == 10.f && res.y == 20.f);
    }

    // t * v
    {
        const auto v = vec2_make(1.f, 2.f);
        const auto t = 10.f;
        const auto res = t * v;
        FS_CHECK(res.x == 10.f && res.y == 20.f);
    }

    // v1 / v2
    {
        const auto v1 = vec2_make(1.f, 2.f);
        const auto v2 = vec2_make(10.f, 100.f);
        const auto res = v1 / v2;
        FS_CHECK(res.x == .1f && res.y == .02f);
    }

    // v / t
    {
        const auto v = vec2_make(1.f, 2.f);
        const auto t = 10.f;
        const auto res = v / t;
        FS_CHECK(res.x == .1f && res.y == .2f);
    }

    // t / v
    {
        const auto v = vec2_make(1.f, 2.f);
        const auto t = 10.f;
        const auto res = t / v;
        FS_CHECK(res.x == .1f && res.y == .2f);
    }
}

//--- VEC3 ---

void test_vec3() FS_NOEXCEPT
{
    using namespace fs::math;

    // vec3_make(x, y, z)
    {
        const auto res = vec3_make(1.f, 2.f, 3.f);
        FS_CHECK(res.x == 1.f && res.y == 2.f && res.z == 3.f);
    }
    
    // += v
    {
        const auto v = vec3_make(10.f, 100.f, 1000.f);
        auto res = vec3_make(1.f, 2.f, 3.f);
        res += v;
        FS_CHECK(res.x == 11.f && res.y == 102.f && res.z == 1003.f);
    }

    // += t
    {
        const auto t = 10.f;
        auto res = vec3_make(1.f, 2.f, 3.f);
        res += t;
        FS_CHECK(res.x == 11.f && res.y == 12.f && res.z == 13.f);
    }

    // -= v
    {
        const auto v = vec3_make(10.f, 100.f, 1000.f);
        auto res = vec3_make(1.f, 2.f, 3.f);
        res -= v;
        FS_CHECK(res.x == -9.f && res.y == -98.f && res.z == -997.f);
    }

    // -= t
    {
        const auto t = 10.f;
        auto res = vec3_make(1.f, 2.f, 3.f);
        res -= t;
        FS_CHECK(res.x == -9.f && res.y == -8.f && res.z == -7.f);
    }

    // *= v
    {
        const auto v = vec3_make(10.f, 100.f, 1000.f);
        auto res = vec3_make(1.f, 2.f, 3.f);
        res *= v;
        FS_CHECK(res.x == 10.f && res.y == 200.f && res.z == 3000.f);
    }

    // *= t
    {
        const auto t = 10.f;
        auto res = vec3_make(1.f, 2.f, 3.f);
        res *= t;
        FS_CHECK(res.x == 10.f && res.y == 20.f && res.z == 30.f);
    }

    // /= v
    {
        const auto v = vec3_make(10.f, 100.f, 1000.f);
        auto res = vec3_make(1.f, 2.f, 3.f);
        res /= v;
        FS_CHECK(res.x == .1f && res.y == .02f && res.z == .003f);
    }

    // /= t
    {
        const auto t = 10.f;
        auto res = vec3_make(1.f, 2.f, 3.f);
        res /= t;
        FS_CHECK(res.x == .1f && res.y == .2f && res.z == .3f);
    }

    // [] const
    {
        const auto res = vec3_make(1.f, 2.f, 3.f);
        FS_CHECK(res[0] == res.x && res[1] == res.y && res[2] == res.z);
    }

    // []
    {
        auto res = vec3_make(1.f, 2.f, 3.f);
        FS_CHECK(res[0] == res.x && res[1] == res.y && res[2] == res.z);
    }

    // v1 == v2
    {
        FS_CHECK(vec3_make(1.f, 2.f, 3.f) == vec3_make(1.f, 2.f, 3.f));
    }

    // v1 != v2
    {
        FS_CHECK(vec3_make(1.f, 2.f, 3.f) != vec3_make(10.f, 20.f, 30.f));
    }

    // -v
    {
        const auto v = vec3_make(1.f, 2.f, 3.f);
        const auto res = -v;
        FS_CHECK(res.x == -1.f && res.y == -2.f && res.z == -3.f);
    }

    // v1 + v2
    {
        const auto v1 = vec3_make(1.f, 2.f, 3.f);
        const auto v2 = vec3_make(10.f, 100.f, 1000.f);
        const auto res = v1 + v2;
        FS_CHECK(res.x == 11.f && res.y == 102.f && res.z == 1003.f);
    }

    // v + t
    {
        const auto v = vec3_make(1.f, 2.f, 3.f);
        const auto t = 10.f;
        const auto res = v + t;
        FS_CHECK(res.x == 11.f && res.y == 12.f && res.z == 13.f);
    }

    // t + v
    {
        const auto v = vec3_make(1.f, 2.f, 3.f);
        const auto t = 10.f;
        const auto res = t + v;
        FS_CHECK(res.x == 11.f && res.y == 12.f && res.z == 13.f);
    }

    // v1 - v2
    {
        const auto v1 = vec3_make(1.f, 2.f, 3.f);
        const auto v2 = vec3_make(10.f, 100.f, 1000.f);
        const auto res = v1 - v2;
        FS_CHECK(res.x == -9.f && res.y == -98.f && res.z == -997.f);
    }

    // v - t
    {
        const auto v = vec3_make(1.f, 2.f, 3.f);
        const auto t = 10.f;
        const auto res = v - t;
        FS_CHECK(res.x == -9.f && res.y == -8.f && res.z == -7.f);
    }

    // t - v
    {
        const auto v = vec3_make(1.f, 2.f, 3.f);
        const auto t = 10.f;
        const auto res = t - v;
        FS_CHECK(res.x == -9.f && res.y == -8.f && res.z == -7.f);
    }

    // v1 * v2
    {
        const auto v1 = vec3_make(1.f, 2.f, 3.f);
        const auto v2 = vec3_make(10.f, 100.f, 1000.f);
        const auto res = v1 * v2;
        FS_CHECK(res.x == 10.f && res.y == 200.f && res.z == 3000.f);
    }

    // v * t
    {
        const auto v = vec3_make(1.f, 2.f, 3.f);
        const auto t = 10.f;
        const auto res = v * t;
        FS_CHECK(res.x == 10.f && res.y == 20.f && res.z == 30.f);
    }

    // t * v
    {
        const auto v = vec3_make(1.f, 2.f, 3.f);
        const auto t = 10.f;
        const auto res = t * v;
        FS_CHECK(res.x == 10.f && res.y == 20.f && res.z == 30.f);
    }

    // v1 / v2
    {
        const auto v1 = vec3_make(1.f, 2.f, 3.f);
        const auto v2 = vec3_make(10.f, 100.f, 1000.f);
        const auto res = v1 / v2;
        FS_CHECK(res.x == .1f && res.y == .02f && res.z == .003f);
    }

    // v / t
    {
        const auto v = vec3_make(1.f, 2.f, 3.f);
        const auto t = 10.f;
        const auto res = v / t;
        FS_CHECK(res.x == .1f && res.y == .2f && res.z == .3f);
    }

    // t / v
    {
        const auto v = vec3_make(1.f, 2.f, 3.f);
        const auto t = 10.f;
        const auto res = t / v;
        FS_CHECK(res.x == .1f && res.y == .2f && res.z == .3f);
    }
}

//--- VEC4 ---

void test_vec4() FS_NOEXCEPT
{
    using namespace fs::math;

    // vec4_make(x, y, z, w)
    {
        const auto res = vec4_make(1.f, 2.f, 3.f, 4.f);
        FS_CHECK(res.x == 1.f && res.y == 2.f && res.z == 3.f && res.w == 4.f);
    }
    
    // += v
    {
        const auto v = vec4_make(10.f, 100.f, 1000.f, 10000.f);
        auto res = vec4_make(1.f, 2.f, 3.f, 4.f);
        res += v;
        FS_ASSERT(res.x == 11.f && res.y == 102.f && res.z == 1003.f && res.w == 10004.f);
    }

    // += t
    {
        const auto t = 10.f;
        auto res = vec4_make(1.f, 2.f, 3.f, 4.f);
        res += t;
        FS_ASSERT(res.x == 11.f && res.y == 12.f && res.z == 13.f && res.w == 14.f);
    }

    // -= v
    {
        const auto v = vec4_make(10.f, 100.f, 1000.f, 10000.f);
        auto res = vec4_make(1.f, 2.f, 3.f, 4.f);
        res -= v;
        FS_ASSERT(res.x == -9.f && res.y == -98.f && res.z == -997.f && res.w == -9996.f);
    }

    // -= t
    {
        const auto t = 10.f;
        auto res = vec4_make(1.f, 2.f, 3.f, 4.f);
        res -= t;
        FS_ASSERT(res.x == -9.f && res.y == -8.f && res.z == -7.f && res.w == -6.f);
    }

    // *= v
    {
        const auto v = vec4_make(10.f, 100.f, 1000.f, 10000.f);
        auto res = vec4_make(1.f, 2.f, 3.f, 4.f);
        res *= v;
        FS_ASSERT(res.x == 10.f && res.y == 200.f && res.z == 3000.f && res.w == 40000.f);
    }

    // *= t
    {
        const auto t = 10.f;
        auto res = vec4_make(1.f, 2.f, 3.f, 4.f);
        res *= t;
        FS_ASSERT(res.x == 10.f && res.y == 20.f && res.z == 30.f && res.w == 40.f);
    }

    // /= v
    {
        const auto v = vec4_make(10.f, 100.f, 1000.f, 10000.f);
        auto res = vec4_make(1.f, 2.f, 3.f, 4.f);
        res /= v;
        FS_ASSERT(res.x == .1f && res.y == .02f && res.z == .003f && res.w == .0004f);
    }

    // /= t
    {
        const auto t = 10.f;
        auto res = vec4_make(1.f, 2.f, 3.f, 4.f);
        res /= t;
        FS_ASSERT(res.x == .1f && res.y == .2f && res.z == .3f && res.w == .4f);
    }

    // [] const
    {
        const auto res = vec4_make(1.f, 2.f, 3.f, 4.f);
        FS_ASSERT(res[0] == res.x && res[1] == res.y && res[2] == res.z && res[3] == res.w);
    }

    // []
    {
        auto res = vec4_make(1.f, 2.f, 3.f, 4.f);
        FS_ASSERT(res[0] == res.x && res[1] == res.y && res[2] == res.z && res[3] == res.w);
    }

    // v1 == v2
    {
        FS_ASSERT(vec4_make(1.f, 2.f, 3.f, 4.f) == vec4_make(1.f, 2.f, 3.f, 4.f));
    }

    // v1 != v2
    {
        FS_ASSERT(vec4_make(1.f, 2.f, 3.f, 4.f) != vec4_make(10.f, 20.f, 30.f, 40.f));
    }

    // -v
    {
        const auto v = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto res = -v;
        FS_ASSERT(res.x == -1.f && res.y == -2.f && res.z == -3.f && res.w == -4.f);
    }

    // v1 + v2
    {
        const auto v1 = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto v2 = vec4_make(10.f, 100.f, 1000.f, 10000.f);
        const auto res = v1 + v2;
        FS_ASSERT(res.x == 11.f && res.y == 102.f && res.z == 1003.f && res.w == 10004.f);
    }

    // v + t
    {
        const auto v = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto t = 10.f;
        const auto res = v + t;
        FS_ASSERT(res.x == 11.f && res.y == 12.f && res.z == 13.f && res.w == 14.f);
    }

    // t + v
    {
        const auto v = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto t = 10.f;
        const auto res = t + v;
        FS_ASSERT(res.x == 11.f && res.y == 12.f && res.z == 13.f && res.w == 14.f);
    }

    // v1 - v2
    {
        const auto v1 = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto v2 = vec4_make(10.f, 100.f, 1000.f, 10000.f);
        const auto res = v1 - v2;
        FS_ASSERT(res.x == -9.f && res.y == -98.f && res.z == -997.f && res.w == -9996.f);
    }

    // v - t
    {
        const auto v = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto t = 10.f;
        const auto res = v - t;
        FS_ASSERT(res.x == -9.f && res.y == -8.f && res.z == -7.f && res.w == -6.f);
    }

    // t - v
    {
        const auto v = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto t = 10.f;
        const auto res = t - v;
        FS_ASSERT(res.x == -9.f && res.y == -8.f && res.z == -7.f && res.w == -6.f);
    }

    // v1 * v2
    {
        const auto v1 = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto v2 = vec4_make(10.f, 100.f, 1000.f, 10000.f);
        const auto res = v1 * v2;
        FS_ASSERT(res.x == 10.f && res.y == 200.f && res.z == 3000.f && res.w == 40000.f);
    }

    // v * t
    {
        const auto v = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto t = 10.f;
        const auto res = v * t;
        FS_ASSERT(res.x == 10.f && res.y == 20.f && res.z == 30.f && res.w == 40.f);
    }

    // t * v
    {
        const auto v = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto t = 10.f;
        const auto res = t * v;
        FS_ASSERT(res.x == 10.f && res.y == 20.f && res.z == 30.f && res.w == 40.f);
    }

    // v1 / v2
    {
        const auto v1 = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto v2 = vec4_make(10.f, 100.f, 1000.f, 10000.f);
        const auto res = v1 / v2;
        FS_ASSERT(res.x == .1f && res.y == .02f && res.z == .003f && res.w == .0004f);
    }

    // v / t
    {
        const auto v = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto t = 10.f;
        const auto res = v / t;
        FS_ASSERT(res.x == .1f && res.y == .2f && res.z == .3f && res.w == .4f);
    }

    // t / v
    {
        const auto v = vec4_make(1.f, 2.f, 3.f, 4.f);
        const auto t = 10.f;
        const auto res = t / v;
        FS_ASSERT(res.x == .1f && res.y == .2f && res.z == .3f && res.w == .4f);
    }
}

//--- MAT4 ---

void test_mat4() FS_NOEXCEPT
{
    using namespace fs::math;

    // mat4_make(e11 ... e44)
    {
        const auto res = mat4_make(
         11.f, 12.f, 13.f, 14.f,
         21.f, 22.f, 23.f, 24.f,
         31.f, 32.f, 33.f, 34.f,
         41.f, 42.f, 43.f, 44.f
        );
        FS_CHECK(
         res.cx.x == 11.f && res.cy.x == 12.f && res.cz.x == 13.f && res.cw.x == 14.f &&
         res.cx.y == 21.f && res.cy.y == 22.f && res.cz.y == 23.f && res.cw.y == 24.f &&
         res.cx.z == 31.f && res.cy.z == 32.f && res.cz.z == 33.f && res.cw.z == 34.f &&
         res.cx.w == 41.f && res.cy.w == 42.f && res.cz.w == 43.f && res.cw.w == 44.f
        );
    }

    // mat4_make(e11 ... e44)
    {
        const auto cx = vec4_make(11.f, 21.f, 31.f, 41.f);
        const auto cy = vec4_make(12.f, 22.f, 32.f, 42.f);
        const auto cz = vec4_make(13.f, 23.f, 33.f, 43.f);
        const auto cw = vec4_make(14.f, 24.f, 34.f, 44.f);
        const auto res = mat4_make(cx, cy, cz, cw);
        FS_CHECK(
         res.cx.x == 11.f && res.cy.x == 12.f && res.cz.x == 13.f && res.cw.x == 14.f &&
         res.cx.y == 21.f && res.cy.y == 22.f && res.cz.y == 23.f && res.cw.y == 24.f &&
         res.cx.z == 31.f && res.cy.z == 32.f && res.cz.z == 33.f && res.cw.z == 34.f &&
         res.cx.w == 41.f && res.cy.w == 42.f && res.cz.w == 43.f && res.cw.w == 44.f
        );
    }
}

// --- MAIN ---

int main(int argc, char *argv[])
{
    FS_TRACE(("[o] TEST: fs_test_math"));

    test_color3();
    test_color4();
    test_vec2();
    test_vec3();
    test_vec4();
    test_mat4();

    return 0;
}