#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <time.h>
#include <sys\timeb.h>
/* Gyors pixelrajzol rutinok  286-os processzorra
	[A fordtsnl ezt engedlyezni kell!  (NEM a 386-ost!!!)]
   [386-os utastskszlettel jelentsen egyszersthetk lennnek a long
    szorzsok, mert nincs tvitel, de a Borland C++ 3.1 mg bekapcsolt 386
    esetn sem fogadja el a 386-os ASM utastsokat...]
   [A drawlinepix()-nl nem kell tadni a regisztereket, ha normlisan
    van belltva a fordt.]

   Az n PCI-os S3-as videokrtymon, 486DX2/80-as gpen
   A putpix16()       1 mp. alatt 602000 kppontot rajzol ki.
   A putpixvga256()              1650000
   A putpixsvga256()              525000 ... 1330000
			[Attl fgg, mennyire esnek ugyanarra a plane-re az egyms utni pontok.]
   A vertlinesvga()              3050000
   A horizlinesvga()             3040000

   A Borland BGI (PutPixel) az n gpemen kb. 8-szor lassabb, mint putpix16(),
   az .EXE meg 4-szer akkora... :)

   if-ek nlkl putpix16() kb. mg 10%-kal gyorsabb.
*/

static char VERSION_STRING[]="Video2 v2.1.3 23/04/1998";

#define VIDEOSEG 0xA000
#define PAGEREG 0x3c4
unsigned int maxx,maxy;
unsigned char size;
char lastpage;
struct timeb t1,t2;


int putpix16(int x, int y)            // return =
                                 	  // -1: hibs koordinta
												  //	0: nem volt pixel
												  //  1: volt pixel
{
  int i;

  if ((x>=maxx) || (y>=maxy)) return -1;
  asm {
    mov ax,VIDEOSEG                       /* A video-memria szegmenscme */
    mov es,ax
    mov bx,x                              /* Az ofszet kiszmtsa */
    mov cl,bl
    mov dx,y
    shr bx,3            /* dx=x/8 */
    shl dx,4
    add bx,dx
    shl dx,2
    add bx,dx           /* bx=dx+y*80 */
    not cl                                /* A kirand rtk kiszmtsa */
    and cl,0x07         /* al=7-(x%8) */
    mov ah,1
    shl ah,cl
    test es:[bx],ah
    pushf
    pop cx
    shr cx,6
    and cx,1
    mov i,cx
    or es:[bx],ah                         /* A kppont kigyjtsa */
  }
  return i;
}

void clearpix16(int x, int y)
{
  if ((x>=maxx) || (y>=maxy)) return;
  asm {
    mov ax,VIDEOSEG                       /* A video-memria szegmenscme */
    mov es,ax
    mov bx,x                              /* Az ofszet kiszmtsa */
    mov cl,bl
    mov dx,y
    shr bx,3            /* dx=x/8 */
    shl dx,4
    add bx,dx
    shl dx,2
    add bx,dx           /* bx=dx+y*80 */
    not cl                                /* A kirand rtk kiszmtsa */
    and cl,0x07         /* al=7-(x%8) */
    mov ah,1
    shl ah,cl
    not ah
    and es:[bx],ah                        /* A kppont kioltsa */
  }
}

void putpixvga256(int x,int y,unsigned char c)     /* 320*200, 256 C */
{
  asm {
    mov ax,y
    mov bh,al
    xor bl,bl
    shl ax,6
    add bx,ax
    add bx,x      // bx=y*320 + x
    mov ax,VIDEOSEG                       /* A video-memria szegmenscme */
    mov es,ax
    mov al,c
    mov es:[bx],al
  }
}

void putpixsvga256(int x,int y,unsigned char c)     /* 640*480[400], 256 C */
{
  asm {
    mov bx,y
    shl bx,5
    mov ax,bx
    shl bx,2
    add bx,ax        // bx=y*160
    mov ax,x
    mov cx,ax
    shr ax,2
    add bx,ax        // bx=y*160+x/4
    and cl,3
    cmp lastpage,cl
    jz WriteMem
    mov lastpage,cl
    mov dx,PAGEREG
    mov ax,0x0102
    shl ah,cl
    out dx,ax
  }
WriteMem:
  asm {
    mov ax,VIDEOSEG
    mov es,ax
    mov al,c
    mov es:[bx],al
  }
}

