#include <conio.h>
#include <stdlib.h>
#include <iostream.h>
#include <dos.h>
#include <mem.h>
#include <alloc.h>
#include <time.h>
char palette[768];

void setpal(void)
 {
  int i;
  char *pal;

  pal = palette;
  for (i=0; i<32; i+=2)
   {
    *(pal++) = i;
    *(pal++) = 0;
    *(pal++) = 0;
   }
  for (i=0; i<32; i+=1)
   {
    *(pal++) = 31;
    *(pal++) = i;
    *(pal++) = 0;
   }

  for (i=0; i<32; i+=1)
   {
    *(pal++) = 31;
    *(pal++) = 31;
    *(pal++) = i;
    *(pal++) = 31;
    *(pal++) = 31;
    *(pal++) = i;
   }
  asm { mov ax,0x1012
	mov bx,0
	mov cx,256
	mov dx, offset palette;
	int 0x10
      }
 }

void setmode (void)
 {
  asm { mov ax,0x0013
	int 0x10
      }
 }

void waitvbi (void)
 {
  while (inportb(0x03da) & 0x08)
   ;
  while (!(inportb(0x03da) & 0x08))
   ;
 }

int main (void)
 {
  unsigned int I, Frames;
  time_t ITime;
  register int x;
  register int y;
  char far *Scrn,
	   *Src,
	   *ScrBuf;

  setmode();
  setpal();
  randomize();
  Frames = 0;
  Scrn = (char far *)MK_FP(0xa000,0);
  Src = (char *)malloc((unsigned)64320);
  if (!Src)
   {
    asm { mov ax,0x0003
	  int 0x10
	}
    cerr << "Unable to allocate the source buffer." << endl;
    return -1;
   }
  ScrBuf = (char *)malloc((unsigned)64320);
  if (!ScrBuf)
   {
    farfree (Src);
    asm { mov ax,0x0003
	  int 0x10
	}
    cerr << "Unable to allocate the screen buffer." << endl;
    return -1;
   }
  _fmemset(Src,0,64320);
  _fmemset(ScrBuf,0,64320);
  ITime = time(NULL);
  do
   {
    for (I=0; I < 319; ++I)                // Place a random bottom on Src.
     if ((rand() % 0x06) > 1) *(Src+64000+I) = 112;
     else *(Src+64000+I) = 0;
    for (y=140; y<201; ++y)                  // Average pixels, moving up 1 row
     for (x=1; x<319; ++x)                 // adding the decay.
       {
	*(ScrBuf+x+(((y-1)<<8)+((y-1)<<6))) = (*(Src+x-1+((y<<8)+(y<<6))) + *(Src+x+1+((y<<8)+(y<<6)))
					     +*(Src+x-1+(((y+1)<<8)+((y+1)<<6)))+ *(Src+x+(((y+1)<<8)+((y+1)<<6)))
					     +*(Src+x+1+(((y+1)<<8)+((y+1)<<6))))/5-1;
	if (*(ScrBuf+x+(((y-1)<<8)+((y-1)<<6))) < 0)
	 *(ScrBuf+x+(((y-1)<<8)+((y-1)<<6))) = 0;
       }
    waitvbi();
    _fmemcpy(Scrn+32960,ScrBuf+32000,31040);
    ++Frames;

    for (I=0; I < 319; ++I)                // Place a random bottom on Src.
     if ((rand() % 0x06) > 1) *(Src+64000+I) = 112;
     else *(Src+64000+I) = 0;

    for (y=140; y<201; ++y)                  // Average pixels, moving up 1 row
     for (x=1; x<319; ++x)                 // adding the decay.
      {
       *(Src+x+(((y-1)<<8)+((y-1)<<6))) = (*(ScrBuf+x-1+((y<<8)+(y<<6))) + *(ScrBuf+x+1+((y<<8)+(y<<6)))
					     +*(ScrBuf+x-1+(((y+1)<<8)+((y+1)<<6)))+*(ScrBuf+x+(((y+1)<<8)+((y+1)<<6)))
					     +*(ScrBuf+x+1+(((y+1)<<8)+((y+1)<<6))))/5-1;
	if (*(ScrBuf+x+(((y-1)<<8)+((y-1)<<6))) < 0)
	 *(ScrBuf+x+(((y-1)<<8)+((y-1)<<6))) = 0;
       }
    waitvbi();
    _fmemcpy(Scrn+32960,Src+32000,31040);
    ++Frames;

   }
  while (!kbhit());
  farfree (Src);
  farfree (ScrBuf);
  asm { mov ax,0x0003
	int 0x10
      }
  cout << endl << "Display rate was " << (float)Frames / (float)(time(NULL)-ITime) << " frames/second. " << endl;
  return 0;
 }