#include <dos.h>
#include "modex.h"

void ModeX::textMode(void)
{
	asm mov ax,03h
	asm int 10h
}

void ModeX::putPixelonVidBuf(unsigned int x,unsigned int y,unsigned int col)
{
/*setzt Punkt (x/y) auf Farbe col (Mode X)*/
	int hpagebuf=hpage;
	asm
	{
		mov ax,0a000h                 /*Segment laden*/
		mov es,ax

		mov cx,x                      /*Write Plane bestimmen*/
		and cx,3                      /*als x mov 4*/
		mov ax,1
		shl ax,cl                     /*entsprechendes Bit setzen*/
		mov ah,al
		mov dx,03c4h                  /*Timing Sequenzer*/
		mov al,2                      /*Register 2 - Write Plane Mask*/
		out dx,ax

		mov ax,80                     /*Offset = Y*80 + X div 4*/
		mul y
		mov di,ax
		mov ax,x
		shr ax,2
		add ax,hpagebuf
		add di,ax                     /*Offset laden*/
		mov al,byte ptr col           /*Farbe laden*/
		mov es:[di],al                /*und Punkt setzen*/
	}
}

void ModeX::VidBufonScr(void)
{
	int hpagebuf=hpage;
	WaitRetrace();
	asm
	{
		mov bx,hpagebuf               //Startadresse laden
		mov dx,3d4h
		mov al,0ch                    //;auf CRTC-Register 0dh/0ch aufteilen
		mov ah,bh
		out dx,ax                     //;Highbyte setzen (Register 0dh)
		inc al
		mov ah,bl
		out dx,ax                     //;Lowbyte setzen (Register 0ch)
		cmp bx,16000d                 //;Startadresse umschalten (0/16000)
		je setze0
		mov hpagebuf,16000
		jmp ende
	setze0:
		mov hpagebuf,0
	ende:
	}
	hpage=hpagebuf;
}


void ModeX::initMode(void)
{ 												       //schaltet Mode X ein
	asm
	{
		mov ax,0013h                  //Mode 13h setzen
		int 10h

		mov dx,3c4h                   //Timing Sequenzer
		mov al,4                      //Register 4 (Memory Mode):
		out dx,al                     //Bit 3 lschen -> Chain4 aus
		inc dx
		in al,dx
		and al,0f7h
		or al,4h                      //Bit 2 setzen -> Odd/Even Mode aus
		out dx,al
		dec dx

		mov ax,0f02h                  //Register 2 (Write Plane Mask):
		out dx,ax                     //0fh: alle Planes beim Schreiben ein
		mov ax,0a000h                 //Bildschirmspeicher lschen
		mov es,ax
		xor di,di
		xor ax,ax
		mov cx,0ffffh
		cld
		rep stosw

		mov dx,3d4h                   //CRTC
		mov al,14h                    //Register 14h  (Underline Row Adress):
		out dx,al
		inc dx
		in al,dx                      //Bit 6 lschen -> Doubleword adress. aus
		and al,0bfh
		out dx,al
		dec dx
		mov al,17h                    //Register 17h (CRTC Mode):
		out dx,al                     //Bit 6 setzen -> Byte Mode ein
		inc dx
		in al,dx
		or al,40h
		out dx,al
	}
}

void ModeX::onSoftBuf(unsigned char*bmp,
											unsigned int pic_size,//default: 64000
											int transparent)//default: 0
{
	if(transparent==0)
		for(unsigned int i=0; i<pic_size; i++)
			softbuf[i]=bmp[i];
	else
		for(unsigned int i=0; i<pic_size; i++)
			if(bmp[i]!=0)
				softbuf[i]=bmp[i];
}

void ModeX::onVidPage(unsigned char* bitmap,
										 unsigned int pic_size,
										 unsigned int page)
{
	pic_size/=4;

	unsigned char plane_l = 0;
	unsigned int plane_pos =FP_OFF(bitmap);

	unsigned int bmp_off=FP_OFF(bitmap);
	unsigned int bmp_seg=FP_SEG(bitmap);

	unsigned int start=page;

	asm
	{
		mov dx,03ceh                //Write Mode 0 setzen
		mov ax,4005h                //ber GDC Register 5 (GDC Mode)
		out dx,ax

		mov byte ptr plane_l,1             //Plane-Maske speichern
		push ds

		mov si,bmp_off
		mov ds,bmp_seg
//		lds si,dword ptr ds:vscreen 		 //Quelladresse laden
//		mov word ptr plane_pos,si        //und sichern
		mov ax,0a000h     			           //Zieladresse setzen
		mov es,ax
		mov di,start
		mov cx,pic_size             //Anzahl holen
lpplane:
		mov al,02h                  //TS Register 2 (Write Plane Mask)
		mov ah,byte ptr plane_l            //entsprechende Plane maskieren
		mov dx,3c4h
		out dx,ax

	lp1:
		movsb                       //Byte kopieren
		add si,3                    //auf nchstes Quellbyte positionieren
		loop lp1

		mov di,start                //Zieladresse neu holen
		inc word ptr plane_pos             //Quelladresse auf neuen Start
		mov si,word ptr plane_pos
		mov cx,pic_size             //Gráe holen
		shl byte ptr plane_l,1             //nchste Plane maskieren
		cmp byte ptr plane_l,10h           //alle 4 Planes kopiert ?
		jne lpplane

		pop ds
	}
}

void ModeX::WaitRetrace(void)
{
	asm
	{
		mov dx,3dah                   //Input Status Register 1
	wait1:
		in al,dx                      //Bit 3 wird 0 wenn Strahl beim Bildaufbau
		test al,08h
		jnz wait1
	wait2:
		in al,dx                      //Bit 3 wird 1 wenn Retrace
		test al,08h
		jz wait2
	}
}

void ModeX::setPalette(unsigned char col, unsigned char red,
											 unsigned char gre, unsigned char blu)
{
	asm mov al,col		// load palette
	asm mov dx,0x3c8	// Ignite write mode
	asm out dx,al		// store it
	asm mov dx,0x3c9	// Initialize color data
	asm mov al,red		// red color
	asm out dx,al		// store it
	asm mov al,gre		// green color
	asm out dx,al		// store it
	asm mov al,blu		// blue color
	asm out dx,al		// and store it
}

void ModeX::setPalette(unsigned char* palette)
{
	for(int i=0; i<255; i++)
	{
		setPalette(i,palette[i*3+0],palette[i*3+1],palette[i*3+2]);
	}
}

void ModeX::setStart (unsigned int row)  //setzt Bildschirmstart auf angegebene Adr.
{
	asm
	{
		mov dx,3d4h                   //CRTC
		mov al,0ch                    //Register 0ch(Linear Starting Adress Middle)
		mov ah,byte ptr row + 1         //Bits 15:8 setzen
		out dx,ax                     //Register 0dh(LSA Low)
		mov al,0dh                    //Bits 7:0 setzen
		mov ah,byte ptr row
		out dx,ax
	}
}

