/*
==============================================================================
		      WordUp Graphics Toolkit Version 5.0
			     Demonstration Program 66

 Uses VESA routines to create a large 256 color mouse cursor in any SVGA
 mode.  The first loop will draw lines while you can move the mouse. Hit
 a key and the lines will stop.  Hit another key to quit the program.

 *** PROJECT ***
 This program requires the WGT5_WC.LIB and WVESA_WC.LIB files to be linked.

 *** DATA FILES ***
 SVGACURS.SPR
							   WATCOM C++ VERSION
==============================================================================
*/

#include <wgt5.h>
#include <wgtvesa.h>
#include <conio.h>
#include <dos.h>
#include <graph.h>


int mousestate = 1;
block mousebackground;          /* Stores what is behind the cursor */
block mouse_image[10];          /* Holds the image(s) used for the cursor */
				/* You can animate the cursor by using more
				   images in this array. */
short ox, oy;                   /* Old mouse coordinate */
char inbyte;
float xfactor, yfactor;         /* Multiply by mouse coords to get the 
				   correct ratio */

color pal[256];                 /* Our color palette */
int videomode[10];              /* Array to hold supported modes */
int totalmodes;                 /* Total number of supported VESA modes */

char vstring[7][18] = { "640  x 350  x 256",
			"640  x 400  x 256", "640  x 480  x 256", 
			"800  x 600  x 256", "1024 x 768  x 256", 
			"1280 x 1024 x 256", "1600 x 1200 x 256" };




void svga_moff (void)
/* Removes the cursor from the screen */
{
 if ((mousestate) && (mousebackground != NULL))
    {
     wvesa_putblock (ox, oy, mousebackground, 0);
     wfreeblock (mousebackground);
     mousebackground = NULL;
    }
  mousestate = 0;
}


void svga_mon (void)
/* Turns the cursor back on (not drawn until drawmouse) */
{
 mousestate = 1;
}



void svga_drawcursor_retrace (void)
/* Waits for retrace and draws the mouse cursor */
{
int cwidth, cheight;

  /* Wait for retrace */
  do {
      inbyte =  inp (0x3DA);
     } while (! (inbyte & 0x08));

  if (mousestate)
  {
    if (mousebackground != NULL)
    {
     wvesa_putblock (ox, oy, mousebackground, 0);
     wfreeblock (mousebackground);
     mousebackground = NULL;
    }
  }

  ox = (float)mouse.mx * xfactor;
  oy = (float)mouse.my * yfactor;

  cwidth = wgetblockwidth (mouse_image[0]) - 1;
  cheight = wgetblockheight (mouse_image[0]) - 1;

  if (mousestate)
    {
     mousebackground = wvesa_newblock (ox, oy, ox + cwidth, oy + cheight);

     if (mouse_image[0] != NULL)
       wvesa_putblock (ox, oy, mouse_image[0], 1);
    }

  do {
      inbyte =  inp (0x3DA);
     } while ((inbyte & 0x08));
}


void svga_drawcursor (void)
/* Draws the mouse cursor */
{
int cwidth, cheight;

  if ((mousestate) && (mousebackground != NULL))
    {
     wvesa_putblock (ox, oy, mousebackground, 0);
     wfreeblock (mousebackground);
     mousebackground = NULL;
    }

  cwidth = wgetblockwidth (mouse_image[0]) - 1;
  cheight = wgetblockheight (mouse_image[0]) - 1;

  ox = (float)mouse.mx * xfactor;
  oy = (float)mouse.my * yfactor;

  if (mousestate)
    {
     mousebackground = wvesa_newblock (ox, oy, ox + cwidth, oy + cwidth);

     if (mouse_image[0] != NULL)
       wvesa_putblock (ox, oy, mouse_image[0], 1);
    }
}


void getmodes (void)
{
  totalmodes = 0;               /* Start counter at 0 modes supported */

  /* Now find supported modes and add them to our array */
  if (wvesa_supported (V640x350))
  {
    videomode[totalmodes] = V640x350;
    totalmodes++;
  }
  if (wvesa_supported (V640x400))
  {
    videomode[totalmodes] = V640x400;
    totalmodes++;
  }
  if (wvesa_supported (V640x480))
  {
    videomode[totalmodes] = V640x480;
    totalmodes++;
  }
  if (wvesa_supported (V800x600))
  {
    videomode[totalmodes] = V800x600;
    totalmodes++;
  }
  if (wvesa_supported (V1024x768))
  {
    videomode[totalmodes] = V1024x768;
    totalmodes++;
  }
  if (wvesa_supported (V1280x1024))
  {
    videomode[totalmodes] = V1280x1024;
    totalmodes++;
  }
  if (wvesa_supported (V1600x1200))
  {
    videomode[totalmodes] = V1600x1200;
    totalmodes++;
  }
}


int which_string (int mode)
{
  /* This function simply returns a string number to display based on the
     highlighted video mode */
  switch (mode)
  {
    case V640x350   : return 0; 
    case V640x400   : return 1; 
    case V640x480   : return 2; 
    case V800x600   : return 3; 
    case V1024x768  : return 4; 
    case V1280x1024 : return 5; 
    case V1600x1200 : return 6; 
  }
  return 0;
}


