/*
       file name: drv.c
      written by: Jim Gage
            date: 3/28/96
         purpose: Demonstrates the use of GASM for drivers, written in
                  Borland C.  Loads driver in vesa.asm

       ** Compile with large model **
*/

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include <math.h>

/* functions that are in the driver */
  int far (far * initmode) (void);
  int far (far * switchbanks) (int);
/* where the driver is in memory */
  int * driver;

#define SCREEN_WIDTH  640L
#define SCREEN_HEIGHT 480L

void pixel(int x,int y,char c)
{
  long bank;
  unsigned int position;
  static int CurrentBank = 0;

  bank = (x + (y*SCREEN_WIDTH));
  position = bank & 0xffff;
  bank >>= 16;
  if (bank != CurrentBank)
    {
      switchbanks(bank);
      CurrentBank = bank;
    }
  *((char *)MK_FP(0xa000,position)) = c;
}

void LoadDriver(void)
{
  FILE * fpin;
  int  size;

  if (!(fpin = fopen("VESA.DRV","rb")))            /* open the driver    */
    {
      printf("Unable to load driver.\n");
      exit(1);
    }

  fread(&size,1,2,fpin);                           /* read driver size   */
  driver = (int *)malloc(size-4);                  /* get mem for driver */
  fread(driver,1,size-4,fpin);                     /* read in driver     */

  initmode = MK_FP(FP_SEG(driver),*(driver));      /* point functions to */
  switchbanks = MK_FP(FP_SEG(driver),*(driver+1)); /* driver procedures  */

  fclose(fpin);                                    /* close the file     */
}

void palette(int c,int r,int g,int b)
{
  outp(0x3c7,0xff);
  outp(0x3c8,c);
  outp(0x3c9,r>>2);
  outp(0x3c9,g>>2);
  outp(0x3c9,b>>2);
}

void SetMode(int mode)
{
  union REGS regs;

  regs.x.ax = mode;
  int86(0x10, &regs, &regs);
}

void main(void)
{
  long i,j,rot,col,
       cos1000[360],sin1000[360];    /* store fixed point cos and sin */

  LoadDriver();
  if(!initmode())    /* used to initialize the mode */
    {
      /* init failed */
      printf("Unable to init mode.\n");
      exit(1);
    }

  for (i=1;i<255;i++)              /* set video palette */
    palette(i,i,0,0);

  /* set cos and sin tables */
  for (j=0;j<360;j++)
    {
      cos1000[j] = (1+0.9*cos((j*3.14159265358)/180)) * (1<<12);
      sin1000[j] = (1+0.9*sin((j*3.14159265358)/180)) * (1<<12);
    }
  for(j=(SCREEN_HEIGHT/2)-(SCREEN_HEIGHT/3);j<(SCREEN_HEIGHT/2)+(SCREEN_HEIGHT/3);j++)
    for(i=(SCREEN_WIDTH/2)-(SCREEN_WIDTH/3);i<(SCREEN_WIDTH/2)+(SCREEN_WIDTH/3);i++)
      pixel(i,j,((sin1000[(j<<3)%360]+cos1000[(i<<3)%360])>>5)&0xff);
  col = 255;
  while(!kbhit())
    {
      for(i=1;i<256;i++)
        palette(i,((col+i)/2)%256,i%256,(col+i)%256);
      col = (col-1) & 0xff;
    }
  getch();                         /* wait for keypress */
  SetMode(3);
  free(driver);
}
