;-----------------------------------------------------------------------
; MODULE XMAIN
;
; Initialization, panning and split screen functions for all MODE X 256
; Color resolutions
;
; Compile with Tasm.
; C callable.
;
;
; ****** XLIB - Mode X graphics library                ****************
; ******                                               ****************
; ****** Written By Themie Gouthas                     ****************
;
; egg@dstos3.dsto.gov.au
; teg@bart.dsto.gov.au
;
; MODIFICATIONS:
;  26-9-92:          Pel panning code added
;  Dates forgotten:  Numerous ;^)
;  05-10-93:         Timer synchronized vsync handling extensions
;                      and tripple buffering - Tore Jahn Bastiansen
;                      (toreba@ifi.uio.no) for the
;-----------------------------------------------------------------------
include xlib.inc
include xmain.inc


	_DATA		SEGMENT	WORD PUBLIC USE16 'DATA'
;.data


; Mode X CRTC register tweaks for various resolutions


X256Y200 LABEL word
		db      0e3h    ; dot clock
		db      8       ; Number of CRTC Registers to update
	dw      05f00h  ; horz total
	dw      03f01h  ; horz displayed
	dw      04202h  ; start horz blanking
	dw      09f03h  ; end horz blanking
	dw      04c04h  ; start h sync
	dw      00005h  ; end h sync
	dw      00014h  ; turn off dword mode
	dw      0e317h  ; turn on byte mode
	dw      256
	dw      200


X256Y240 label word
	db      0e3h    ; dot clock
	db      16      ; Number of CRTC Registers to update
	dw      05f00h  ; horz total
	dw      03f01h  ; horz displayed
	dw      04202h  ; start horz blanking
	dw      09f03h  ; end horz blanking
	dw      04c04h  ; start h sync
	dw      00005h  ; end h sync
	dw      00d06h  ; vertical total
	dw      03e07h  ; overflow (bit 8 of vertical counts)
	dw      04109h  ; cell height (2 to double-scan)
	dw      0ea10h  ; v sync start
	dw      0ac11h  ; v sync end and protect cr0-cr7
	dw      0df12h  ; vertical displayed
	dw      00014h  ; turn off dword mode
	dw      0e715h  ; v blank start
	dw      00616h  ; v blank end
	dw      0e317h  ; turn on byte mode
	dw      256
		dw      240


X320Y200 label  word
	db      00      ; 0e3h    ; dot clock
	db      02      ; Number of CRTC Registers to update
	dw      00014h  ; turn off dword mode
	dw      0e317h  ; turn on byte mode
	dw      320     ; width
	dw      200     ; height

X320Y240 label  word
	db      0e3h    ; dot clock
	db      10      ; Number of CRTC Registers to update
	dw      00d06h  ; vertical total
	dw      03e07h  ; overflow (bit 8 of vertical counts)
	dw      04109h  ; cell height (2 to double-scan)
	dw      0ea10h  ; v sync start
	dw      0ac11h  ; v sync end and protect cr0-cr7
	dw      0df12h  ; vertical displayed
	dw      00014h  ; turn off dword mode
	dw      0e715h  ; v blank start
	dw      00616h  ; v blank end
	dw      0e317h  ; turn on byte mode
	dw      320     ; width
	dw      240     ; height

X360Y200 label  word
	db      0e7h    ; dot clock
	db      08      ; Number of CRTC Registers to update
	dw      06b00h  ; horz total
	dw      05901h  ; horz displayed
	dw      05a02h  ; start horz blanking
	dw      08e03h  ; end horz blanking
	dw      05e04h  ; start h sync
	dw      08a05h  ; end h sync
	dw      00014h  ; turn off dword mode
	dw      0e317h  ; turn on byte mode
	dw      360     ; width
	dw      200     ; height

X360Y240  label word
	db      0e7h    ; dot clock
	db      17      ; Number of CRTC Registers to update
	dw      06b00h  ; horz total
	dw      05901h  ; horz displayed
	dw      05a02h  ; start horz blanking
	dw      08e03h  ; end horz blanking
	dw      05e04h  ; start h sync
	dw      08a05h  ; end h sync
	dw      00d06h  ; vertical total
	dw      03e07h  ; overflow (bit 8 of vertical counts)
	dw      04109h  ; cell height (2 to double-scan)
	dw      0ea10h  ; v sync start
	dw      0ac11h  ; v sync end and protect cr0-cr7
	dw      0df12h  ; vertical displayed
	dw      02d13h  ; offset;
	dw      00014h  ; turn off dword mode
	dw      0e715h  ; v blank start
	dw      00616h  ; v blank end
	dw      0e317h  ; turn on byte mode
	dw      360
	dw      240

X376Y282 label word
	db      0e7h
	db      18
	dw      06e00h  ; horz total
	dw      05d01h  ; horz displayed
	dw      05e02h  ; start horz blanking
	dw      09103h  ; end horz blanking
	dw      06204h  ; start h sync
	dw      08f05h  ; end h sync
	dw      06206h  ; vertical total
	dw      0f007h  ; overflow
	dw      06109h  ; cell height
	dw      0310fh  ;
	dw      03710h  ; v sync start
	dw      08911h  ; v sync end and protect cr0-cr7
	dw      03312h  ; vertical displayed
	dw      02f13h  ; offset
	dw      00014h  ; turn off dword mode
	dw      03c15h  ; v blank start
	dw      05c16h  ; v blank end
	dw      0e317h  ; turn on byte mode
	dw      376
	dw      282

X256Y400 label word
	db      0e3h    ; dot clock
	db      8       ; Number of CRTC Registers to update
	dw      05f00h  ; horz total
	dw      03f01h  ; horz displayed
	dw      04202h  ; start horz blanking
	dw      09f03h  ; end horz blanking
	dw      04c04h  ; start h sync
	dw      00005h  ; end h sync
	dw      04009h  ; cell height
	dw      00014h  ; turn off dword mode
	dw      0e317h  ; turn on byte mode
	dw      256
	dw      400


X256Y480 label word
	db      0e3h    ; dot clock
	db      16      ; Number of CRTC Registers to update
		dw      05f00h  ; horz total
		dw      03f01h  ; horz displayed
	dw      04202h  ; start horz blanking
	dw      09f03h  ; end horz blanking
	dw      04c04h  ; start h sync
	dw      00005h  ; end h sync
	dw      00d06h  ; vertical total
	dw      03e07h  ; overflow (bit 8 of vertical counts)
	dw      04009h  ; cell height (2 to double-scan)
	dw      0ea10h  ; v sync start
	dw      0ac11h  ; v sync end and protect cr0-cr7
	dw      0df12h  ; vertical displayed
	dw      00014h  ; turn off dword mode
	dw      0e715h  ; v blank start
	dw      00616h  ; v blank end
	dw      0e317h  ; turn on byte mode
	dw      256
	dw      480



