#include "c_efx.h"
#include "main.h"

/*
Clamp the number to two given limits.
*/
int clamp(int num, int min, int max) {
  if (num < min)
    return min;
  if (num > max)
    return max;
  return num;
}

/*
Helper function for draw_lens_flare.
*/
void flare_helper(BITMAP *bmp, fix x, fix y, fix pos, int size)
{
  int xx = x*pos + sx/2*(1-pos);
  int yy = y*pos + sy/2*(1-pos);
  drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
  draw_trans_sprite(bmp, (BITMAP *)gfxdata[FLARE1_BMP+size].dat, xx-24, yy-24);
  drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
}

/*
Draws a lens flare of an object at location (x,y) on the screen.
*/
void draw_lens_flare(BITMAP *bmp, int x, int y)
{
   if ((x < 0) || (x >= sx) || (y < 0) || (y > sy))
      return;
   flare_helper(bmp, x, y, 0.7 , 4);
   flare_helper(bmp, x, y, 0.4 , 1);
   flare_helper(bmp, x, y, 0.2 , 5);
   flare_helper(bmp, x, y, -0.4, 2);
   flare_helper(bmp, x, y, -0.9, 3);
}

/*
Helper function for lightning()
*/
void lightning_helper(BITMAP *buf, int x, int y, int d) {
  circlefill(buffer, x, y, 2, 192 );
  circlefill(buffer, x, y, 1, 190 );
  circlefill(buffer, x, y, 0, 10 );
}

/*
Draws an electricity/lightning effect between the given points.
*/
void draw_lightning(int x1, int y1, int x2, int y2) {
  int i;
  int x[10];
  int y[10];
  int dx = (x2-x1)/8;
  int dy = (y2-y1)/8;
  int var = (MAX(abs(x2-x1),abs(y2-y1)) / 5);
  if (var == 0) var = 1;
  if (var > 10) var = 10;
  x[0] = x1;
  y[0] = y1;
  x[9] = x2;
  y[9] = y2;
  for (i=1; i<9; i++) {
    x[i] = x1+(dx*i) - (var>>1) + (random()%var);
    y[i] = y1+(dy*i) - (var>>1) + (random()%var);
  }
  drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
  for (i=0; i<9; i++)
    do_line(buffer, x[i], y[i], x[i+1], y[i+1], 0, lightning_helper);
  drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
}

/*
Draws a glenzed bitmap (distortion effect)
*/
void draw_glenz( BITMAP *buf, BITMAP *bmp, int x, int y ) {
  int w = bmp->w >> 1;
  int h = bmp->h >> 1;
  int get;
  BITMAP *tmp = create_bitmap(bmp->w, bmp->h);
  clear(tmp);
  for (int i = -w; i < w; i++)
  for (int j = -h; j < h; j++) {
    if (getpixel(bmp,w+i,h+j)) {
      get = getpixel( buf, x+w+(int)(i*1.2), y+h+(int)(j*1.2) );
      if (get >= 0)
        putpixel(tmp, w+i, h+j, get);
    }
  }
  masked_blit( tmp, buf, 0, 0, x, y, bmp->w, bmp->h );
  destroy_bitmap( tmp );
}

/*
Helper function for generating an additive glow table.
*/
void add_blender(PALETTE pal, int x, int y, RGB *out)
{
  int r, g, b;
  r = (int)pal[x].r + (int)pal[y].r;
  g = (int)pal[x].g + (int)pal[y].g;
  b = (int)pal[x].b + (int)pal[y].b;
  if (out) {
   out->r = MIN(r, 63);
   out->g = MIN(g, 63);
   out->b = MIN(b, 63);
  }
}

/*
Create a transformation matrix for a wormhole type effect.
*/
void create_worm_tfx(TFX_TABLE *tfx, fixed rot, int w, int h) {
  int x, y, cx, cy, sx, sy, s, ms;
  fixed r, sinr, cosr;
  int hw = w >> 1;
  int hh = h >> 1;
  ms = (hw * hw) + (hh * h);
  for (y = 0, cy = -hh; y < h; y++, cy++) {
    sy = cy * cy;
    for (x = 0, cx = -hw; x < w; x++, cx++) {
      sx = cx * cx;
      s = sy + sx;
      r = rot - ((unsigned long) rot * s / ms);
      sinr = fsin(r);
      cosr = fcos(r);
      if (s < 576) {
        tfx->x[y][x] = clamp(hw + fixtoi(cx * cosr + cy * sinr), 0, w-1);
        tfx->y[y][x] = clamp(hh + fixtoi(cy * cosr - cx * sinr), 0, h-1);
      } else {
        tfx->x[y][x] = x;
	tfx->y[y][x] = y;
      }
    }
  }
}

void create_ripple_tfx(TFX_TABLE *tfx, int num, fixed off, int w, int h) {
  int x, y, cx, cy, sx, sy, s, ms;
  fixed ss, ns;
  int hw = w >> 1;
  int hh = h >> 1;
  ms = (hw * hw) + (hh * hh);
  for (y = 0, cy = -hh; y < h; y++, cy++) {
    sy = cy * cy;
    for (x = 0, cx = -hw; x < w; x++, cx++) {
      sx = cx * cx;
      s = sy + sx;
      ss = ftofix((double) s / ms);
      ns = ss + fsin(256 * num * ss - off) / (num * 20);
      if (ss && s < 576) {
 	tfx->x[y][x] = clamp(hw + (long) cx * ns / ss, 0, w-1);
	tfx->y[y][x] = clamp(hh + (long) cy * ns / ss, 0, h-1);
      } else {
	tfx->x[y][x] = x;
	tfx->y[y][x] = y;
      }
    }
  }
}

/*
Apply the transformation matrix.
*/
void apply_tfx(BITMAP *dest, BITMAP *src, TFX_TABLE *tfx, int sx, int sy, int w, int h) {
  int x, y, c;
  BITMAP *tbmp = create_bitmap(w,h);
  blit(dest, tbmp, sx, sy, 0, 0, w, h);
  for (y = 0; y < h; y++) {
    for (x = 0; x < w; x++) {
      c = getpixel(tbmp, tfx->x[y][x], tfx->y[y][x]);
      if (c) putpixel(dest, x+sx, y+sy, c);
    }
  }
  destroy_bitmap(tbmp);
}

/* END */