void vertlinesvga256(int x,int y1,int y2,unsigned char c)     /* 640*480[400], 256 C */
{
  if (y1>=y2) return;
  asm {
	 mov bx,y1
	 shl bx,5
	 mov ax,bx
	 shl bx,2
	 add bx,ax        // bx=y1*160
	 mov ax,x
	 mov cx,ax
	 shr ax,2
	 add bx,ax        // bx=y1*160+x/4
	 and cl,3
	 mov dx,PAGEREG
	 mov ax,0x0102
	 shl ah,cl
	 out dx,ax
	 mov ax,VIDEOSEG
	 mov es,ax
	 mov al,c
	 mov cx,y2
	 sub cx,y1
	 inc cx
  }
Cikl:
  asm {
	 mov es:[bx],al
	 add bx,160
	 loop Cikl
  }
}

void drawlinepix(int a, int b, int c)
{
  asm {
    mov cx,c
    shr cx,2
    sub cx,b
    inc cx
    add di,b        // di=y*160+x/4
    mov ax,a
    out dx,ax
    mov ax,VIDEOSEG
    mov es,ax
    mov ax,si
    rep stosb
  }
}

void horizlinesvga256(int x1,int x2,int y,unsigned char col)     /* 640*480[400], 256 C */
{
  unsigned int s;

  if (x1>=x2-3) return;    // Minimum 4 pixeles vonal
  asm {
    mov di,y
    shl di,5
    mov ax,di
    shl di,2
    add di,ax        // di=y*160
    mov s,di
    mov dx,PAGEREG
    mov bl,col
    mov si,bx

    mov bx,x1
    add bx,3
  }
  drawlinepix(0x0102,_BX>>2,x2--);       // A 0. plane pontjainak kirajzolsa
  asm {
    mov di,s
    dec bx
  }
  drawlinepix(0x0202,_BX>>2,x2--);       // Az 1. plane pontjainak kirajzolsa
  asm {
    mov di,s
    dec bx
  }
  drawlinepix(0x0402,_BX>>2,x2--);       // A 2. plane pontjainak kirajzolsa
  asm {
    mov di,s
    dec bx
  }
  drawlinepix(0x0802,_BX>>2,x2);       // A 3. plane pontjainak kirajzolsa
}

void setmode(int mode)
{
  if (mode>=0x100) {
	 asm {
		mov ax,0x4f02
		mov bx,mode
      int 0x10
    }
  }
  else {
    asm {
      mov ax,mode
      int 0x10
    }
  }
  switch (mode) {
    case 0x0012: {
      maxx=640;
      maxy=480;
    } break;
    case 0x0013: {
      maxx=320;
      maxy=200;
    } break;
    case 0x0101: {
      maxx=640;
      maxy=409;		/* A felbonts ugyan 640*480, de egyszeren csak 409.6 sor jelezhet ki */
      lastpage=255;  /* Az els pixelnl mindenkppen legyen plane-vlts */
      asm {
	mov dx,PAGEREG
	mov al,4
	out dx,al
	inc dx
	in al,dx
	and al,0xf7
	out dx,al
	dec dx
        mov ax,0x5013
        out dx,ax
        mov ax,0x0306
        out dx,ax
      }
    } break;
  }
}