X320Y400 label  word
	db      0e3h    ; dot clock
	db      03      ; Number of CRTC Registers to update
	dw      04009h  ; cell height
	dw      00014h  ; turn off dword mode
	dw      0e317h  ; turn on byte mode
	dw      320     ; width
	dw      400     ; height

X320Y480 label  word
	db      0e3h    ; dotclock
	db      10      ; Number of CRTC Registers to update
	dw      00d06h  ; vertical total
	dw      03e07h  ; overflow (bit 8 of vertical counts)
	dw      04009h  ; cell height (2 to double-scan)
	dw      0ea10h  ; v sync start
	dw      0ac11h  ; v sync end and protect cr0-cr7
	dw      0df12h  ; vertical displayed
	dw      00014h  ; turn off dword mode
	dw      0e715h  ; v blank start
	dw      00616h  ; v blank end
	dw      0e317h  ; turn on byte mode
	dw      320     ; width
	dw      480     ; height

X360Y400 label  word
	db      0e7h    ; dot clock
	db      09      ; Number of CRTC Registers to update
	dw      06b00h  ; horz total
	dw      05901h  ; horz displayed
	dw      05a02h  ; start horz blanking
	dw      08e03h  ; end horz blanking
	dw      05e04h  ; start h sync
	dw      08a05h  ; end h sync
	dw      04009h  ; cell height
	dw      00014h  ; turn off dword mode
	dw      0e317h  ; turn on byte mode
	dw      360     ; width
	dw      400     ; height



X360Y480  label word
	db      0e7h
	db      17
	dw      06b00h  ; horz total
	dw      05901h  ; horz displayed
	dw      05a02h  ; start horz blanking
	dw      08e03h  ; end horz blanking
	dw      05e04h  ; start h sync
	dw      08a05h  ; end h sync
	dw      00d06h  ; vertical total
	dw      03e07h  ; overflow
	dw      04009h  ; cell height
	dw      0ea10h  ; v sync start
	dw      0ac11h  ; v sync end and protect cr0-cr7
	dw      0df12h  ; vertical displayed
	dw      02d13h  ; offset
	dw      00014h  ; turn off dword mode
	dw      0e715h  ; v blank start
	dw      00616h  ; v blank end
	dw      0e317h  ; turn on byte mode
	dw      360
	dw      480

X360Y360  label word
	db      0e7h
	db      15
	dw      06b00h  ; horz total
	dw      05901h  ; horz displayed
	dw      05a02h  ; start horz blanking
	dw      08e03h  ; end horz blanking
	dw      05e04h  ; start h sync
	dw      08a05h  ; end h sync
	dw      04009h  ; cell height
	dw      08810h  ; v sync start
	dw      08511h  ; v sync end and protect cr0-cr7
	dw      06712h  ; vertical displayed
	dw      02d13h  ; offset
	dw      00014h  ; turn off dword mode
	dw      06d15h  ; v blank start
	dw      0ba16h  ; v blank end
	dw      0e317h  ; turn on byte mode
	dw      360
	dw      360


X376Y308 label word
	db      0e7h
	db      18
	dw      06e00h  ; horz total
	dw      05d01h  ; horz displayed
	dw      05e02h  ; start horz blanking
	dw      09103h  ; end horz blanking
	dw      06204h  ; start h sync
	dw      08f05h  ; end h sync
	dw      06206h  ; vertical total
	dw      00f07h  ; overflow
	dw      04009h  ;
	dw      0310fh  ;
	dw      03710h  ; v sync start
	dw      08911h  ; v sync end and protect cr0-cr7
	dw      03312h  ; vertical displayed
	dw      02f13h  ; offset
	dw      00014h  ; turn off dword mode
	dw      03c15h  ; v blank start
	dw      05c16h  ; v blank end
	dw      0e317h  ; turn on byte mode
	dw      376
	dw      308

X376Y564 label word
	db      0e7h
	db      18
	dw      06e00h  ; horz total
	dw      05d01h  ; horz displayed
	dw      05e02h  ; start horz blanking
	dw      09103h  ; end horz blanking
	dw      06204h  ; start h sync
	dw      08f05h  ; end h sync
	dw      06206h  ; vertical total
	dw      0f007h  ; overflow
	dw      06009h  ;
	dw      0310fh  ;
	dw      03710h  ; v sync start
	dw      08911h  ; v sync end and protect cr0-cr7
	dw      03312h  ; vertical displayed
	dw      02f13h  ; offset
	dw      00014h  ; turn off dword mode
	dw      03c15h  ; v blank start
	dw      05c16h  ; v blank end
	dw      0e317h  ; turn on byte mode
	dw      376
	dw      564

LAST_X_MODE         equ    13
ModeTable label word    ; Mode X tweak table
	dw      offset X320Y200
	dw      offset X320Y240
	dw      offset X360Y200
	dw      offset X360Y240
	dw      offset X376Y282
	dw      offset X320Y400
	dw      offset X320Y480
	dw      offset X360Y400
	dw      offset X360Y480
	dw      offset X360Y360
	dw      offset X376Y308
	dw      offset X376Y564
	dw      offset X256Y200
	dw      offset X256Y240


