/******************************* vesa24.cpp *********************************/
/* This Program is for demonstrating 15, 16 and 24bit colour VESA boards    */
/* capabilities. Written by Don Lewis                                       */
/* <djlewis@ualr.edu> or <djlewis@spider.ualr.edu>, Dec 92 and Jan 93       */
/* written, compiled and linked with Borlandc C++ 3.1                       */
/* This program is for purposes of demonstration only. It is not shareware. */
/* It is freeware. While Randy Buckland wrote a 256 color demo in 'C' this  */
/* program only maintains Randy's original 'C' functions for your exercise. */
/* Much credit goes to Randy Buckland for his efforts. The assembly code    */
/* vga24.asm is originally Randy Bucklands code. I have modified it heavily */
/* and am redistributing it as vga24.asm. The 'VESA24.EXE' distribution     */
/* is a compilation of 'vesa24.cpp', 'vheader.h'and 'vga24.asm'.            */
/* I hope you enjoy and further develop this code and continue to offer it  */
/* as freeware so that others might benefit from our efforts.               */
/****************************************************************************/

#include <conio.h>
#include <dos.h>
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <process.h>
#include <string.h>
#include "vheader.h" /* VESA, PCX and TARGA header info. */


#define VIDEO 0x10

struct VgaInfoBlock info;
struct ModeInfoBlock modeinfo;
struct REGPACK reg;

ReturnCurrentMode(int curmode);
void SetSvgaMode(int);
void GetSvgaInfo(void);
void ReturnSvgaMode(int);
void tone(void);
void PutPixelDemo(unsigned char);
void FillAreaDemo(unsigned char, int);


/* These r,g,b functions will work with std 256 color SVGA
   just use the 0-255 byte color value in 'r' and '0's in 'g','b'.
   Green and blue are ignored. Don Lewis */
extern "C" {void vgapoint_rgb(int row, int column,
		 unsigned char r, unsigned char g, unsigned char b);}
extern "C" {void vgaline (short row1, short col1, short row2, short col2,
		 unsigned char r, unsigned char g, unsigned char b);}
extern "C" {void vgafill (short row, short column, short width,short height,
		 unsigned char r, unsigned char g, unsigned char b);}

/* These std 256 color (only) VGA functions are still supported. */
/* Still SVGA 8bit mode functions */
extern "C" {void vgainit (short vesamode);} /* Works for any VESA mode */
extern "C" {void vgasetcolor(unsigned char[256][3], int, int);}
extern "C" {void vgapoint (short row, short column, unsigned int pixel);}
extern "C" {void vgarect (unsigned char *data, short linewidth,
	      short row, short col, short width, short height);}
/* I have'nt modified or tested these functions. Don Lewis */
extern "C" {void vgarect2 (unsigned char *data, short linewidth,
	       short row, short col, short width, short height);}
extern "C" {void vgasync ();}
extern "C" {void vgatext (short row, short col, char *text,
	      unsigned char fg, unsigned char bg);}
extern "C" {short vgagetbutton();}

/* changed to 15,16,24 bit functions, see above.*/
/* extern "C" {void vgaline (short row1, short col1, short row2, short col2,
				unsigned char pixel);}  */
/* extern "C" {void vgafill (short row, short column, short width,short height,
				unsigned char pixel);}  */


