/*
==============================================================================
		      WordUp Graphics Toolkit Version 5.0                     
			    Demonstration Program 43                          
									      
 VESA HICOLOR demonstration file. Any program which uses the WGT VESA library        
 requires the existence of a VESA driver. Most video card manufacturers      
 include software drivers with their installation diskettes. You can also    
 find drivers for most popular cards on a BBS.                               
									      
 This program demonstrates how to access and use video modes in VESA with
 more than 256 colors. In order to do this, the card must have enough memory
 to support the video modes since each pixel on the screen requires several
 bytes.
									      
 *** PROJECT ***                                                             
 This program requires the WGT5_WC.LIB and WVESA_WC.LIB files to be linked.  
									      
 *** DATA FILES ***                                                          
 None                                                           
							   WATCOM C++ VERSION 
==============================================================================
*/

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

short videomode[24];    /* Array to hold supported modes */

short modenums[24] = { 0x10d, 0x11d, 0x11e, 0x110, 0x113, 0x116,
		       0x119, 0x125, 0x10e, 0x11f, 0x120, 0x111,
		       0x114, 0x117, 0x11a, 0x126, 0x10f, 0x121,
		       0x122, 0x112, 0x115, 0x118, 0x11b, 0x127 };

int totalmodes;         /* Total number of supported VESA modes */

char vstring[24][18] = { "320  x 200  x 32k", "640  x 350  x 32k",
			 "640  x 400  x 32k", "640  x 480  x 32k",
			 "800  x 600  x 32k", "1024 x 768  x 32k",
			 "1280 x 1024 x 32k", "1600 x 1200 x 32k",
			 "320  x 200  x 64k", "640  x 350  x 64k",
			 "640  x 400  x 64k", "640  x 480  x 64k",
			 "800  x 600  x 64k", "1024 x 768  x 64k",
			 "1280 x 1024 x 64k", "1600 x 1200 x 64k",
			 "320  x 200  x 16m", "640  x 350  x 16m",
			 "640  x 400  x 16m", "640  x 480  x 16m",
			 "800  x 600  x 16m", "1024 x 768  x 16m",
			 "1280 x 1024 x 16m", "1600 x 1200 x 16m" };

short bytesperpixel;    /* Used to keep track of the # of bytes per pixel */


void getmodes (void)
{
  short counter;

  totalmodes = 0;               /* Start counter at 0 modes supported */

  /* Now find supported modes and add them to our array */
  for (counter = 0; counter < 24; counter++)
  {
    if (wvesa_supported (modenums[counter]))
    {
      videomode[totalmodes] = modenums[counter];
      totalmodes++;
    }
  }
}


/* This function simply returns a string number to display based on the
   highlighted video mode */
short which_string (int mode)
{
  short counter;

  for (counter = 0; counter < 24; counter++)
    if (modenums[counter] == mode)
      return counter;
  return 0;
}


short select_mode (void)
{
  short ctr;
  short done;
  short 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 (12 + ctr, 1);
    _outtext (vstring[ which_string(videomode[ctr]) ]);
  }
  endy = _gettextposition ();

  selected = 0;
  done = 0;
  while (!done)
  {
    _settextcolor (12);                       /* Highlight string */
    _settextposition (12 + 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 (12 + 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 hi_pixel (short x, short y, unsigned int color)
{
  int bankpos;
  block dst;

  /* Now find the offset in video ram we want to set */
  bankpos = (y * VESAmode.BytesPerScanLine) + (x * bytesperpixel);

  /* Now switch to the appropriate bank of memory in the video card */
  wvesa_bank (bankpos / VESAbanksize);

  /* Set our pointer to the visual screen (abuf) plus the offset within the
     bank that we want to set */
  dst = abuf + (bankpos % VESAbanksize);

  /* Now set it */
  memcpy (dst, &color, bytesperpixel);
}


void do_pixels (void)
{
  short x, y;
  unsigned int ctr;
  unsigned int lastcolor;

  ctr = 0;
  lastcolor = 1 << VESAmode.BitsPerPixel;
  for (x = 0; x < VESAmode.XResolution; x++)
    for (y = 0; y < VESAmode.YResolution; y++)
    {
      hi_pixel (x, y, ctr);
      ctr++;
      if (ctr > lastcolor)
	ctr = 0;
    }
  getch();
}


void load_tga(char *filename)
{
  FILE *in;
  struct {
    unsigned char  identsize;
    unsigned char  colormaptype;
    unsigned char  imagetype;
    unsigned short colormapstart;
    unsigned short colormaplength;
    unsigned char  colormapbits;
    unsigned short xstart;
    unsigned short ystart;
    unsigned short width;
    unsigned short depth;
    unsigned char  bits;
    unsigned char  descriptor;
  } TGA_Header;
  int size, ctr, bankpos;  
  unsigned int color;
  unsigned char temp;
  unsigned char *targa, *dst;
  int i;

  in = fopen (filename, "rb");
  fread (&TGA_Header, sizeof (TGA_Header), 1, in);  
  if (TGA_Header.imagetype == 2)
  {
    for (i = 1; i <= TGA_Header.identsize; i++)
      fread (&temp, 1, 1, in);
    size = TGA_Header.width * TGA_Header.depth * 3;
    targa = (unsigned char *)malloc (size);
    for (i = 0; i < size; i+= 3)
    {
      targa[i] = fgetc (in);
      targa[i + 1] = fgetc (in);
      targa[i + 2] = fgetc (in);
    }
    for (i = TGA_Header.depth - 1; i >= 0; i--)
      for (ctr = 0; ctr < TGA_Header.width; ctr++)
      {
	bankpos = (i * VESAmode.BytesPerScanLine) + (ctr * bytesperpixel);
	wvesa_bank (bankpos / VESAbanksize);
	dst = abuf + (bankpos % VESAbanksize);
	color = 0;
	memcpy (&color, targa, 3);
	memcpy (dst, &color, bytesperpixel);
	targa += 3;
      }
  }
  fclose (in);
}


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

  printf ("WGT Example #43\n\n");
  printf ("VESA SVGA and HICOLOR modes are demonstrated providing a driver is present.\n");
  printf ("Pixels are drawn in 640x480 x 16 million color mode.\n"); 
  printf ("\n\nPress any key to continue.\n");
  getch ();

  oldmode = wgetmode ();         /* Preserve our original video mode */
  _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");

  printf ("Card contains %dk of video RAM.\n", VGA.TotalMemory * 64);

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

  if (totalmodes == 0)
  {
    printf ("Hicolor 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 ("Bits per pixel: %d\n", VESAmode.BitsPerPixel);
    printf ("Bytes per scanline: %d\n", VESAmode.BytesPerScanLine);
  }

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

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

  bytesperpixel = (VESAmode.BitsPerPixel + 1) / 8;
  do_pixels ();                         /* Perform our test */
  
  /* Attempt to use 640x480x16m */
  /*
  if (wvesa_supported (0x112))
  {
    wvesa_init (0x112);
    bytesperpixel = (VESAmode.BitsPerPixel + 1) / 8;
    load_tga ("hicolor.tga");
  } 
  getch ();*/
  wsetmode (oldmode);                    /* Return text mode */
}