PARAMS label byte

	_CurrXMode               dw 0   ; Current graphics mode index
	_InGraphics              db 0   ; Flag indicating graphics activity
	_ScrnPhysicalByteWidth   dw 0   ; Physical width in bytes of screen
	_ScrnPhysicalPixelWidth  dw 0   ; Physical width in pixels of screen
	_ScrnPhysicalHeight      dw 0   ; Physical Height of screen
	_ErrorValue              db 0   ; Set after function calls


	_SplitScrnActive         db 0   ; Flag indicating Split scrn activity
	_DoubleBufferActive      dw 0   ; Flag indicating double buffering
	_TrippleBufferActive     dw 0   ; Flag indicating tripple buffering

	_SplitScrnScanLine       dw 0   ; Split Screen's starting scan line
	_SplitScrnVisibleHeight  dw 0   ; Split Screen's height on screen

	_SplitScrnOffs           dw 0   ; Offset in video ram of Split Screen
					; always = 0
	_Page0_Offs              dw 0   ; Ofset in video ram of Main virtual
					; screen ( = 0 if no split screen
					; otherwise = offset of first byte
					; after split screen
	_Page1_Offs              dw 0   ; Ofset in video ram of Second virtual
					; screen ( = 0 if no split screen
					; otherwise = offset of first byte
					; after split screen
					; = Page0_Offs if Doubble buffering
					; not enabled
	_Page2_Offs              dw 0

	_NonVisual_Offs          dw 0   ; Ofset in video ram of first byte
					; of non visible ram
	_ScrnLogicalByteWidth    dw 0   ; Logical width in bytes of screen
	_ScrnLogicalPixelWidth   dw 0   ; Logical width in pixels of screen
	_ScrnLogicalHeight       dw 0   ; Logical Height of screen

	_MaxScrollX              dw 0   ; Max X start position of Physical
					; screen within virtual screen (in
					; bytes)
	_MaxScrollY              dw 0   ; Max Y start position of Physical
					; screen within virtual screen

	_VisiblePageIdx          dw 0   ; Index of currently visible D.B.
					; page

	PageAddrTable label word
	_VisiblePageOffs         dw 0   ; Table containing starting offsets
	_HiddenPageOffs          dw 0   ; of the double buffer pages
	_WaitingPageOffs                 dw 0

	_TopClip                 dw 0   ; Clipping Rectangle
	_BottomClip              dw 0   ;
	_LeftClip                dw 0   ; Left/Right coordinates in bytes
	_RightClip               dw 0   ;
	_PhysicalStartByteX      dw 0   ; X byte coord of physical screen
					; relative to virtual virtual screen
	_PhysicalStartPixelX     dw 0   ; X pixel coord of physical screen
					; relative to virtual screen
	_PhysicalStartY          dw 0   ; Y pixel coord of physical screen
					; relative to virtual screen

; NEW
	_VsyncHandlerActive     dw      0
	_MouseRefreshFlag       dw      0
	_MouseVsyncHandler      dd      0
	_StartAddressFlag       dw      0
	_WaitingStartLow        dw      0
	_WaitingStartHigh       dw      0
	_WaitingPelPan          dw      0
	_VsyncPaletteStart      dw      0
	_VsyncPaletteCount      dw      0
	_VsyncPaletteBuffer     label  byte
				db  768  dup(?)


PARAMS_END label byte

PARAM_COUNT equ ($-PARAMS)


; Index/data pairs for CRT Controller registers that differ between
; mode 13h and mode X.

	;Pelpan values for 0,1,2,3 pixel panning to the left, respectively
	PelPanMask              db      000h,002h,004h,006h

DoubleScanFlag db ?     ; Flag to indicate double scanned mode

_DATA		ENDS


	.code

;-------------------------------------------------------------------------
; Local Logical Screen Width setting function
; cx = Requitrd Logical Width
;
; WARNING: no registers are preserved

SetLogicalScrWidth proc
	mov   dx,CRTC_INDEX
	mov   al,CRTC_OFFSET
	out   dx,al
	inc   dx

	mov   ax,cx
	cmp   ax,[_ScrnPhysicalPixelWidth]; Is logical width >= physical width
	jge   @@ValidLogicalWidth          ; yes - continue
	mov   ax,bx                        ; no - set logical width = physical

@@ValidLogicalWidth:
	shr   ax,1
	shr   ax,1
	shr   ax,1
	out   dx,al

	; The EXACT logical pixel width may not have been possible since
	; it should be divisible by 8. Round down to the closest possible
	; width and update the status variables

	shl   ax,1
	mov   bx,ax
	mov   [_ScrnLogicalByteWidth],ax  ; Store the byte width of virtual
	mov   [_RightClip],ax             ; Set default Right clip column
					  ; screen
	sub   ax,[_ScrnPhysicalByteWidth] ; Calculate and store Max X position
	shl   ax,1                        ; of physical screen in virtual
	shl   ax,1                        ; of physical screen in virtual
	mov   [_MaxScrollX],ax            ; screen in pixels
	mov   ax,bx                       ; set ax to byte width of virt scrn
	shl   ax,1                        ; convert to pixels
	shl   ax,1                        ; convert to pixels
	mov   [_ScrnLogicalPixelWidth],ax ; store virt scrn pixel width
	mov   cx,ax                       ; save ax (return value)

	; calculate no. non split screen rows in video ram

	mov   ax,0ffffh                ; cx = Maximum video ram offset
	sub   dx,dx                    ; DX:AX is divide operand,  set DX = 0
	div   bx                       ; divide ax by ScrnLogicalByteWidth
	mov   [_ScrnLogicalHeight],ax  ; Save Screen Logical Height
	mov   [_BottomClip],ax         ; Set default bottom clip row
	sub   ax,[_ScrnPhysicalHeight] ; Update the maximum Y position of
	mov   [_MaxScrollY],ax         ; Physical screen in logical screen
	mov   ax,cx                    ; restore ax (return value)

	; calculate initial NonVisual
	mov  ax,[_ScrnLogicalByteWidth]
	mul  [_ScrnPhysicalHeight]
	mov  [_NonVisual_Offs],ax

@@Done: ret
SetLogicalScrWidth endp

clear_vram proc
		push  di
	mov   dx,SC_INDEX
	mov   ax,0f02h
	out   dx,ax               ; enable writes to all four planes
	mov   ax,SCREEN_SEG       ; now clear all display memory, 8 pixels
	mov   es,ax               ; at a time
	sub   di,di               ; point ES:DI to display memory

	WaitVsyncEnd

	sub   ax,ax               ; clear to zero-value pixels
	mov   cx,0FFFFh           ; # of words in display memory
	rep   stosw               ; clear all of display memory
		pop   di
	ret
clear_vram endp



;-----------------------------------------------------------------------
; Mode X graphics mode set with a virtual screen
;   logical screen width.
; C near-callable as:
;
;    int x_set_mode(unsigned int mode,unsigned int WidthInPixels);
;
; returns the actual width of the allocated virtual screen in pixels
; if a valid mode was selected otherwise returns -1
;
; Saves virtual screen pixel width in _ScrnLogicalPixelWidth.
; Saves virtual screen byte  width in _ScrnLogicalByteWidth.
; Physical screen dimensions are set in _ScrnPhysicalPixelWidth,
; _ScrnPhysicalByteWidth and _ScrnPhysicalHeight
;
;
; Modes:  0  = 320 x 200  (256 color)  NOTE: Some of these modes require
;         1  = 320 x 240  (256 color)     vertical size adjustment.
;         2  = 360 x 200  (256 color)
;         3  = 360 x 240  (256 color)
;         4  = 320 x 400  (256 color)
;         5  = 320 x 480  (256 color)
;         6  = 360 x 200  (256 color)
;         7  = 360 x 480  (256 color)
;         8  = 360 x 360  (256 color)
;         9  = 376 x 308  (256 color)
;         10 = 376 x 564  (256 color)
;
; Written by Themie Gouthas,
; parts adapted from M. Abrash code.
;------------------------------------------------------------------------
_x_set_mode proc
	;;arg   mode:word,logicalscrwidth:word
	push  bp      ;preserve caller's stack frame
	mov   bp,sp

	push  si      ;preserve C register vars
	push  di      ; (don't count on BIOS preserving anything)

	cld
	mov   ax,ds
	mov   es,ax
	mov   di,offset PARAMS
	xor   ax,ax
	mov   cx,PARAM_COUNT
	rep   stosb

	mov   cx,[BP+4]
	cmp   cx,LAST_X_MODE        ; have we selected a valid mode
	jle   @@ValidMode           ; Yes !

	mov   [_InGraphics],FALSE   ; No return -1
	mov   ax,-1
	pop   di
	pop   si
	pop   bp
	ret

@@ValidMode:

	mov   [_CurrXMode],cx
	mov   [_InGraphics],TRUE

	xor   al,al
	cmp   cx,3
	jg    @@SetDoubleScanFlag
	mov   al,TRUE
@@SetDoubleScanFlag:
	mov   [DoubleScanFlag],al
	push  cx                    ; some bios's dont preserve cx

	call  clear_vram

	mov   ax,13h                ; let the BIOS set standard 256-color
	int   10h                   ;  mode (320x200 linear)


	pop   cx

	mov   dx,SC_INDEX
	mov   ax,0604h
	out   dx,ax                 ; disable chain4 mode
	mov   ax,0100h
	out   dx,ax                 ; synchronous reset while setting Misc
				    ;  Output for safety, even though clock
				    ;  unchanged

	mov   bx,offset ModeTable
	shl   cx,1
	add   bx,cx
	mov   si, word ptr [bx]
	lodsb

	or    al,al
	jz    @@DontSetDot
	mov   dx,MISC_OUTPUT
	out   dx,al               ; select the dot clock and Horiz
				  ;  scanning rate
@@DontSetDot:
	mov   dx,SC_INDEX
	mov   ax,0300h
	out   dx,ax               ; undo reset (restart sequencer)


	mov   dx,CRTC_INDEX       ; reprogram the CRT Controller
	mov   al,11h              ; VSync End reg contains register write
	out   dx,al               ; protect bit
	inc   dx                  ; CRT Controller Data register
	in    al,dx               ; get current VSync End register setting
	and   al,07fh             ; remove write protect on various
	out   dx,al               ; CRTC registers
	dec   dx                  ; CRT Controller Index
	cld
	xor   cx,cx
	lodsb
	mov   cl,al

@@SetCRTParmsLoop:
	lodsw                     ; get the next CRT Index/Data pair
	out   dx,ax               ; set the next CRT Index/Data pair
	loop  @@SetCRTParmsLoop

	mov   dx,SC_INDEX
	mov   ax,0f02h
	out   dx,ax               ; enable writes to all four planes
	mov   ax,SCREEN_SEG       ; now clear all display memory, 8 pixels
	mov   es,ax               ; at a time
	sub   di,di               ; point ES:DI to display memory
	sub   ax,ax               ; clear to zero-value pixels
	mov   cx,8000h            ; # of words in display memory
	rep   stosw               ; clear all of display memory

	;  Set pysical screen dimensions

	lodsw                               ; Load scrn pixel width
	mov   [_ScrnPhysicalPixelWidth],ax  ;  from tweak table and store
	mov   [_SplitScrnScanLine],ax       ; No splitscrn ==
					    ; splitscrn=PhysicalscrnHeight
	mov   bx,ax                         ; Copy width for later use
	shr   ax,1                          ; Convert to byte width
	shr   ax,1                          ; Convert to byte width
	mov   [_ScrnPhysicalByteWidth],ax   ; Store for later use
	lodsw                               ; Load Screen Phys. Height
	mov   [_ScrnPhysicalHeight],ax      ; Store for later use


	;  Mode X is set, now set the required logical page width.

	mov     cx,[BP+6]

	call    SetLogicalScrWidth

	pop     di      ;restore C register vars
	pop     si
	pop     bp      ;restore caller's stack frame
	ret
_x_set_mode endp

;----------------------------------------------------------------------
; Mode X (256 color mode) set default access video plane
;
; C near-callable as:
;    void x_select_default_plane(unsigned char plane);
;
; Enables Read/Write access to a plane using general memory access
; methods
;
; Written by Themie Gouthas
;----------------------------------------------------------------------
_x_select_default_plane proc
	;arg Plane:byte
	push bp
	mov  bp,sp       ; set up stack frame
	mov  cl,byte ptr [bp+4]

	; SELECT WRITE PLANE
	and  cl,011b              ;CL = plane
	mov  ax,0100h + MAP_MASK  ;AL = index in SC of Map Mask reg
	shl  ah,cl                ;set only the bit for the required
				  ; plane to 1
	mov  dx,SC_INDEX          ;set the Map Mask to enable only the
	out  dx,ax                ; pixel's plane

	; SELECT READ PLANE
	mov  ah,cl                ;AH = plane
	mov  al,READ_MAP          ;AL = index in GC of the Read Map reg
	mov  dx,GC_INDEX          ;set the Read Map to read the pixel's
	out  dx,ax                ; plane

	pop  bp
	ret
_x_select_default_plane endp


;----------------------------------------------------------------------
; Mode X (256 color mode) Set Mode X split screen starting row
; The split screen resides on the bottom half of the screen and has a
; starting address of A000:0000
;
; C near-callable as:
;    void x_set_splitscreen(unsigned int line);
;
; Updates _Page0_Offs to reflect the existence of the split screen region
; ie _MainScrnOffset is set to the offset of the first pixel beyond the split
; screen region
;
; Written by Themie Gouthas
;----------------------------------------------------------------------

_x_set_splitscreen proc
	;arg Line:word
	push bp
	mov  bp,sp       ; set up stack frame
	push si

	xor  si,si       ; si=0 -> x virtual page start coord

	cmp  [_DoubleBufferActive],0
	jne   @@error

	cmp  [_SplitScrnActive],0
	je   @@NotPreviouslyCalled

@@error:
	mov  [_ErrorValue],ERROR
	pop  si
	pop  bp          ; Return if previously called
	ret

@@NotPreviouslyCalled:

	; Turn on split screen pal pen suppression, so the split screen
	; wo'nt be subject to pel panning as is the non split screen portion.

	mov  dx,INPUT_STATUS_0
	in   al,dx                  ; Reset the AC Index/Data toggle to
					;  index state
	mov  al,AC_MODE_CONTROL+20h ; Bit 5 set to prevent screen blanking
	mov  dx,AC_INDEX            ; Point AC to Index/Data register
	out  dx,al
	inc  dx                     ; Point to AC Data reg (for reads only)
	in   al,dx                  ; Get the current AC Mode Control reg
	or   al,20h                 ; Enable split scrn Pel panning suppress.
	dec  dx                     ; Point to AC Index/Data reg (for writes only)
	out  dx,al                  ; Write the new AC Mode Control setting
					;  with split screen pel panning
					;  suppression turned on

	mov  [_PhysicalStartByteX],ax   ; Set the Phisical screen start
	mov  [_PhysicalStartPixelX],ax  ; offset within virtual screen
	mov  [_PhysicalStartY],ax
	mov  [_SplitScrnActive],TRUE
	mov  ax,[bp+4]
	jns  @@NotNeg    ; Check that Split Scrn start scan line is +ve

	mov  ax,0        ; Since -ve set to 0

@@NotNeg:
	mov  [_SplitScrnScanLine],ax   ; save the scanline



	or    [DoubleScanFlag],0
	jz    @@NotDoubleScanned
	shl   ax,1
	dec   ax
@@NotDoubleScanned:
	;mov  cl,[DoubleScanFlag]
	;shl  ax,cl            ; Mode X 200 and 240 line modes are actually
				  ; 400 and 480 lines that are double scanned
				  ; so for start scanline multiply required ModeX
				  ; scan line by 2 if its a double scanned mode


	mov  bx,ax            ; save the scanline


	WaitVsyncStart        ; wait for vertical retrace

	cli                   ; Dont allow register setting to be interrupted
	mov  dx,CRTC_INDEX
	mov  ah,bl
	mov  al,LINE_COMPARE
	out  dx,ax            ; Bits 7-0 of the split screen scan line

	mov  ah,bh
	and  ah,1
	shl  ah,1
	shl  ah,1
	shl  ah,1
	shl  ah,1
	mov  al,OVERFLOW     ; Bit 4 of overflow register = Bit 8 of split
	out  dx,al           ; screen scan line,
	inc  dx              ; So using readability of VGA registers
	in   al,dx           ; Read the OVERFLOW register, and set the
	and  al, not 10h     ; bit corresponding to Bit 8 (above)
	or   al,ah
	out  dx,al

	dec  dx
	mov  ah,bh
	and  ah,2
	ror  ah,1
	ror  ah,1
	ror  ah,1
	mov  al,MAX_SCAN_LINE  ; Bit 6 of max scan line register =
	out  dx,al             ; Bit 9 of split screen scan line
	inc  dx                ; As we did before, update the apropriate
	in   al,dx             ; bit without disturbing the rest
	and  al, not 40h
	or   al,ah
	out  dx,al
	sti                    ; Registers are set, so interrupts are safe

	mov  ax,[_ScrnPhysicalHeight]     ; Determine where the first byte
	sub  ax,[_SplitScrnScanLine]      ; of the non split screen video ram
	mov  [_SplitScrnVisibleHeight],ax ; starts and store it for reference

	mov  bx,[_ScrnLogicalByteWidth]
	mul  bx
	mov  [_Page0_Offs],ax
	mov  [_Page1_Offs],ax
	mov  [_Page2_Offs],ax

	; calculate no. non split screen rows in video ram
	mov  cx,0ffffh             ; cx = Maximum video ram offset
	sub  cx,ax                 ; cx = cx - _Page0_Offs
	xchg cx,ax                 ; swap cx and ax
	sub  dx,dx                 ; DX:AX is divide operand,  set DX = 0
	div  bx                    ; divide ax (prev cx) by
				   ; ScrnLogicalByteWidth

	mov  [_ScrnLogicalHeight],ax     ; Save Screen Logical Height
	cmp   ax,[_BottomClip]
	jle   @@BottomClipOK2             ; Adjust Clip Rectangle if necessary
	mov   [_BottomClip],ax
@@BottomClipOK2:
	sub  ax,[_SplitScrnScanLine]     ; Update the maximum Y position of
	mov  [_MaxScrollY],ax            ; Physical screen in logical screen

	xchg cx,ax                       ; restore original ax (MainScrnOfs)
	mov  bh,al                       ; Set the visible screen start address
	mov  ch,ah                       ; to the top left corner of the virtual
	jmp  StartAddrEntry              ; screen
_x_set_splitscreen      endp


;-----------------------------------------------------------------------
; Mode X (256 color mode) Page flip primer
; No clipping is performed.
; C near-callable as:
;
;    void x_page_flip(unsigned int x, unsigned int y);
;
; Swaps visible and hidden page offsets and then executes the SetStartAddr
; to achieve a page flip.
;
; SEE x_set_start_addr below
;
; Written by Themie Gouthas
;------------------------------------------------------------------------

_x_page_flip proc
	;arg x:word,y:word
	push  bp                  ;preserve caller's stack frame
	mov   bp,sp               ;point to local stack frame
	push  si

	mov  si,[bp+4]
	mov  ax,[_ScrnLogicalByteWidth]     ; Calculate Offset increment
	mov  cx,[bp+6]
	mul  cx                             ; for Y
	cmp  [_DoubleBufferActive],TRUE     ; Do we have double buffering ?
	je   @@DoubleBuffer
	cmp  [_TrippleBufferActive],TRUE
	jne   PageFlipEntry1

; TrippleBuffer
	mov  bx,[_HiddenPageOffs]
	xchg bx,[_VisiblePageOffs]
	xchg bx,[_WaitingPageOffs]
	mov  [_HiddenPageOffs],bx
	mov  bx,[_VisiblePageIdx]
	inc  bx
	cmp  bx,3
	jne  @@IdxOk
	xor  bx,bx
@@IdxOk:
	mov  [_VisiblePageIdx],bx
	jmp  short PageFlipEntry2
@@DoubleBuffer:
	mov  bx,[_HiddenPageOffs]
	xchg bx,[_VisiblePageOffs]          ; Swap the Page Offsete
	xchg [_HiddenPageOffs],bx
	xor  [_VisiblePageIdx],01h          ; Set the Visible page index
	jmp  short PageFlipEntry2
_x_page_flip endp


;-----------------------------------------------------------------------
; Mode X (256 color mode) Set Mode X non split screen start address
;   of logical screen.
; C near-callable as:
;
;    void x_set_start_addr(unsigned int x, unsigned int y);
;
; Params: StartOffset is offset of first byte of logical screen ram
;           (Useful if you want to double buffer by splitting your non
;            split screen video ram into 2 pages)
;        X,Y coordinates of the top left hand corner of the physical screen
;           within the logical screen
;           X must not exceed (Logical screen width - Physical screen width)
;           Y must not exceed (Logical screen height - Physical screen height)
;
;
; Written by Themie Gouthas,
; Parts addapted from M. Abrash code published in DDJ Mag.
;------------------------------------------------------------------------
_x_set_start_addr proc
	;arg x:word,y:word
	push bp
	mov  bp,sp
	push si

	mov  si,[bp+4]
	mov  ax,[_ScrnLogicalByteWidth]     ; Calculate Offset increment
	mov  cx,[bp+6]                         ; for Y
	mul  cx
	cmp  [_DoubleBufferActive],TRUE     ; Do we have double buffering ?
	je   @@PageResolution
	cmp  [_TrippleBufferActive],TRUE
	je   @@PageResolution
PageFlipEntry1:
	add  ax,[_Page0_Offs]               ; no - add page 0 offset
	jmp  short @@AddColumn

PageFlipEntry2:

	mov  [_PhysicalStartPixelX],si
	mov  [_PhysicalStartY],cx

@@PageResolution:
	add  ax,[_VisiblePageOffs]          ; Add visible page offset

@@AddColumn:
	mov  cx,si
	shr  cx,1
	shr  cx,1
	mov  [_PhysicalStartByteX],cx
	add  ax,cx                          ; add the column offset for X
	mov  bh,al                          ; setup CRTC start addr regs and
						; values in word registers for
	mov  ch,ah                          ; fast word outs

StartAddrEntry:
	mov  bl,ADDR_LOW
	mov  cl,ADDR_HIGH
	and  si,0003h             ; select pel pan register value for the
	mov  ah,PelPanMask[si]    ; required x coordinate
	mov  al,PEL_PANNING+20h
	mov  si,ax

	cmp  [_VsyncHandlerActive],TRUE
	jne   @@NoVsyncHandler
; NEW STUFF
@@WaitLast:
	cmp   [_StartAddressFlag],0
	jne   @@WaitLast
	cli
	mov  [_WaitingStartLow],bx
	mov  [_WaitingStartHigh],cx
	mov  [_WaitingPelPan],si
	mov  [_StartAddressFlag],1
	sti
	jmp  short @@Return

@@NoVsyncHandler:
	mov  dx,INPUT_STATUS_0    ;Wait for trailing edge of Vsync pulse
@@WaitDE:
	in   al,dx
	test al,01h
	jnz  @@WaitDE            ;display enable is active low (0 = active)

	mov  dx,CRTC_INDEX
	mov  ax,bx
	cli
	out  dx,ax               ;start address low
	mov  ax,cx
	out  dx,ax               ;start address high
	sti

; Now wait for vertical sync, so the other page will be invisible when
; we start drawing to it.
	mov  dx,INPUT_STATUS_0    ;Wait for trailing edge of Vsync pulse
@@WaitVS:
	in   al,dx
	test al,08h
	jz @@WaitVS           ;display enable is active low (0 = active)


	mov  dx,AC_INDEX
	mov  ax,si                ; Point the attribute controller to pel pan
	cli
	out  dx,al                ; reg. Bit 5 also set to prevent blanking
	mov  al,ah
	out  dx,al                ; load new Pel Pan setting.
	sti

@@Return:
	mov  [_ErrorValue],OK
	pop  si
	pop  bp
	ret
_x_set_start_addr  endp


;-----------------------------------------------------------------------
; Mode X (256 color mode) Mode X split screen hide
; C near-callable as:
;
;    void x_hide_splitscreen()
;
; Hides an existing split screen by setting its starting scan line to
; the last physical screen scan line
;
; WARNING: Only to be used if SplitScrnLine has been previously called
; WARNING: DO NOT USE with mode 5-11 (320x400-376x564). The memory for
;          the initial split screen is reserved and the size limitations
;          of these modes means any change in the split screen scan line
;          will encroach on the split screen ram
;
; Written by Themie Gouthas
;------------------------------------------------------------------------

_x_hide_splitscreen proc
	push bp
	mov  bp,sp

	cmp  [_SplitScrnActive],TRUE
	je   @@SplitScreenEnabled

@@error0:
	mov  [_ErrorValue],ERROR
	pop  bp
	ret

@@SplitScreenEnabled:
	cmp  [_CurrXMode],4          ; Do nothing for Modes > 2
	jg   @@error0
	mov  bx,[_ScrnPhysicalHeight]

	mov  ax,[_ScrnLogicalHeight]
	sub  ax,bx
	mov  [_MaxScrollY],ax
	xor  ax,ax
	mov  [_SplitScrnVisibleHeight],ax

	or    [DoubleScanFlag],0
	jz    @@NotDoubleScanned0
	shl   bx,1
	dec   bx
@@NotDoubleScanned0:
	;mov  cl,[DoubleScanFlag]  ; Compensate for double scanned modes
	;shl  bx,cl

	WaitVsyncStart               ; wait for vertical retrace

	cli                 ; Dont allow register setting to be interrupted
	mov  dx,CRTC_INDEX
	mov  ah,bl
	mov  al,LINE_COMPARE
	out  dx,ax          ; Bits 7-0 of the split screen scan line

	mov  ah,bh
	and  ah,1
	shl  ah,1
	shl  ah,1
	shl  ah,1
	shl  ah,1
	mov  al,OVERFLOW  ; Bit 4 of overflow register = Bit 8 of split
	out  dx,al        ; screen scan line,
	inc  dx           ; So using readability of VGA registers
	in   al,dx        ; Read the OVERFLOW register, and set the
	and  al, not 10h  ; bit corresponding to Bit 8 (above)
	or   al,ah
	out  dx,al

	dec  dx
	mov  ah,bh
	and  ah,2
	ror  ah,1
	ror  ah,1
	ror  ah,1
	mov  al,MAX_SCAN_LINE  ; Bit 6 of max scan line register =
	out  dx,al             ; Bit 9 of split screen scan line
	inc  dx                ; As we did before, update the apropriate
	in   al,dx             ; bit without disturbing the rest
	and  al, not 40h
	or   al,ah
	out  dx,al
	sti                  ; Registers are set, so interrupts are safe

@@done0:

	mov  [_ErrorValue],OK
	pop  bp
	ret
_x_hide_splitscreen endp

;-----------------------------------------------------------------------
; Mode X (256 color mode) Mode X split screen show
; C near-callable as:
;
;    void x_show_splitscreen()
;
; Restores split screen start scan line to the initial split screen
; starting scan line as set by SplitScrnLine.
;
; WARNING: Only to be used if SplitScrnLine has been previously called
; WARNING: DO NOT USE with mode 5-11 (320x400-376x564). The memory for
;          the initial split screen is reserved and the size limitations
;          of these modes means any change in the split screen scan line
;          will encroach on the split screen ram
;          Update: Now disabled for these modes
;
; Written by Themie Gouthas
;------------------------------------------------------------------------


_x_show_splitscreen proc
	push bp
	mov  bp,sp

	cmp  [_SplitScrnActive],TRUE
	je   @@SplitScreenEnabled0

@@error1:
	mov  [_ErrorValue],ERROR
	pop  bp
	ret

@@SplitScreenEnabled0:
	cmp  [_CurrXMode],4          ; Do nothing for Modes > 2
	jg   @@error1

	mov  bx,[_SplitScrnScanLine]
	mov  ax,[_ScrnLogicalHeight] ; Update Max Scroll Y
	sub  ax,bx
	mov  [_MaxScrollY],ax

	mov  ax,[_ScrnPhysicalHeight]
	sub  ax,bx
	mov  [_SplitScrnVisibleHeight],ax

	or    [DoubleScanFlag],0
	jz    @@NotDoubleScanned1
	shl   bx,1
	dec   bx
@@NotDoubleScanned1:
	;mov  cl,[DoubleScanFlag]  ; Compensate for double scanned modes
	;shl  bx,cl
	WaitVsyncStart               ; wait for vertical retrace

	cli                          ; Dont allow register setting to be interrupted
	mov  dx,CRTC_INDEX
	mov  ah,bl
	mov  al,LINE_COMPARE
	out  dx,ax                  ; Bits 7-0 of the split screen scan line

	mov  ah,bh
	and  ah,1
	shl  ah,1
	shl  ah,1
	shl  ah,1
	shl  ah,1
	mov  al,OVERFLOW  ; Bit 4 of overflow register = Bit 8 of split
	out  dx,al        ; screen scan line,
	inc  dx           ; So using readability of VGA registers
	in   al,dx        ; Read the OVERFLOW register, and set the
	and  al, not 10h  ; bit corresponding to Bit 8 (above)
	or   al,ah
	out  dx,al

	dec  dx
	mov  ah,bh
	and  ah,2
	ror  ah,1
	ror  ah,1
	ror  ah,1
	mov  al,MAX_SCAN_LINE  ; Bit 6 of max scan line register =
	out  dx,al             ; Bit 9 of split screen scan line
	inc  dx                ; As we did before, update the apropriate
	in   al,dx             ; bit without disturbing the rest
	and  al, not 40h
	or   al,ah
	out  dx,al
	sti                  ; Registers are set, so interrupts are safe

@@Done1:
	mov  [_ErrorValue],0
	pop  bp
	ret
_x_show_splitscreen endp


;-----------------------------------------------------------------------
; Mode X (256 color mode) Modify Mode X split screen starting scan line
; C near-callable as:
;
;    void x_adjust_splitscreen(unsigned int ScanLine)
;
; Sets the split screen start scan line to a new scan line. Valid scan lines
; are between the initial split screen starting scan line and the last
; physical screen scan line.
;
; WARNING: Only to be used if SplitScrnLine has been previously called
; WARNING: DO NOT USE with mode 5-11 (320x400-376x564). The memory for
;          the initial split screen is reserved and the size limitations
;          of these modes means any change in the split screen scan line
;          will encroach on the split screen ram
;          Update: Now disabled for these modes
;
;
; Written by Themie Gouthas
;------------------------------------------------------------------------


_x_adjust_splitscreen proc
	;arg   ScanLine
	push bp
	mov  bp,sp

	cmp  [_SplitScrnActive],TRUE
	je   @@SplitScreenEnabled1

@@error2:
	mov  [_ErrorValue],ERROR
	pop  bp
	ret

@@SplitScreenEnabled1:
	cmp  [_CurrXMode],4          ; Do nothing for Modes > 2
	jg   @@error2
	mov  bx,[bp+4]            ; Is the required starting scan line
	cmp  bx,[_SplitScrnScanLine]  ; valid ?
	js   @@Done2                   ; No - Then do nothing

@@ValidScanLine:

	mov  ax,[_ScrnLogicalHeight] ; Update Max Scroll Y
	sub  ax,bx
	mov  [_MaxScrollY],ax

	mov  ax,[_ScrnPhysicalHeight]
	sub  ax,bx
	mov  [_SplitScrnVisibleHeight],ax

	or    [DoubleScanFlag],0
	jz    @@NotDoubleScanned2
	shl   bx,1
	dec   bx
@@NotDoubleScanned2:
	;mov  cl,[DoubleScanFlag]   ; Compensate for double scanned modes
	;shl  bx,cl

	WaitVsyncStart      ; wait for vertical retrace

	cli                 ; Dont allow register setting to be interrupted

	mov  dx,CRTC_INDEX
	mov  ah,bl
	mov  al,LINE_COMPARE
	out  dx,ax          ; Bits 7-0 of the split screen scan line

	mov  ah,bh
	and  ah,1
	shl  ah,1
	shl  ah,1
	shl  ah,1
	shl  ah,1
	mov  al,OVERFLOW  ; Bit 4 of overflow register = Bit 8 of split
	out  dx,al        ; screen scan line,
	inc  dx           ; So using readability of VGA registers
	in   al,dx        ; Read the OVERFLOW register, and set the
	and  al, not 10h  ; bit corresponding to Bit 8 (above)
	or   al,ah
	out  dx,al

	dec  dx
	mov  ah,bh
	and  ah,2
	ror  ah,1
	ror  ah,1
	ror  ah,1
	mov  al,MAX_SCAN_LINE  ; Bit 6 of max scan line register =
	out  dx,al             ; Bit 9 of split screen scan line
	inc  dx                ; As we did before, update the apropriate
	in   al,dx             ; bit without disturbing the rest
	and  al, not 40h
	or   al,ah
	out  dx,al
	sti                    ; Registers are set, so interrupts are safe
@@Done2:
	mov  [_ErrorValue],OK
	pop   bp
	ret
_x_adjust_splitscreen endp



;-----------------------------------------------------------------------
; Mode X (256 color mode) Enable DoubleBuffering on non split screen area
; C near-callable as:
;
;    int x_set_doublebuffer(unsigned int PageHeight);
;
; Params: PageHeight is the height of the virtual screen to double buffer
;         Returns the closest possible height to the specified.
;
; Sets up two double buffering virtual pages
; GLOBAL variables set:
;
;      _Page1_Offs              Offset of second virtual page
;      _NonVisual_Offs          Offset of first non visible video ram byte
;      _DoubleBufferActive      Flag
;      _PageAddrTable           Table of Double buffering pages start offsets
;      _ScrnLogicalHeight       Logical height of the double buffering pages
;
;
; Written by Themie Gouthas
;------------------------------------------------------------------------


_x_set_doublebuffer proc
	   ;arg PageHeight:word
	   push  bp
	   mov   bp,sp

	   cmp   [_DoubleBufferActive],0
	   je    @@OkToContinue
@error:
	   mov   [_ErrorValue],ERROR
	   pop   bp
	   ret

@@OkToContinue:
	   mov   [_VisiblePageIdx],0     ; Set visible Page to 0
	   mov   ax,[_ScrnLogicalHeight] ; Set Maximum D.B. Page height to
	   shr   ax,1                    ;   _ScrnLogicalHeight / 2

	   mov   bx,[bp+4]         ; Is the require D.B. Page Height
	   cmp   ax,bx                   ;  > the Maximum  D.B. Page Height ?

	   js    @@InvalidHeight         ; no  - jump
	   mov   ax,bx                   ; yes - Set the D.B. Page height to
					 ;       to the maximum allowed.

@@InvalidHeight:
	   mov   [_ScrnLogicalHeight],ax    ; Update logical screen height to
					;  reflect the height of a D.B. page
	   cmp   ax,[_BottomClip]
	   jle   @@BottomClipOK0             ; Adjust Clip Rectangle if necessary
	   mov   [_BottomClip],ax
@@BottomClipOK0:
	   push  ax
	   mul   [_ScrnLogicalByteWidth]    ; Calculate the offset of the second
	   mov   cx,ax                      ;  D.B. Page in video ram
	   mov   bx,[_Page0_Offs]
	   mov   [_VisiblePageOffs],bx

	   add   ax,bx
	   mov   [_Page1_Offs],ax           ; Save it
	   mov   [_HiddenPageOffs],ax

	   add   ax,cx                      ; Calculate the offset of first byte
	   mov   [_NonVisual_Offs],ax       ;  beyond the D.B. pages and save it
	   mov   [_DoubleBufferActive],TRUE ; Set flag indicating D.B'ing mode on

	   pop   ax
	   sub   ax,[_ScrnPhysicalHeight]
	   add   ax,[_SplitScrnVisibleHeight]
	   mov   [_MaxScrollY],ax

	   mov   ax,dx                      ; return the D.B. pages' height
	   mov   [_ErrorValue],OK
	   pop   bp
	   ret
_x_set_doublebuffer endp


;-----------------------------------------------------------------------
; Mode X (256 color mode) Enable TrippleBuffering on non split screen area
; C near-callable as:
;
;    int x_set_tripplebuffer(unsigned int PageHeight);
;
; Params: PageHeight is the height of the virtual screen to tripple buffer
;         Returns the closest possible height to the specified.
;
; Sets up two tripple buffering virtual pages
; GLOBAL variables set:
;
;      _Page1_Offs              Offset of second virtual page
;      _Page2_Offs              Offset of third virtual page
;      _NonVisual_Offs          Offset of first non visible video ram byte
;      _DoubleBufferActive      Flag
;      _PageAddrTable           Table of Double buffering pages start offsets
;      _ScrnLogicalHeight       Logical height of the double buffering pages
;
;
; Almost written by Tore Bastiansen (cut & paste from _x_set_doublebuffer)
;------------------------------------------------------------------------

_x_set_tripplebuffer proc
	   ;arg PageHeight:word
	   push  bp
	   mov   bp,sp

	   cmp   [_DoubleBufferActive],0
	   jne   @@Error3
	   cmp   [_TrippleBufferActive],0
	   je    @@OkToContinue3
@@Error3:
	   mov   [_ErrorValue],ERROR
	   pop   bp
	   ret

@@OkToContinue3:
	   mov   [_VisiblePageIdx],0     ; Set visible Page to 0
	   mov   ax,[_ScrnLogicalHeight] ; Set Maximum T.B. Page height to
	   mov   bx,3
	   xor   dx,dx
	   idiv  bx                      ;   _ScrnLogicalHeight / 3

	   mov   bx,[bp+4]         ; Is the require T.B. Page Height
	   cmp   ax,bx                   ;  > the Maximum  T.B. Page Height ?

	   js    @@InvalidHeight0         ; no  - jump
	   mov   ax,bx                   ; yes - Set the T.B. Page height to
									 ;       to the maximum allowed.

@@InvalidHeight0:
	   mov   [_ScrnLogicalHeight],ax    ; Update logical screen height to
										;  reflect the height of a T.B. page
	   cmp   ax,[_BottomClip]
	   jle   @@BottomClipOK1             ; Adjust Clip Rectangle if necessary
	   mov   [_BottomClip],ax
@@BottomClipOK1:
	   push  ax
	   mul   [_ScrnLogicalByteWidth]    ; Calculate the offset of the second
	   mov   cx,ax                      ;  D.B. Page in video ram
	   mov   bx,[_Page0_Offs]
	   mov   [_VisiblePageOffs],bx

	   add   ax,bx
	   mov   [_Page1_Offs],ax           ; Save it
	   mov   [_HiddenPageOffs],ax

	   add   ax,cx
	   mov   [_Page2_Offs],ax            ; Save the other it ?
	   mov   [_WaitingPageOffs],ax

	   add   ax,cx                       ; Calculate the offset of first byte
	   mov   [_NonVisual_Offs],ax        ;  beyond the D.B. pages and save it
	   mov   [_TrippleBufferActive],TRUE ; Set flag indicating T.B'ing mode on

	   pop   ax
	   sub   ax,[_ScrnPhysicalHeight]
	   add   ax,[_SplitScrnVisibleHeight]
	   mov   [_MaxScrollY],ax

	   mov   ax,dx                      ; return the D.B. pages' height
	   mov   [_ErrorValue],OK
	   pop   bp
	   ret
_x_set_tripplebuffer endp


;-----------------------------------------------------------------------
; Set Clipping rectangle
; C callable as:
;
;
;    int x_set_cliprect(WORD left,WORD top, WORD right, WORD bottom);
;
;
; NOTE clipping is byte oriented. "left" and "right" are in bytes not pixels.
;    Only selected functions perform any clipping at all.
;
; Written by Themie Gouthas
;------------------------------------------------------------------------

_x_set_cliprect proc
;arg left:word,top:word,right:word,bottom:word
       push  bp
       mov   bp,sp
       mov   ax,[bp+4]
       mov   bx,[bp+8]
       cmp   bx,ax
       jns   @@CorrectXOrder
       xchg  bx,ax
@@CorrectXOrder:
       mov   [_LeftClip],ax
       mov   [_RightClip],bx
	   mov   ax,[bp+6]
       mov   bx,[bp+10]
       cmp   bx,ax
	   jns   @@CorrectYOrder
       xchg  bx,ax
@@CorrectYOrder:
       mov   [_TopClip],ax
       mov   [_BottomClip],bx
       pop   bp
       ret
_x_set_cliprect endp


;----------------------------------------------------------------------
; Return to text mode
;
_x_text_mode proc
       push  bp
       call  clear_vram
       mov   ax,03h        ; Restore Text Mode
       int   10h

       pop   bp
       ret
_x_text_mode endp

;-----------------------------------------------------------------------
; Wait for Vertical sync
_x_wait_vsync proc
	push  bp
	WaitVsyncStart
	pop   bp
	ret
_x_wait_vsync endp


end
