/* started 9-6-90 by Matthew Cross
 *
 * Displays a moving star background on your X-display, to make it appear
 * as if your windows are moving in space....
 *
 *  WINDOWS IN SPAAAAAAAAAAAACE!!!!!
 *
 *  Dragged kicking and screaming into Xtacy 2/21/94 jpj
 *
 *  And mostly finished 5/2/94 ( yup, it's a real background job)
 */
#ifdef X
#include <X11/Xlib.h>
#include <X11/X.h>
#include "vroot.h"
#else
//#include <metawndo.h>
//#include "fakex.h"
#endif
#include <stdlib.h>
#include "trippy.h"
#include "color.h"

extern foo options;

#ifdef WINDOWS
extern HPALETTE hPal;
#endif

/* debugging, anyone? */

#define DEBUG 10

/* global defines, D_ means default */

#define D_STAR_SPEED 20  /* calculated as follows...

                           new_x = old_x + (old_x - x_center) / star_speed;
                           new_y = old_y + (old_y - y_center) / star_speed;
                         */
#define D_TURN_SPEED 18
#define D_USLEEP_TIME 10
#define D_N_STARS     100
#define D_INIT_RANGE  100
#define HIGHPREC 32
#define WAIT 1000
#define D_MAX_IND_SPEED 30
#define D_RANDOM_CHANCE 50000
#define MAX_PIXELS 5000

/* global vars */
static int inited=0;

static int star_speed = D_STAR_SPEED,
            init_range = D_INIT_RANGE,
            max_ind_speed = D_MAX_IND_SPEED;
long random_chance = D_RANDOM_CHANCE;
int n_pixels;

struct point
{
  long x,y;
  long oldx, oldy;
  int ind_speed;
  int pixel;
};

struct point **star_array_p;
short def_root, finish = 0, moveable = 0, random_move = 1, multi_color = 0;

void
init_point (struct point *pt)
{
  pt->x = rndm(init_range * 2);
  pt->y = rndm(init_range * 2);
  pt->x += (CX>>1) - init_range;
  pt->y += (CY>>1) - init_range;
  pt->x *= HIGHPREC;
  pt->y *= HIGHPREC;
  pt->oldx = pt->x;
  pt->oldy = pt->y;
  pt->ind_speed = (rndm(max_ind_speed) + 1);
  if(options.multi)
    pt->pixel = rndm(numcolors);
  else
    pt->pixel=GetNearestPaletteIndex(hPal,RGB(255,255,255)); /* WHITE */
}

void
draw_star (int winno, struct point *star)
{
  XDrawLine (display, window[winno], color_gcs[star->pixel], star->x/HIGHPREC,
             star->y/HIGHPREC, star->oldx/HIGHPREC, star->oldy/HIGHPREC);
}

void
clear_star (int winno, struct point *star)
{
  XDrawLine (display, window[winno], color_gcs[0], star->x/HIGHPREC,
             star->y/HIGHPREC, star->oldx/HIGHPREC, star->oldy/HIGHPREC);
}

int
update_star (struct point *star, int winno)
{
  long x, y;

  clear_star (winno, star);
  x = star->x; y = star->y;
  star->x = x + (x - (CX>>1)*HIGHPREC)/(star_speed + star->ind_speed);
  star->y = y + (y - (CY>>1)*HIGHPREC)/(star_speed + star->ind_speed);
  star->oldx = x; star->oldy = y;
  if(options.multi)
  {
     star->pixel = (star->pixel+1) %numcolors;
  }
  if ((star->oldx/HIGHPREC < 0) || (star->oldx/HIGHPREC > CX) ||
      (star->oldy/HIGHPREC < 0) || (star->oldy/HIGHPREC > CY))
  {
    return 1;
  }
  else
  {
    draw_star (winno, star);
  }
  return 0;
}

void
init_galaxy(int winno)
{
  int cur_star=0;  
  if(!inited)
  {
    star_array_p=(struct point **) malloc (sizeof(struct point*) * 1);
    /* options.windows); */
    if(!options.multi)
    {
      XColor col;
#ifdef WINDOWS
      if(options.tryfor!=0)
      {  resizePalette(3,FALSE); }
#endif
      col.flags=DoRed|DoGreen|DoBlue;
      col.pixel= color_gcs[1];
      col.red=col.blue=col.green=255;   /* WHITE */
      XStoreColor(display,colmap,&col);
    }
    inited=1;
  }
  
  star_array_p[winno] = (struct point *) malloc (sizeof (struct point) *
                                                 options.number);

  for (cur_star=0; cur_star<options.number; cur_star++)
  {
    init_point (&(star_array_p[winno][cur_star]));
    draw_star (winno, &(star_array_p[winno][cur_star]));
  }
}

void
exit_galaxy(int winno)
{
  if(inited)
  {
    free(star_array_p[0]);
    free(star_array_p);
    inited=0;
    if(!options.multi)
    {
#ifdef WINDOWS
        resizePalette(0,TRUE);
#endif
    }
  }
}

void
draw_stars(int winno)
{
  int cur_star=0;
  for(cur_star=0;cur_star<options.number;cur_star++)
  {
    if (update_star (&(star_array_p[winno][cur_star]), winno))
    {
      init_point (&(star_array_p[winno][cur_star]));
      draw_star (winno, &(star_array_p[winno][cur_star]));
    }
  }
}
