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

// struct declaration in global scope
struct Astruct {
    float f;
    int i;
    point p;
    string s;
};


struct Bstruct {
    vector v;
    float i;
};



void test_output_param (output float fout)
{
    fout = 310.5;
}


float func_with_struct_param (Astruct ap)
{
    return ap.f * 2;
}



void func_with_struct_output_param (output Astruct ap)
{
    ap.i *= 14;
}



shader
test (
    Astruct aparam = { 1.0, 0, point(3,4,5), "foo!" },
    Bstruct eparam = {}
)
{
    printf ("test struct\n");

    // Make one
    Astruct a;

    // Structure assignment
    a.f = M_PI;
    a.i = 42;
    a.p = point (0, 1, 2);
    a.s = "foobar";

    // Structure selection
    printf ("a == { %g, %i, [%g], %s }\n", a.f, a.i, a.p, a.s);

    // Test struct construction
    {
        Astruct x = Astruct (M_PI*2, 21, point(1,2,3), "constructed");
        printf ("\n");
        printf ("constructed x == { %g, %i, [%g], %s }\n", x.f, x.i, x.p, x.s);
    }

    // Make sure it came in ok as a param
    printf ("\n");
    printf ("struct param:  aparam == { %g, %i, [%g], %s }\n",
            aparam.f, aparam.i, aparam.p, aparam.s);

    // Test that empty default initializer for eparam
    printf ("Default init eparam == { %g, %g }\n", eparam.v, eparam.i);

    Bstruct b;

    // Structure assignment
    Astruct c;
    c = a;
    printf ("\n");
    printf ("after c=a, c == { %g, %i, [%g], %s }\n", c.f, c.i, c.p, c.s);

    // Structure assignment upon declaration
    Astruct d = a;
    printf ("\n");
    printf ("after Astruct d=a, d == { %g, %i, [%g], %s }\n", d.f, d.i, d.p, d.s);

    // Make sure we can address individual components of struct fields
    printf ("\n");
    printf ("components of fields: a.p = %g, a.p[1] = %g\n", a.p, a.p[1]);

    // Make sure we can pass structure elements back and forth to functions
    printf ("\n");
    printf ("Pass structure element to functions:\n");
    printf (" sqrt(a.f=%g) = %g\n", a.f, sqrt(a.f));
    a.f = sqrt(a.f);
    printf (" after 'a.f = sqrt(a.f)', a.f = %g\n", a.f);
    a.p[2] = sqrt (a.p[2]);
    printf (" after 'a.p[2] = sqrt(a.p[2])', a.p[2] = %g\n", a.p[2]);

    test_output_param (a.f);
    printf (" after writing via a function output arg, a.f = %g\n", a.f);
    test_output_param (a.p[0]);
    printf (" after writing via a function output arg, a.p = %g\n", a.p);

    {
        Astruct aa = a;
        printf ("\nPass whole struct as function argument:\n");
        float f = func_with_struct_param (aa);
        printf ("  func_with_struct_param(aa) = %g\n", f);
        func_with_struct_output_param (aa);
        printf ("  after func_with_struct_output_param(aa), aa.i = %d\n", aa.i);
    }

    // Make sure it's ok with varying
    printf ("\n\nVarying:\n");
    a.p = P;
    printf ("after a.p=P, a == { %g, %i, [%g], %s }\n", a.f, a.i, a.p, a.s);
}
