#include <cogl/cogl.h>

#include "tests/cogl-test-utils.h"

#define N_TEXTURES 128

#define OPACITY_FOR_ROW(y) \
  (0xff - ((y) & 0xf) * 0x10)

#define COLOR_FOR_SIZE(size) \
  (colors + (size) % 3)

typedef struct
{
  uint8_t red, green, blue, alpha;
} TestColor;

static const TestColor colors[] =
  { { 0xff, 0x00, 0x00, 0xff },
    { 0x00, 0xff, 0x00, 0xff },
    { 0x00, 0x00, 0xff, 0xff } };

static CoglTexture *
create_texture (int size)
{
  CoglTexture *texture;
  const TestColor *color;
  uint8_t *data, *p;
  int x, y;

  /* Create a red, green or blue texture depending on the size */
  color = COLOR_FOR_SIZE (size);

  p = data = g_malloc (size * size * 4);

  /* Fill the data with the color but fade the opacity out with
     increasing y coordinates so that we can see the blending it the
     atlas migration accidentally blends with garbage in the
     texture */
  for (y = 0; y < size; y++)
    {
      int opacity = OPACITY_FOR_ROW (y);

      for (x = 0; x < size; x++)
        {
          /* Store the colors premultiplied */
          p[0] = color->red * opacity / 255;
          p[1] = color->green * opacity / 255;
          p[2] = color->blue * opacity / 255;
          p[3] = opacity;

          p += 4;
        }
    }

  texture = test_utils_texture_new_from_data (test_ctx,
                                              size, /* width */
                                              size, /* height */
                                              TEST_UTILS_TEXTURE_NONE, /* flags */
                                              /* format */
                                              COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                                              /* rowstride */
                                              size * 4,
                                              data);

  g_free (data);

  return texture;
}

static void
verify_texture (CoglTexture *texture, int size)
{
  uint8_t *data, *p;
  int x, y;
  const TestColor *color;

  color = COLOR_FOR_SIZE (size);

  p = data = g_malloc (size * size * 4);

  cogl_texture_get_data (texture,
                         COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                         size * 4,
                         data);

  for (y = 0; y < size; y++)
    {
      int opacity = OPACITY_FOR_ROW (y);

      for (x = 0; x < size; x++)
        {
          TestColor real_color =
            {
              color->red * opacity / 255,
              color->green * opacity / 255,
              color->blue * opacity / 255
            };

          test_utils_compare_pixel (p,
                                    (((guint32) real_color.red) << 24) |
                                    (((guint32) real_color.green) << 16) |
                                    (((guint32) real_color.blue) << 8) |
                                    opacity);
          g_assert_cmpint (p[3], ==, opacity);

          p += 4;
        }
    }

  g_free (data);
}

static void
test_atlas_migration (void)
{
  CoglTexture *textures[N_TEXTURES];
  int i, tex_num;

  /* Create and destroy all of the textures a few times to increase
     the chances that we'll end up reusing the buffers for previously
     discarded atlases */
  for (i = 0; i < 5; i++)
    {
      for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
        textures[tex_num] = create_texture (tex_num + 1);
      for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
        g_object_unref (textures[tex_num]);
    }

  /* Create all the textures again */
  for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
    textures[tex_num] = create_texture (tex_num + 1);

  /* Verify that they all still have the right data */
  for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
    verify_texture (textures[tex_num], tex_num + 1);

  /* Destroy them all */
  for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
    g_object_unref (textures[tex_num]);

  if (cogl_test_verbose ())
    g_print ("OK\n");
}

COGL_TEST_SUITE (
  g_test_add_func ("/atlas-migration", test_atlas_migration);
)
