/*                         
 * plasma por GGI
 *
 * (C) Copyright 1998,99 by Nick Rusnov <nick@tortie.me.uiuc.edu>
 * (C) Copyright 1998,99 by Etherbox Software
 * 

 compile with: gcc -O3 -Wall -o plasma plasma.c -lm -lggi

 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <unistd.h>

#include <ggi/ggi.h>

#define MYRAND_MAX (RAND_MAX + 1.0)
#define PI 3.14157

#define XBASE 160
#define YBASE 100

/* returns a scaled random value using random */ 
int myrand(maxrand) int maxrand;{return 1+(int)((float)maxrand*random()/(MYRAND_MAX));}

ggi_visual_t myvis;
ggi_mode mymode;
ggi_pixel white;
ggi_color mycolor;

ggi_pixel mypal[1024]; 

/* holds the cosine table */
short  sintable[550], costable[550];

void gencostbl() 
{
  short foo;

  for (foo=0; foo < 550; foo++) 
    {
      /* do it */
      costable[foo]=rint(256 + 256 * cos(((float)foo / (float)512) * 2 * PI * ((float)foo / 256.0)));
      sintable[foo]=rint(256 + 256 * sin(((float)foo / (float)512) * 2 * PI * ((float)(512 - foo) / 256.0 )));
    } 
} 

void genpal()
{
  unsigned char  rc, bc, gc;
  int  r,  rmx, g,  gmx, b,  bmx;
  int i;
  ggi_color lcolor;

  /* decide what direction to grad the colours */
  rc = myrand(255);
  rc = (rc >= 128) ? 1 : 0;
  gc = myrand(255);
  gc = (gc >= 128) ? 1 : 0;
  bc = myrand(255);
  bc = (bc >= 128) ? 1 : 0;

  rmx = myrand(65535);  
  r = myrand(rmx);

  gmx = myrand(65535);
  g = myrand(gmx);

  bmx = myrand(65535);
  b = myrand(bmx);
  
  for (i = 0; i < 512; i++)
    {
      if (r >= rmx)
	{
	  rc = 0;
	  r = (r > 65535) ? 65535 : r;
	}
      if (r <= 0)
	{
	  rc = 1;
	  r = (r < 0) ? 0 : r;
	}

      if (g >= gmx)
	{
	  gc = 0;
	  g = (g > 65535) ? 65535 : g;
	}
      if (g <= 0)
	{
	  gc = 1;
	  g = (g < 0) ? 0 : g;
	}

      if (b >= bmx)
	{
	  bc = 0;
	  b = (b > 65535) ? 65535 : b;
	}
      if (b <= 0)
	{
	  bc = 1;
	  b = (b < 0) ? 0 : b;
	}

      lcolor.r = r;
      lcolor.g = g;
      lcolor.b = b;

      mypal[i] = mypal[i+512] = ggiMapColor(myvis, &lcolor);

      r = (rc) ? r+256 : r-256;
      g = (gc) ? g+256 : g-256;
      b = (bc) ? b+256 : b-256;      

    }  
}