void main()
{
  int f,g,h;

/*  setmode(0x0012);             // Set video mode: 640*480, 16 color
  for (f=100; f<200; f++) for (g=100; g<200; g++) putpix16(f,g);
  for (f=100; f<200; f++) for (g=100; g<200; g++) clearpix16(f,g);
*/
/*  setmode(0x0013);            // Set video mode: 320*200, 256 color VGA
* for (h=0; h<250; h++) {
	 for (f=0; f<maxx; f++) for (g=0; g<maxy; g++) {
      putpixvga256(f,g,h);
	 }
  }
  for (h=0; h<250; h++) {
	 for (f=0; f<maxx; f++) for (g=0; g<maxy; g++) {
      putpixvga256(f,g,h);
	 }
  }
  for (h=0; h<250; h++) {
	 for (f=0; f<maxx; f++) for (g=0; g<maxy; g++) {
      putpixvga256(f,g,h);
	 }
  }
  for (h=0; h<250; h++) {
	 for (f=0; f<maxx; f++) for (g=0; g<maxy; g++) {
      putpixvga256(f,g,h);
	 }
  }
  for (f=0; f<maxx; f++) for (g=0; g<maxy; g++) putpixvga256(f,g,0);*/

  setmode(0x0101);           // Set video mode: 640*480, 256 color VESA!
/*  for (h=1; h<50; h++) {
	 for (f=0; f<maxx; f++) for (g=0; g<maxy; g++) {
		putpixsvga256(f,g,h);
//		delay(1);
	 }
  }*/
/*  for (h=0; h<50; h++) {
	 for (f=0; f<maxy; f++) for (g=0; g<maxx; g++) {
		putpixsvga256(g,f,h);
	 }
  }*/
ftime(&t1);
  for (h=0; h<250; h++) {
//	 for (f=0; f<maxx; f++) vertlinesvga256(f,0,maxy-1,h);
	 for (f=0; f<maxy; f++) horizlinesvga256(0,maxx-1,f,h);
  }
  for (h=0; h<250; h++) {
	 for (f=0; f<maxy; f++) horizlinesvga256(0,maxx-1,f,h);
  }
  for (h=0; h<250; h++) {
	 for (f=0; f<maxy; f++) horizlinesvga256(0,maxx-1,f,h);
  }
  for (h=0; h<250; h++) {
	 for (f=0; f<maxy; f++) horizlinesvga256(0,maxx-1,f,h);
  }
ftime(&t2);

  vertlinesvga256(13,123,234,12);
  vertlinesvga256(323,123,234,12);
  horizlinesvga256(13,323,123,11);
  horizlinesvga256(13,323,234,11);
  for (f=0; f<160; f++) horizlinesvga256(f,f*3,f,0);
  getch();
  setmode(0x0003);             // Set video mode: 80*25 char, color
  printf("%lf\n",0.001*(t2.millitm-t1.millitm)+(t2.time-t1.time));
}


/*
Javaslat: Ha y rtke 0 s 4095 kztti, a gyors koordinta-szmtst az
			 albbi pr sor tudja elvgezni:  [A putpix/clearpix "mov dx,y"
			 sora mg kell illeszteni.]

            not dx            // Hogy a bal als sarok legyen az orig
            and dx,0x0fff     // Korltozzuk a tartomnyt, gy nem kell IF
            mov ax,dx
            shl dx,4
            sub dx,ax      //dx=y*16-y
            shr dx,7          // dx=y*15/128=y*480/4096

	  putpixvga256:		           [A "mov ax,y" mg]
	    not ax
		 and ax,0x0fff
	    mov dx,ax
	    shl ax,1
		 add ax,dx     // ax=3*y
	    xor bx,bx
		 shl ax,3
	    rcl bx,1      // bx:ax=24*y
	    add ax,dx
	    adc bx,0      // bx:ax=25*y
	    shr bx,1
	    rcr ax,1      // ax=25*y/2
	    mov al,ah
	    xor ah,ah             // ax=y*25/512=y*200/4096

	  putpixsvga256:               [A "mov bx,y" mg]
       not bx
       and bx,0xfff
       mov dx,bx
       shl bx,1
       add bx,dx     // bx=3*y
		 xor ax,ax
       shl bx,3
       rcl ax,1      // ax:bx=24*y
		 add bx,dx
       adc ax,0      // ax:bx=25*y
       shr ax,1
       rcr bx,1      // bx=25*y/2
       shl bx,7              // bx=y*25/256=y*400/4096

       VAGY:

       mov ax,y            // !!! A mov bx,y kimarad !!!
       not ax
       and ax,0xfff
       mov bl,10
       div bl
       mov bx,ax	     // bx=y/10   -> 
			     //	a 4089 fltti (eredetileg 6 alatti) rtkek 
			     // lemaradnak !!! -> nem javasolt

*/