/*
    bomb - automatic interactive visual stimulation
    Copyright (C) 1994  Scott Draves <spot@cs.cmu.edu>

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "defs.h"
#include "image.h"
#include "image_db.h"

#include "bomb.h"


void
change_rules2(int old_sym, int new_sym, board_t *dst)
{
   if (sym_tile4 == old_sym &&
       sym_one == new_sym) {
      int x, y;
      for (y = 0; y <= SMALL_YSIZE; y++)
	 for (x = 0; x <= SMALL_XSIZE; x++) {
	    int t = (*dst)[x][y];
	    (*dst)[SMALL_XSIZE+x][y] = t;
	    (*dst)[x][SMALL_YSIZE+y] = t;
	    (*dst)[SMALL_XSIZE+x][SMALL_YSIZE+y] = t;
	 }
   } else if (sym_mirror4 == old_sym &&
	      sym_one == new_sym) {
      int x, y;
      for (y = 0; y <= SMALL_YSIZE; y++)
	 for (x = 0; x <= SMALL_XSIZE; x++) {
	    int t = (*dst)[x][y];
	    (*dst)[XSIZE-x][y] = t;
	    (*dst)[x][YSIZE-y] = t;
	    (*dst)[XSIZE-x][YSIZE-y] = t;
	 }
   }
}

void
pix2heat2(image8_t *fb, board_t *dst,
	  int x0, int y0, int x1, int y1)
{
   int x, y;
   int s = fb->stride;
   u_char *p = fb->p;
   for (y = y0; y < y1; y++)
      for (x = x0; x < x1; x++) {
	 int pix = p[x + y * s];
	 (*dst)[x+1][y+1] = (pix * rule.mask) >> 8;
      }
}

void
pix2heat(image8_t *fb, board_t *dst)
{
   pix2heat2(fb, dst, 0, 0, XSIZE, YSIZE);
}

void
write_fb_ppm(image8_t *fb)
{
   static int frame_num = 0;
   static u_char dbuf[YSIZE][XSIZE][3];
   int x, y;

   for (y = 0; y < YSIZE; y++) {
      u_char *fbp = fb->p + fb->stride * y;
      for (x = 0; x < XSIZE; x++) {
	 int ci = ((int) fbp[x]) * 3;
	 /* should rebuild original 8 bit cmap */
	 dbuf[y][x][0] = current_cmap[ci]<<2;
	 dbuf[y][x][1] = current_cmap[ci+1]<<2;
	 dbuf[y][x][2] = current_cmap[ci+2]<<2;
      }
   }

   if (1) {
      char fname[40];
      FILE *o;
      frame_num++;
      sprintf(fname, "dribble/%03d.ppm", frame_num);
      if (NULL != (o = fopen(fname, "w"))) {
	 /* put parms in comment */
	 fprintf(o, "P6\n%d %d\n255\n", XSIZE, YSIZE);
	 fwrite(dbuf, 3, XSIZE * YSIZE, o);
	 fclose(o);
      } else
	 fprintf(stderr, "can't open %s\n", fname);
   }
}

/* returns true if the screen is `boring'.  should use
   much more sophisticated analysis, but ... */
int
run_hist(image8_t *fb)
{
#define nsamp 3000
#define nframes 30
   static int samples = 0;
   static int hist[nsamp];
   static int sum = 0;
   int i;

   for (i = 0; i < (nsamp/nframes); i++) {
      u_char p = fb->p[fb->stride * (R%fb->height) + (R%fb->width)];
      hist[samples++] = p;
      sum += p;
   }

   if (samples >= nsamp) {
      double avg = sum / (double) nsamp;
      double var = 0;
      for (i = 0; i < nsamp; i++) {
	 double t = avg - hist[i];
	 var += t * t;
      }
      var = var / samples;
      samples = 0;
      sum = 0;
      /* fprintf(stderr, "var = %g\n", var); */
      if (var < 10.0) {
	 return 1;
      }
   }
   return 0;
}

int iclamp(int p, int n)
{
   if (p < 0)
      p = -p;
   return p%n;
}

void
cool(image8_t *fb)
{
   int i, j;
   for (j = 0; j < fb->height; j++) {
      u_char *p = &fb->p[j * fb->stride];
      for (i = 0; i < fb->width; i++)
	 p[i] = p[i] * 0.9;
   }
}

void
warm(image8_t *fb)
{
   int i, j;
   for (j = 0; j < fb->height; j++) {
      u_char *p = &fb->p[j * fb->stride];
      for (i = 0; i < fb->width; i++) {
	 int t = p[i] * 1.11111;
	 p[i] = (t > 255) ? 255 : t;
      }
   }
}




void
fill_board(fill_t *p)
{
   int r,g,b,x,y;
   board_t *dst;

   dst = &board[dbuf];

   /* there are bugs in the boundary conditions of this code */

   switch (p->fill) {
    case fill_hramp:
      for (y = 1; y <= YSIZE; y++)
	 for (x = 1; x <= XSIZE; x++)
	    (*dst)[x][y] = (x * 255) / XSIZE;
      break;
    case fill_vramp:
      for (y = 1; y <= YSIZE; y++)
	 for (x = 1; x <= XSIZE; x++)
	    (*dst)[x][y] = (y * 255) / YSIZE;
      break;
    case fill_grid:
      for (y = 1; y <= YSIZE; y++)
	 for (x = 1; x <= XSIZE; x++)
	    (*dst)[x][y] =
	       ((x * 16) / XSIZE) |
		  (((y * 16) / YSIZE) << 4);
      break;
    case fill_noise:
      for (y = 1; y <= YSIZE; y++)
	 for (x = 1; x <= XSIZE; x++)
	    (*dst)[x][y] = R;
      break;
    case fill_vnoise:
      for (y = 1; y <= YSIZE; y++)
	 for (x = 1; x <= XSIZE/2; x++)
	    (*dst)[x][y] = (*dst)[XSIZE-x][y] = R;
      break;
    case fill_sparse:
      for (y = 1; y <= YSIZE; y++)
	 for (x = 1; x <= XSIZE/2; x++)
	    (*dst)[x][y] = (*dst)[XSIZE-x][y] = R & R & R & R;
      break;
   }

   /* XXX */
   if (rule_rug_image == rule.rule) {
      drive_with_image(current_image);
   } else {
      for (x = 1; x <= XSIZE; x++)
	 for (y = 1; y <= YSIZE; y++)
	    board2[dbuf][x][y] = R;
   }
}
