/*
 *  $Id: rgba.c 15501 2013-10-26 20:11:05Z yeti-dn $
 *  Copyright (C) 2010-2025 David Nečas (Yeti).
 *  E-mail: yeti@gwyddion.net.
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
 *  License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any
 *  later version.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 *  details.
 *
 *  You should have received a copy of the GNU General Public License along with this program; if not, write to the
 *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "tests/testlibgwy.h"

static void
serialize_and_back(GwyRGBA rgba)
{
    GwyRGBA *copy = serialize_boxed_and_back(&rgba, GWY_TYPE_RGBA, TRUE);
    g_assert_cmpfloat(rgba.r, ==, copy->r);
    g_assert_cmpfloat(rgba.g, ==, copy->g);
    g_assert_cmpfloat(rgba.b, ==, copy->b);
    g_assert_cmpfloat(rgba.a, ==, copy->a);
    g_boxed_free(GWY_TYPE_RGBA, copy);
}

void
test_rgba_boxed_serialization(void)
{
    serialize_and_back((GwyRGBA){ 0.0, 0.0, 0.0, 0.0 });
    serialize_and_back((GwyRGBA){ 0.25, 0.7, 0.64, 0.12 });
}

void
test_rgba_boxed_equal(void)
{
    GwyRGBA rgba1 = { 0.25, 0.125, 0.5, 0.75 };
    GwyRGBA rgba2 = { 0.75, 0.125, 0.5, 0.75 };
    GwyRGBA rgba3 = { 0.25, 0.75, 0.5, 0.75 };
    GwyRGBA rgba4 = { 0.25, 0.125, 0.75, 0.75 };
    GwyRGBA rgba5 = { 0.25, 0.125, 0.5, 0.25 };
    GwyRGBA rgba6 = { 0.25, 0.125, 0.5, 0.75 };

    g_assert_false(gwy_serializable_boxed_equal(GWY_TYPE_RGBA, &rgba1, &rgba2));
    g_assert_false(gwy_serializable_boxed_equal(GWY_TYPE_RGBA, &rgba1, &rgba3));
    g_assert_false(gwy_serializable_boxed_equal(GWY_TYPE_RGBA, &rgba1, &rgba4));
    g_assert_false(gwy_serializable_boxed_equal(GWY_TYPE_RGBA, &rgba1, &rgba5));
    g_assert_false(gwy_serializable_boxed_equal(GWY_TYPE_RGBA, &rgba2, &rgba3));
    g_assert_false(gwy_serializable_boxed_equal(GWY_TYPE_RGBA, &rgba2, &rgba4));
    g_assert_false(gwy_serializable_boxed_equal(GWY_TYPE_RGBA, &rgba2, &rgba5));
    g_assert_false(gwy_serializable_boxed_equal(GWY_TYPE_RGBA, &rgba3, &rgba4));
    g_assert_false(gwy_serializable_boxed_equal(GWY_TYPE_RGBA, &rgba3, &rgba5));
    g_assert_false(gwy_serializable_boxed_equal(GWY_TYPE_RGBA, &rgba4, &rgba5));
    g_assert_true(gwy_serializable_boxed_equal(GWY_TYPE_RGBA, &rgba1, &rgba6));
}

void
test_rgba_boxed_assign(void)
{
    GwyRGBA rgba1 = { 0.11, 1.0, 0.888, 0.42 };
    GwyRGBA rgba2 = { 0.25, 0.7, 0.64, 0.12 };
    GwyRGBA rgba3, rgba0;

    rgba0 = rgba1;
    gwy_serializable_boxed_assign(GWY_TYPE_RGBA, &rgba3, &rgba1);
    g_assert_cmpfloat(rgba1.r, ==, rgba0.r);
    g_assert_cmpfloat(rgba1.g, ==, rgba0.g);
    g_assert_cmpfloat(rgba3.r, ==, rgba1.r);
    g_assert_cmpfloat(rgba3.g, ==, rgba1.g);

    rgba0 = rgba2;
    gwy_serializable_boxed_assign(GWY_TYPE_RGBA, &rgba3, &rgba2);
    g_assert_cmpfloat(rgba2.r, ==, rgba0.r);
    g_assert_cmpfloat(rgba2.g, ==, rgba0.g);
    g_assert_cmpfloat(rgba3.r, ==, rgba2.r);
    g_assert_cmpfloat(rgba3.g, ==, rgba2.g);
}

static void
check_rgba_interpolation(GwyRGBA c0,
                         GwyRGBA c1,
                         gdouble x,
                         GwyRGBA expected_result)
{
    GwyRGBA result;

    gwy_rgba_interpolate(&c0, &c1, x, &result);
    g_assert_cmpfloat_with_epsilon(result.a, expected_result.a, 1e-15);
    // Compare premultiplied values.  This means if alpha == 0 anything goes.
    g_assert_cmpfloat_with_epsilon(result.a*result.r, expected_result.a*expected_result.r, 1e-15);
    g_assert_cmpfloat_with_epsilon(result.a*result.g, expected_result.a*expected_result.g, 1e-15);
    g_assert_cmpfloat_with_epsilon(result.a*result.b, expected_result.a*expected_result.b, 1e-15);
}

void
test_rgba_interpolation(void)
{
    // Opaque
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 1.0}, (GwyRGBA){1.0, 0.5, 0.0, 1.0}, 0.0,
                             (GwyRGBA){0.0, 0.5, 1.0, 1.0});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 1.0}, (GwyRGBA){1.0, 0.5, 0.0, 1.0}, 1.0,
                             (GwyRGBA){1.0, 0.5, 0.0, 1.0});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 1.0}, (GwyRGBA){1.0, 0.5, 0.0, 1.0}, 0.4,
                             (GwyRGBA){0.4, 0.5, 0.6, 1.0});

    // Equal-alpha
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.5}, (GwyRGBA){1.0, 0.5, 0.0, 0.5}, 0.0,
                             (GwyRGBA){0.0, 0.5, 1.0, 0.5});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.5}, (GwyRGBA){1.0, 0.5, 0.0, 0.5}, 1.0,
                             (GwyRGBA){1.0, 0.5, 0.0, 0.5});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.5}, (GwyRGBA){1.0, 0.5, 0.0, 0.5}, 0.4,
                             (GwyRGBA){0.4, 0.5, 0.6, 0.5});

    // Both transparent
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.0}, (GwyRGBA){1.0, 0.5, 0.0, 0.0}, 0.0,
                             (GwyRGBA){0.0, 0.5, 1.0, 0.0});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.0}, (GwyRGBA){1.0, 0.5, 0.0, 0.0}, 1.0,
                             (GwyRGBA){1.0, 0.5, 0.0, 0.0});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.0}, (GwyRGBA){1.0, 0.5, 0.0, 0.0}, 0.4,
                             (GwyRGBA){0.4, 0.5, 0.6, 0.0});

    // First transparent, second opaque
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.0}, (GwyRGBA){1.0, 0.5, 0.0, 1.0}, 0.0,
                             (GwyRGBA){0.0, 0.5, 1.0, 0.0});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.0}, (GwyRGBA){1.0, 0.5, 0.0, 1.0}, 1.0,
                             (GwyRGBA){1.0, 0.5, 0.0, 1.0});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.0}, (GwyRGBA){1.0, 0.5, 0.0, 1.0}, 0.4,
                             (GwyRGBA){1.0, 0.5, 0.0, 0.4});

    // First opaque, second transparent
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 1.0}, (GwyRGBA){1.0, 0.5, 0.0, 0.0}, 0.0,
                             (GwyRGBA){0.0, 0.5, 1.0, 1.0});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 1.0}, (GwyRGBA){1.0, 0.5, 0.0, 0.0}, 1.0,
                             (GwyRGBA){1.0, 0.5, 0.0, 0.0});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 1.0}, (GwyRGBA){1.0, 0.5, 0.0, 0.0}, 0.4,
                             (GwyRGBA){0.0, 0.5, 1.0, 0.6});

    // Arbitrary
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.4}, (GwyRGBA){1.0, 0.5, 0.0, 0.8}, 0.0,
                             (GwyRGBA){0.0, 0.5, 1.0, 0.4});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.4}, (GwyRGBA){1.0, 0.5, 0.0, 0.8}, 1.0,
                             (GwyRGBA){1.0, 0.5, 0.0, 0.8});
    check_rgba_interpolation((GwyRGBA){0.0, 0.5, 1.0, 0.4}, (GwyRGBA){1.0, 0.5, 0.0, 0.8}, 0.4,
                             (GwyRGBA){4.0/7.0, 0.5, 3.0/7.0, 0.56});
}

void
test_rgba_pixbuf_pixel_to(void)
{
    /* Tne interval [0,1] is divided into 256 equal(!) pieces and each gets assigned one integer 0..255.
     * Pixbuf pixel integers do not have internal endiannes; red is always in the upper byte. */
    g_assert_cmphex(gwy_rgba_to_pixbuf_pixel(&(GwyRGBA){ 13.5/256.0, 108.5/256.0, 66.5/256.0, 254.5/256.0 }),
                    ==, 0x0d6c42fe);
    g_assert_cmphex(gwy_rgba_to_pixbuf_pixel(&(GwyRGBA){ 13.001/256.0, 108.001/256.0, 66.001/256.0, 254.001/256.0 }),
                    ==, 0x0d6c42fe);
    g_assert_cmphex(gwy_rgba_to_pixbuf_pixel(&(GwyRGBA){ 13.999/256.0, 108.999/256.0, 66.999/256.0, 254.999/256.0 }),
                    ==, 0x0d6c42fe);
    g_assert_cmphex(gwy_rgba_to_pixbuf_pixel(&(GwyRGBA){ 0.999/256.0, 0.999/256.0, 0.999/256.0, 0.999/256.0 }),
                    ==, 0x00000000);
    g_assert_cmphex(gwy_rgba_to_pixbuf_pixel(&(GwyRGBA){ 255.999/256.0, 255.999/256.0, 255.999/256.0, 255.999/256.0 }),
                    ==, 0xffffffff);
}

void
test_rgba_pixbuf_pixel_from(void)
{
    GwyRGBA rgba;

    gwy_rgba_from_pixbuf_pixel(&rgba, 0x03c2ff44);
    g_assert_cmpfloat(rgba.r, ==, 0x03/255.0);
    g_assert_cmpfloat(rgba.g, ==, 0xc2/255.0);
    g_assert_cmpfloat(rgba.b, ==, 0xff/255.0);
    g_assert_cmpfloat(rgba.a, ==, 0x44/255.0);
}

/* vim: set cin columns=120 tw=118 et ts=4 sw=4 cino=>1s,e0,n0,f0,{0,}0,^0,\:1s,=0,g1s,h0,t0,+1s,c3,(0,u0 : */
