#include <wgt45.h>

/*
==============================================================================
		      WordUp Graphics Toolkit Version 4.5
			     Demonstration Program 68b

 Same as wgt68a.c, but with shadows.

 *** PROJECT ***
 This program requires the WGT45.LIB file to be linked.

 *** DATA FILES ***
 STREET.PAL, RUN.SPR
==============================================================================
*/

unsigned char shadowtable[256]; /* Shadow table */

color pal[256];         /* The palette used for every graphic image */
block sprites[200];     /* Array of images for the running robot */

block background;       /* Holds the background scrolling image */
block work;             /* Page for constructing each frame */

int oldmode;

/* A structure which holds the scrolling values for each horizontal line */
typedef struct
  {
   long x;                /* Current x value, shifted by 8 */
   long increment;        /* fixed point increment */
  } line_scroll;
line_scroll lines[80];  /* 80 scrolling lines along the ground */

/* A simple sprite structure */
typedef struct
  {
   int x;
   int y;
   int anm;              /* Sprite number */
  } sprite;
sprite people[5];


long backx = 0;          /* X value for the scrolling rocks */
long backinc;            /* X increment for scrolling rocks */


/* Loads the graphics files, and allocates buffers */
void load_graphics (void)
{
  work = wallocblock (320, 200);
  /* Allocate a work buffer */

  wems_loadsprites (pal, "run.spr", sprites, 0, 199);
  background = wloadpak ("street.pak");
  wsetpalette (0, 255, pal);
}



/* Frees the buffers and sprites */
void free_graphics (void)
{
  wfreeblock (background);
  wfreeblock (work);
}


/* Set up the initial scrolling values */
void init_lines (void)
{
int i;
int inc;

  inc = 128;     /* slowest scrolling speed (128/256 of a pixel */

  backx = 0;     /* rocks x value */
  backinc = inc; /* rocks same speed as the ground */

  for (i = 0; i < 80; i++)
    {
     lines[i].x = 0;              /* clear out the x value */
     lines[i].increment = inc;    /* set the scroll speed */
     inc += 32;                   /* Make the next row move faster */
    }
}



/* Construct the background image */
void animate_lines (void)
{
block source1, source2;
block dest1, dest2;
block origsource, origdest;
int i;
int x;

  wcopyscreen (0, 0, 319, 51, background, 0, 0, work);
  /* Draw the moon stationary */
 
 
  x = backx >> 8;

  /* Copy the rocks */
  wcopyscreen (x, 52, 319, 119, background, 0, 52, work);
  if (x > 0)
    wcopyscreen (0, 52, x-1, 119, background, 320 - x, 52, work);

  /* Scroll the rocks */
  backx += backinc;
  if (backx >= 81920L)   /* 81920 is 320 << 8 */
    backx -= 81920L;

 
  origdest = abuf + 120 * 320l;           /* First row to copy */
  origsource = background + 120 * 320l;   /* First row to copy */

  for (i = 0; i < 80; i++)
    {
     /* Scroll this line */
     lines[i].x += lines[i].increment;
     if (lines[i].x >= 81920)   /* 81920 is 320 << 8, wraps scroll around */
       lines[i].x -= 81920;

     x = lines[i].x >> 8;
     /* Get the x coord */

     dest1 = origdest + i * 320;
     dest2 = dest1 + (319 - x);
     source1 = origsource + i * 320;
     source2 = source1 + x;


     /* Fastcopy is a function similar to memcpy, only it uses an unrolled
	dword loop for faster copying.  Source code for this routine is
	inside the wnpblock.c source file */

     /* Copy the line in two steps */
     fastcopy (dest1, source2, 320 - x);
     if (x > 0)
       fastcopy (dest2, source1, x + 1);
    }
}



/* Animates and displays the running man */
void animate_man (void)
{
block emsbl;

  people[0].anm++;
  if (people[0].anm > 29)
    people[0].anm = 0;

  /* display the shadow */
  emsbl = wems_getsprite (people[0].anm + 30, sprites);
  wputblock_shade (people[0].x, 158, emsbl, shadowtable, SHADE_SHADOW);

  /* Show the running robot */
  emsbl = wems_getsprite (people[0].anm, sprites);
  wputblock (people[0].x, people[0].y, emsbl, 1);
}


void wcreate_shadow_table (color *palette)
{
float fr, fg, fb;
long ir, ig, ib;

long absr, absg, absb;

int r,g,b;

short col;
short findcol;

unsigned long lowest;
unsigned char bestfit;
unsigned long coldif;

  for (col = 0; col < 256; col++)
    {
     fr = (float)palette[col].r * (0.5);
     fg = (float)palette[col].g * (0.5);
     fb = (float)palette[col].b * (0.5);

     ir = fr;
     ig = fg;
     ib = fb;

     lowest = 655350;
     for  (findcol = 0; findcol < 256; findcol++)
       {
	absr = abs ( (long)palette[findcol].r - ir);
	absg = abs ( (long)palette[findcol].g - ig);
	absb = abs ( (long)palette[findcol].b - ib);

	coldif = absr + absg + absb;
	if  ((coldif < lowest) && (findcol != col))
	  {
	   lowest = coldif;
	   bestfit = findcol;
	  }
       }
     shadowtable[col] = bestfit;
    }
}





void main (void)
{
  oldmode = wgetmode ();

  if (!vgadetected ())
    {
     printf ("VGA is required to run this program...");
     exit (1);
    }

  printf ("WGT Example #68a\n\n");
  printf ("This example shows how to make a scrolling image with depth.  It scrolls\n");
  printf ("each horizontal line of the ground by different amounts, the fastest\n");
  printf ("being closest to you.\n");
  printf ("\nPress any key to begin.\n");
  getch ();

  vga256 ();

  if (!wems_present ())
    {
     printf ("\n EMS not found!\n");
     exit (1);
    }
  if (!wems_init ())
    {
     printf ("\nEMS initialization error!\n");
     exit (1);
    }

  if (!wems_open (700000L / 16384L))
    {
     wsetmode (oldmode);
     printf ("\nNot enough EMS memory!\n");
     exit (1);
    }

  load_graphics ();

  init_lines ();

  /* Set the position of the running man */
  people[0].x = 120;
  people[0].y = 50;
  people[0].anm = 0;

  wcreate_shadow_table (pal);


  do {
   wsetscreen (work);
   animate_lines ();
   animate_man ();
   wnormscreen ();
//   wretrace ();
   wputblock (0, 0, work, 0);
   } while (!kbhit ());

  free_graphics ();
  wsetmode (oldmode);
}
