// Copyright Contributors to the Open Shading Language project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage

#include "../common/shaders/pretty.h"


void matrix_fromto (string from, string to)
{
    matrix M, Mg;
    int ok;
    M = matrix (from, to);
    printf ("  matrix (\"%s\", \"%s\") = (%.5g)\n", from, to, pretty(M));
    ok = getmatrix (from, to, Mg);
    if (!ok || M != Mg)
        printf ("  Hey, matrix ctr didn't match getmatrix!\n");

    M = matrix (to, from);
    printf ("  matrix (\"%s\", \"%s\") = (%.5g)\n", to, from, pretty(M));
    ok = getmatrix (to, from, Mg);
    if (!ok || M != Mg)
        printf ("  Hey, matrix ctr didn't match getmatrix!\n");
}



shader
test (matrix matrixparam0 = 0,
      matrix matrixparam1 = 1,
      matrix matrixparam1m = matrix(1),
      matrix matrixparam1world = matrix("world",1))
{
    // Test parameter initialization
    printf ("Parameter initialization:\n");
    printf ("  matrixparam0  = %g\n", matrixparam0);
    printf ("  matrixparam1  = %g\n", matrixparam1);
    printf ("  matrixparam1m = %g\n", matrixparam1m);
    printf ("  matrixparam1world = %g\n", matrixparam1world);
    printf ("\n");

    // Test matrix constructors
    {
        float a = 0.1, b = 0.2, c = 0.3, d = 0.4,
            e = 0.5, f = 0.6, g = 0.7, h = 0.8,
            i = 0.9, j = 1.0, k = 1.1, l = 1.2,
            m = 1.3, n = 1.4, o = 1.5, p = 1.6;
        printf ("  matrix (%.5g) = %.5g\n", a, matrix(a));
        printf ("  matrix (%.5g, %.5g, %.5g, %.5g,  %.5g, %.5g, %.5g, %.5g,  %.5g, %.5g, %.5g, %.5g,  %.5g, %.5g, %.5g, %.5g) \n\t= %.5g\n",
                a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, 
                matrix (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p));

        printf (" varying:\n");
        a = u;
        b = v;
        printf ("  matrix (%.5g) = %.5g\n", a, matrix(a));
        printf ("  matrix (%.5g, %.5g, %.5g, %.5g,  %.5g, %.5g, %.5g, %.5g,  %.5g, %.5g, %.5g, %.5g,  %.5g, %.5g, %.5g, %.5g) \n\t= %.5g\n",
                a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, 
                matrix (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p));
    }

    // Varying versions of constructors
    { 
        float a = 1, b = 1, c = 0;
        printf ("\ntesting with spaces:\n");
        printf ("  matrix (\"shader\", %.5g) = %.5g\n",
                a, pretty(matrix("shader",a)));
        printf ("  matrix (\"shader\", %.5g, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) \n\t= %.5g\n",
                a, pretty(matrix ("shader", a, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)));
        a = u;
        printf (" varying:\n");
        printf ("  matrix (\"shader\", %.5g) = %.5g\n",
                a, pretty(matrix("shader",a)));
        printf ("  matrix (\"shader\", %.5g, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) \n\t= %.5g\n",
                a, pretty(matrix ("shader", a, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)));
    }

    // World and comomon space construction
    {
        matrix Mw = matrix ("world", 1);
        matrix Mc = matrix ("common", 1);
        printf ("  matrix (\"world\", 1) = %g\n", Mw);
        printf ("  matrix (\"common\", 1) = %g\n", Mc);
    }

    // Test "from-to" matrix construction and getmatrix calls
    {
        printf ("\nTesting matrix from-to construction:\n");
        matrix_fromto ("common", "shader");
        matrix_fromto ("common", "object");
        matrix_fromto ("shader", "object");
    }

    // Test getmatrix with an unknown space
    {
        printf ("\nTesting getmatrix for unknown space name:\n");
        matrix M;
        if (getmatrix ("foobar", "common", M))
            printf ("  found???\n");
        else
            printf ("  'foobar' matrix not found, as expected\n");
    }

    {
        matrix M = matrix ("shader", 1);
        printf ("\n\nTesting matrix component access:\n");
        printf ("  M = %.5g\n", M);
        printf ("  M[1][0..3] = %.5g %.5g %.5g %.5g\n", M[1][0], M[1][1], M[1][2], M[1][3]);
        M[1][3] = 5;
        printf ("  after M[1][3] = 5, M = %.5g\n", pretty(M));
        printf (" varying:\n");
        M[1][2] = 6+u;
        printf ("  after M[1][2] = %.5g, M = %.5g\n", 6+u, pretty(M));
    }

    {
        // Matrix arithmetic
        matrix Ident = 1;
        matrix M = matrix ("shader", 1);
        printf ("\n\nTesting matrix math:\n");
        printf ("  M = [%.5g]\n", pretty(M));
        printf ("  -M = [%.5g]\n", pretty(-M));
        printf ("  2*M = [%.5g]\n", pretty(2*M));
        printf ("  M*2 = [%.5g]\n", pretty(M*2));
        printf ("  M/2 = [%.5g]\n", pretty(M/2));
        printf ("  M*Ident = [%.5g]\n", pretty(M*Ident));
        printf ("  Ident*M = [%.5g]\n", pretty(Ident*M));
        printf ("  M*M = [%.5g]\n", pretty(M*M));
        printf ("  M/M = [%.5g]\n", pretty(M/M));
        printf ("  M/Ident = [%.5g]\n", pretty(M/Ident));
        printf ("  Ident/M = [%.5g]\n", pretty(Ident/M));
        printf ("  1/M = [%.5g]\n", pretty(1/M));
        printf ("  transpose(M) = %.5g\n", pretty(transpose(M)));
        printf ("  determinant(M) = %.5g\n", pretty(determinant(M)));
        printf ("  (M==M) ? %d\n", M == M);
        printf ("  (M!=M) ? %d\n", M != M);
        printf ("  (M==Ident) ? %d\n", M == Ident);
        printf ("  (M!=Ident) ? %d\n", M != Ident);
    }
}