void main()
{
   unsigned char inc;
   unsigned int i,j,x,r,g,b;
   int curmode, OldMode, NewMode;
   OldMode = ReturnCurrentMode(curmode);
   printf("Enter a 15, 16 or 24bit VESA mode in (hex) ei; 110<ret>\n");
   scanf("%x", &NewMode);
   printf("At the tone. . .");
   delay(1000);
   tone();
   printf(" the present routine is finished. \n");
   printf("Hit any key (which one is that) to continue.\n");
   getch();
   vgainit (NewMode); /* use vga24.asm init function */
   GetSvgaInfo();     /* retrieves all kinda good info */
   ReturnSvgaMode(NewMode); /* retrieves even more great stuff */
   if ( modeinfo.BitsPerPixel < 15 )
   {
       SetSvgaMode(OldMode);
       printf(" Sorry, This program does not use 4 or 8 bit per pixel modes.\n");
       exit(1);
   }

   if (modeinfo.BitsPerPixel == 15)
   {
	inc = 31;
	PutPixelDemo(inc); /* plot some random pixels */
	vgafill(0,0,modeinfo.XResolution,modeinfo.YResolution,0,20,20);
	vgaline(0,0,modeinfo.YResolution,modeinfo.XResolution,31,20,31);
	vgaline(0,modeinfo.XResolution,modeinfo.YResolution,0,20,31,20);
	FillAreaDemo(inc, NewMode);
   }
   if (modeinfo.BitsPerPixel == 16)
   {
       inc = 31;
       PutPixelDemo(inc);
       vgafill(0,0,modeinfo.XResolution,modeinfo.YResolution,25,0,20);
       vgaline(0,0,modeinfo.YResolution,modeinfo.XResolution,10,50,10);
       vgaline(0,modeinfo.XResolution,modeinfo.YResolution,0,0,0,0);
       FillAreaDemo(inc, NewMode);
   }
   if (modeinfo.BitsPerPixel == 24)
   {
       inc = 255;
       PutPixelDemo(inc);
       vgafill(0,0,modeinfo.XResolution,modeinfo.YResolution,50,100,70);
       vgaline(0,0,modeinfo.YResolution,modeinfo.XResolution,150,200,150);
       vgaline(0,modeinfo.XResolution,modeinfo.YResolution,0,200,150,200);
       FillAreaDemo(inc, NewMode);
    }

/* 	Restore original video mode before program exit.  */
    SetSvgaMode(OldMode);
}
/* Get SVGA VESA information and pass back to VgaInfoBlock structure */
void GetSvgaInfo(void)
{
    reg.r_ax = 0x4F00;
    reg.r_es = FP_SEG(&info);
    reg.r_di = FP_OFF(&info);
    intr(VIDEO, &reg);

    if (reg.r_ax != 0x004f) {
	printf("Current configuration does not support GetSvgaInfo .\n");
	exit(1);
    }
}
/* Get SVGA MODE information and return to ModeInfoBlock structure */
void ReturnSvgaMode(int nmode)
{
    reg.r_ax = 0x4F01;
    reg.r_cx = nmode;
    reg.r_es = FP_SEG(&modeinfo);
    reg.r_di = FP_OFF(&modeinfo);
    intr(VIDEO, &reg);

    if (reg.r_ax != 0x004f) {
	printf("Current configuration does not support ReturnSvgaMode.\n");
	exit(1);
    }
}
/* like it says, Returns the video mode currently in use. */
ReturnCurrentMode(int curmode)
{
    reg.r_ax = 0x4F03;
    intr(VIDEO, &reg);

    if (reg.r_ax != 0x004f) {
	printf("Return current video mode failed!\n");
	exit(1);
    }
    curmode = reg.r_bx;
    return(curmode);
}
/* Sets the video card to VESA mode if it is supported */
void SetSvgaMode(int nmode)
{
    reg.r_ax = 0x4F02;
    reg.r_bx = nmode;
    intr(VIDEO, &reg);

    if (reg.r_ax != 0x004f) {
	printf("Configuration does not support VESA set VGA mode 0x%xh\n",
			nmode);
	exit(1);
    }
}
void tone(void)
{
    int i;
    for (i=440; i<=3520; i+=440)
    {
       sound(i);
       delay(100);
       nosound();
    }
}
/*									*/
/*	PUTPIXELDEMO: Display a pattern of random dots on the screen	*/
/*	and pick them back up again. From Borland's BGIDEMO.C		*/
/*	Modified by Don Lewis for Hi-color and 24 bit modes.    	*/