int select_mode (void)
{
  int ctr;
  int done;
  int selected;
  struct rccoord endy;
  char ch;

  printf ("\nPress ENTER to selected highlighted mode, any other key advances highlight.\n");

  for (ctr = 0; ctr < totalmodes; ctr++)        /* Show supported modes */
  {
    _settextposition (13 + ctr, 1);
    _outtext (vstring[ which_string (videomode[ctr]) ]);
  }
  endy = _gettextposition ();

  selected = 0;
  done = 0;
  while (!done)
  {
    _settextcolor (12);                       /* Highlight string */
    _settextposition (13 + selected, 1);
    _outtext (vstring[ which_string (videomode[selected]) ]);
    ch = getch ();
    if (ch == 13)                               /* Abort when ENTER pressed */
      done = 1;
    else {
      while (kbhit ()) getch ();  
      _settextcolor (7);                    /* De-highlight previous */
      _settextposition (13 + selected, 1);
      _outtext (vstring[ which_string (videomode[selected]) ]);
      selected++;
      if (selected >= totalmodes)               /* Wrap around list */
	selected = 0;
    }
  }
  _settextposition (endy.row + 1, 1);

  return videomode[selected];           /* Return the selected mode */
}


void main (void)
{
int oldmode;                    /* Video mode before program was started */
int mymode = 0;                 /* Selected video mode */

  oldmode = wgetmode ();        /* Preserve our original video mode */
  if (!vgadetected ())
  {
    printf ("VGA is required to run this program...");
    exit (1);
  }

  printf ("WGT Example #66\n\n");
  printf ("This program creates a 256 color mouse cursor in SVGA.\n");
  printf ("Press any key to begin.\n");
  getch ();

  _clearscreen (_GCLEARSCREEN); /* Clear the screen */
  if (wvesa_detected ())        /* Look for VESA driver */
    printf ("SVGA detected.\n");
  else
  {
    printf ("SVGA support not found. Please check for VESA driver presence.\n");
    exit (1);
  }

  /* Display the video card maunfacturer's string */
  printf ("VESA version %x\n", VGA.VESAVersion);
  printf ("VIDEO CARD OEM STRING:\n%s\n", VGA.OEMStringPtr);
  if (VGA.VESAVersion >= 0x200)
  {
    printf ("OEM Software revision #%x\n", VGA.OemSoftwareRev);
    printf ("OEM Vendor Name: %s\n", VGA.OemVendorNamePtr);
    printf ("OEM Product Name: %s\n", VGA.OemProductNamePtr);
    printf ("OEM Product Revision: %s\n", VGA.OemProductRevPtr);
  }
    else printf ("\n\n\n\n");

  printf ("Memory on card: %dk\n", VGA.TotalMemory * 64);

  getmodes ();                           /* Find supported video modes */

  if (totalmodes == 0)
  {
    printf ("256 color SVGA modes not supported. Program aborted.\n");
    exit (1);
  }
  else
  {
    mymode = select_mode ();
  }

  if (!wvesa_getmodeinfo (mymode))
    printf ("Mode detection failed.\n");
  else
  {
    printf ("\nMode %x selected.\n\n", mymode);
    printf ("X resolution : %5d\nY resolution : %5d\n", VESAmode.XResolution, VESAmode.YResolution);
    printf ("Banks: %d\n", VESAmode.NumberOfBanks);
    printf ("Window Granularity : %d\n", VESAmode.WinGranularity);
    printf ("Window size in Kb  : %d\n", VESAmode.WinSize);
    if (VESAmode.WinAAttributes & 1 == 0)
      printf("Window A not supported\n");
    else
      printf("Window A Segment   : %x\n", VESAmode.WinASegment);
    if (VESAmode.WinBAttributes & 1 == 0)
      printf("Window B not supported\n");
    else
      printf("Window B Segment   : %x\n", VESAmode.WinBSegment);
  }

  printf ("\n\nPRESS ANY KEY TO ENTER GRAPHICS MODE\n");
  getch ();

  vga256 ();
  minit ();
  if (!wvesa_init (mymode))
  {
    printf ("Unable to initialize graphics mode.\n");
    exit (1);
  }

  /* Set the scaling factors */
  xfactor = (float)VESAmode.XResolution / 320.0;
  yfactor = (float)VESAmode.YResolution / 200.0;
  

  /* Load the cursor's image */
  wloadsprites (pal, "svgacurs.spr", mouse_image, 0, 0);
  wsetpalette (0, 255, pal);

  msetbounds (0, 0, 
    (VESAmode.XResolution - wgetblockwidth (mouse_image[0]) - 1) / xfactor,
    (VESAmode.YResolution - wgetblockheight (mouse_image[0]) - 1) / yfactor);
  /* Make sure the cursor does not go off the bottom right */
  
  wvesa_cls (0);


  /* This draw shows the mouse cursor with lines being drawn. */
  do {

      /* Wait for retrace */
      do {
	 inbyte =  inp (0x3DA);
      } while (! (inbyte & 0x08));

      svga_moff ();
      wsetcolor (rand () % 256);
      wvesa_line (0, 0, rand () % VESAmode.XResolution,
		  rand () % VESAmode.YResolution);

      svga_mon ();
      svga_drawcursor ();

       do {
	inbyte =  inp (0x3DA);
       } while ((inbyte & 0x08));
   } while (!kbhit ());


  while (kbhit ())      /* Clear out the keyboard buffer */
     getch ();

  /* This loop shows the mouse cursor with no other drawing going on. */
  do {
      svga_drawcursor_retrace ();
   } while (!kbhit ());

  wfreesprites (mouse_image, 0, 0);

  
  mdeinit ();
  wsetmode (oldmode);                    /* Return text mode */
}
