/*
 *  Copyright 1994-2022 Olivier Girondel
 *  Copyright 2019-2022 Laurent Marsac
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou 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.
 *
 *  lebiniou 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 lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include "context.h"

uint32_t version = 0;
uint32_t options = BO_DISPLACE | BO_LENS | BO_NOT_LENS;
char desc[] = "Ripple effect";
char dname[] = "Ripple";

#define RIPPLE_SIZE_MAX 50

static float *ripple = NULL;


int8_t
create(Context_t *ctx)
{
  ripple = xcalloc(RIPPLE_SIZE_MAX * HEIGHT * WIDTH, sizeof(float));

  const float s = sqrtf((WIDTH * WIDTH) + (HEIGHT * HEIGHT));

  for (int n = 0; n < RIPPLE_SIZE_MAX; n++)
    for (int j = -HHEIGHT; j < HHEIGHT; j++)
      for (int i = -HWIDTH; i < HWIDTH; i++) {
        float dist = sqrtf((i * i) + (j * j));
        float sd = sinf(dist * M_PI * n / s);
        ripple[n * HEIGHT * WIDTH + (j + HHEIGHT) * WIDTH + (i + HWIDTH)] = sd;
      }

  return 1;
}


void
destroy(Context_t *ctx)
{
  xfree(ripple);
}


void
run(Context_t *ctx)
{
  short j, i;
  const float zoom_fact = 0.9;
  const float ripple_fact = 0.1;
  static uint16_t ripple_size = 8;
  static char dir = 1;
  uint16_t di = 0, dj = 0;

  Buffer8_t *src = active_buffer(ctx);
  Buffer8_t *dst = passive_buffer(ctx);

  Buffer8_clear_border(src);

  for (j = -HHEIGHT; j < HHEIGHT; j++) {
    for (i = -HWIDTH; i < HWIDTH; i++) {

      int si = 0, sj = 0;

      float sd = ripple[ripple_size * HEIGHT * WIDTH + (j + HHEIGHT) * WIDTH + (i + HWIDTH)];
      si = (int)(di * (zoom_fact + (ripple_fact * sd)));
      sj = (int)(dj * (zoom_fact + (ripple_fact * sd)));

      if ((si < MINX) || (si > MAXX) || (sj < MINY) || (sj > MAXY)) {
        si = HWIDTH;
        sj = HHEIGHT;
      }

      set_pixel_nc(dst, di, dj, get_pixel_nc(src, si, sj));
      di++;
    }
    di = 0;
    dj++;
  }

  if (dir == 1) {
    if (++ripple_size == 49) {
      dir = -1;
    }
  } else { /* -1 */
    if (--ripple_size == 1) {
      dir = 1;
    }
  }
}