void PutPixelDemo(unsigned char cinc)
{
  int seed = 1958;
  int i, ginc, x, y, h, w, color[3];

  w = modeinfo.YResolution;
  h = modeinfo.XResolution;

  srand( seed );			/* Restart random # function	*/
  if ( modeinfo.BitsPerPixel == 16)
     ginc = 31;
  else
     ginc = 0;
  for( i=0 ; i<5000 ; ++i ){		/* Put 5000 pixels on screen	*/
    x = 1 + random( h - 1 );	        /* Generate a random location	*/
    y = 1 + random( w - 1 );
    color[0] = random( cinc );         /* Generate random colors       */
    color[1] = random( cinc + ginc );
    color[2] = random( cinc );
    /* Write pixel to BLACK  background	*/
    vgapoint_rgb( y, x, color[0], color[1], color[2] );
  }
  tone();
  getch();				/* Wait for user's response     */

}
void FillAreaDemo(unsigned char cinc, int mode)
{
	int i, j, ginc, xcnt, ycnt, width, height;
	ycnt = modeinfo.YResolution/2;
	xcnt = modeinfo.XResolution/2;
	width = modeinfo.XResolution/(cinc+1);
	/* adjust for more color and fewer lines */
	if (modeinfo.BitsPerPixel == 16) ginc = 2; /* make green hotter */
	else ginc = 1;
	if ( mode == 0x010F || mode == 0x112)
	    height = (ycnt-(cinc/8)) / ((cinc/8)/2);
	else
	    height = (ycnt-(cinc+1)) / ((cinc+1)/2);
	for (i=0; i<= cinc; i++)
	{
	   vgafill( 0*height,i*width,width,height,i,0,0);
	   vgafill( 1*height,i*width,width,height,0,i*ginc,0);
	   vgafill( 2*height,i*width,width,height,0,0,i);
	   vgafill( 3*height,i*width,width,height,cinc,i*ginc,0);
	   vgafill( 4*height,i*width,width,height,cinc,0,i);
	   vgafill( 5*height,i*width,width,height,0,cinc*ginc,i);
	   vgafill( 6*height,i*width,width,height,i,i*ginc,0);
	   vgafill( 7*height,i*width,width,height,0,i*ginc,i);
	   vgafill( 8*height,i*width,width,height,i,0,i);
	   vgafill( 9*height,i*width,width,height,i,cinc*ginc,cinc);
	   vgafill(10*height,i*width,width,height,cinc,i*ginc,cinc);
	   vgafill(11*height,i*width,width,height,cinc,cinc*ginc,i);
	   vgafill(12*height,i*width,width,height,i,i*ginc,cinc);
	   vgafill(13*height,i*width,width,height,cinc,i*ginc,i);
	   vgafill(14*height,i*width,width,height,i,cinc*ginc,i);
	   vgafill(15*height,i*width,width,height,i,i*ginc,i);
	   vgafill(30*height,i*width,width,height,i,0,cinc);
	   vgafill(31*height,i*width,width,height,0,i*ginc,cinc);
	   vgafill(32*height,i*width,width,height,i,cinc,0);
	}
	tone();
	getch();
/* put as many colors as we can on the screen. . . Not finished. */
/* 32k and 64k colors show too little, 16mil color mode shows too much */
	for (j=0; j<=cinc; j++)
		for (i=0; i<=cinc; i++)
		{
		vgapoint_rgb(ycnt-i,xcnt-j,0,j*ginc,i);   /* top left     */
		vgapoint_rgb(ycnt+i,xcnt-j,i,j*ginc,i);   /* bottom left  */
		vgapoint_rgb(ycnt+i,xcnt+j,j,i*ginc,i);   /* bottom right */
		vgapoint_rgb(ycnt-i,xcnt+j,j,0,i);        /* top right    */
		}
	tone();
	getch();
}