int main(argc, argv) 
int argc;
char *argv[];
{
  short i,j;
  short mfoo,foo,mfoo2,foo2,mfoo3,foo3,mfoo4,foo4;
  short kmx, k, kt, lmx, l, lt, hmx, h, ht;
  unsigned char kc, lc, hc, fc;
  int err;

  int tilex,tiley;
#ifdef PLSM_TIME  
  time_t mtime,stime,ttime;

  mtime = 0;
#endif

  mfoo = mfoo2 = mfoo3 = mfoo4 = 0;
  fc = kc = lc = hc = 0;

  if (ggiInit())
    {
      printf("Foo! Can't init!\n");
      exit(1);  /* can't start! */
    }

  myvis = ggiOpen(NULL);
  
  if (!myvis)
    {
      ggiPanic("Foo! No visual!\n");
    }  

  /* seed the random number generator from the PID */
  if (argc > 1)
    {
      srandom(atoi(argv[1]));
    }
  else
    {
      srandom(getpid());
    }

  /* initialize GGI */
  err = ggiCheckGraphMode (myvis, GGI_AUTO, GGI_AUTO,
                           GGI_AUTO, GGI_AUTO, GT_TRUECOLOR, &mymode);
  if (err) {
    ggiClose (myvis);
    ggiExit ();
    fprintf(stderr,"Error finding working truecolor mode.");
    exit(1);
  }

  mymode.frames = 2;

  tiley = rint(mymode.visible.y / YBASE);
  tilex = rint(mymode.visible.x / XBASE);
   printf("PROPOSED MODE:\nframes: %d\nvisible x: %d y: %d\nvirtual x: %d y: %d\ngraphtype: %d (want %d)\ntile size, x: %d y: %d\n", mymode.frames,mymode.visible.x,mymode.visible.y,mymode.virt.x,mymode.virt.y,mymode.graphtype,GT_TRUECOLOR,tilex,tiley);

   if ((tiley * YBASE) != mymode.visible.y)
     {
       mymode.visible.y = tiley * YBASE;
       mymode.visible.x = tilex * XBASE;
       mymode.virt.y = mymode.virt.x = GGI_AUTO;
       printf("Trying to use %dx%d instead, to keep it right.",mymode.visible.x,mymode.visible.y);
       ggiCheckMode(myvis,&mymode);
       tiley = rint(mymode.visible.y / YBASE);
       tilex = rint(mymode.visible.x / XBASE);
       printf("PROPOSED MODE:\nframes: %d\nvisible x: %d y: %d\nvirtual x: %d y: %d\ngraphtype: %d (want %d)\ntile size, x: %d y: %d\n", mymode.frames,mymode.visible.x,mymode.visible.y,mymode.virt.x,mymode.virt.y,mymode.graphtype,GT_TRUECOLOR,tilex,tiley);
     }
      

  err = ggiSetMode (myvis, &mymode);
  if (err) {
    ggiClose (myvis);
    ggiExit ();
    fprintf(stderr,"Error setting mode.");
    exit(1);
  }

   printf("ACTUAL MODE:\nframes: %d\nvisible x: %d y: %d\nvirtual x: %d y: %d\ngraphtype: %d (want %d)\ntile size, x: %d y: %d\n", mymode.frames,mymode.visible.x,mymode.visible.y,mymode.virt.x,mymode.virt.y,mymode.graphtype,GT_TRUECOLOR,tilex,tiley);

  ggiAddFlags(myvis,GGIFLAG_ASYNC);

  ggiSetDisplayFrame(myvis,1);
  ggiSetWriteFrame(myvis,0);
  
  printf("Generating pals... \n");
  genpal();
  printf("Generating tables... \n");
  gencostbl();
  printf("done.\n");

  k = myrand(512);
  kmx = myrand(512);  
  kt = myrand(20);

  l = myrand(512);
  lmx = myrand(512);
  lt = myrand(20);
      
  h = myrand(512);
  hmx = myrand(512);
  ht = myrand(20);

  /* Main loop */
  while (!ggiKbhit(myvis))
    {
#ifdef PLSM_TIME
      stime = time(&stime);
#endif
      if (k >= kmx)
	{
	  kc = 0;
	  k = kmx;
	  kt = myrand(20);
	}
      if (k <= 0)
	{
	  kc = 1;
	  k = 0;
	  kmx = myrand(512);
	}
      
      if (l >= lmx)
	{
	  lc = 0;
	  l = lmx;
	  lt = myrand(20);
	}
      if (l <= 0)
	{
	  lc = 1;
	  l = 0;
	  lmx = myrand(512);
	}
      
      if (h >= hmx)
	{
	  hc = 0;
	  h = hmx;
	  ht = myrand(20);
	}
      if (h <= 0)
	{
	  hc = 1;
	  h = 0;
	  hmx = myrand(512);
	}
      for (j = 0; j < YBASE; j++)
	{
	  foo2 = costable[(j + l) % 512];
	  foo3 = sintable[((j + h) * 2)  % 512];
	  for (i = 0; i < XBASE; i++)
	    { 
 	      foo = costable[(i + k) % 512];
	      foo4 = costable[((i + j) *2) % 512];	  
#ifdef PLSM_BIGGEST
	      mfoo = (foo > mfoo) ? foo : mfoo;
	      mfoo2 = (foo2 > mfoo2) ? foo2 : mfoo2;
	      mfoo3 = (foo3 > mfoo3) ? foo3 : mfoo3;
	      mfoo4 = (foo4 > mfoo4) ? foo4 : mfoo4;
#endif
	      ggiSetGCForeground(myvis, mypal[(int)rint((foo+foo2+foo3+foo4) / 4)]);
	      if (tiley <= 1 && tilex <= 1)
		{
		  ggiDrawPixel(myvis, i, j);
		}
	      else
		{
		  ggiDrawBox(myvis, i*tilex, j*tiley, tilex, tiley);
/*		  ggiDrawPixel(myvis, i, j); */
		}
	    }
	}
      if (fc)
	{
	    ggiSetDisplayFrame(myvis,0);
	    ggiSetWriteFrame(myvis,1);
	    fc = 0;
	}
      else
	{
	  ggiSetDisplayFrame(myvis,1);
	  ggiSetWriteFrame(myvis,0);
	  fc = 1;
	}
      ggiFlush(myvis);
      k = (kc) ? k+kt : k-kt;
      l = (lc) ? l+lt : l-lt;
      h = (hc) ? h+ht : h-ht;
#ifdef PLSM_TIME
      ttime = time(&ttime);
      stime = ttime - stime;
      mtime = (stime > mtime) ? stime : mtime;
#endif
}
#ifdef PLSM_TIME
printf("longest frame time: %d\n", (int)mtime);
#endif
#ifdef PLSM_BIGGEST
  printf("%d %d %d %d\n",mfoo,mfoo2,mfoo3,mfoo4);
#endif
  ggiClose(myvis);
  ggiExit();

  if (argc > 1)
    {
      printf("rand seed: %d\n",atoi(argv[1]));
    }
  else
    {
      printf("rand seed: %d\n",getpid());
    }
  
  printf("done.\n");
  return 0;
}



