;-----------------------------------------------------------------------
; MODULE XPAL
;
; Palette functions 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
;-----------------------------------------------------------------------


COMMENT	$



    All the functions in this module operate on two variations of the
    pallete buffer, the raw and annotated buffers.

    All those functions ending in buff operate on the following palette
    structure:

       BYTE:r0,g0,b0,r1,g1,b1,...rn,gn,bn

    No reference to the starting colour index or number of colours stored
    is contained in the structure.

    All those functions ending in struc operate on the following palette
    structure:

       BYTE:c,BYTE:n,BYTE:r0,g0,b0,r1,g1,b1,...rn,gn,bn

    where c is the starting colour and n is the number of colours stored


    NOTE: previously interrupts were disabled for DAC reads/writes but
	  they have been left enabled in this version to allow the mouse
	  interrupt to be invoked.

$




include xlib.inc
include xpal.inc

.code


;----------------------------------------------------------------------
; Read DAC palette into annotated type buffer with interrupts disabled
; ie BYTE colours to skip, BYTE colours to set, r1,g1,b1,r1,g2,b2...rn,gn,bn
;
; x_get_pal_struc(char far * pal, int num_colrs, int start_color)
;
; WARNING: memory for the palette buffers must all be pre-allocated
;
; Written by Themie Gouthas
;----------------------------------------------------------------------
_x_get_pal_struc  proc
;ARG  PalBuff:dword,NumColors:word,StartColor:word
     push  bp		; Set up stack frame
     mov   bp,sp
     push  di
     push  si
     cld

     les   di,dword ptr [bp+4]  ; Point es:di to palette buffer
     mov   si,[bp+10]         ; Store the Start Colour
     mov   ax,si
     stosb
     mov   dx,[bp+8]          ; Store the Number of Colours
     mov   al,dl
     stosb

     mov   cx,dx                   ; setup regs and jump
     jmp   short ReadPalEntry

_x_get_pal_struc endp





;----------------------------------------------------------------------
; Read DAC palette into raw buffer with interrupts disabled
; ie BYTE r1,g1,b1,r1,g2,b2...rn,gn,bn
;
; x_get_pal_raw(char far * pal, int num_colrs, int start_index)
;
; WARNING: memory for the palette buffers must all be pre-allocated
;
; Written by Themie Gouthas
;----------------------------------------------------------------------
_x_get_pal_raw	proc
;ARG  PalBuff:dword,NumColors:word,StartColor:word
     push  bp		; Set up stack frame
     mov   bp,sp
     push  di
     push  si

     les   di,dword ptr [bp+4]  ; Point es:di to palette buffer

     mov  si,[bp+10]
     mov  cx,[bp+8]

ReadPalEntry:
     cld
     WaitVsyncStart
     mov  ax,si
     mov  dx,DAC_READ_INDEX
     ;cli
     out  dx,al                    ; Tell DAC what colour to start reading
     mov  dx,DAC_DATA

     mov  bx,cx                    ; set cx to Num Colors * 3 ( size of
     shl  bx,1                     ; palette buffer)
     add  cx,bx

     rep  insb                     ; read the palette enntries

     ;sti
     pop  si
     pop  di
     pop  bp
     ret
_x_get_pal_raw endp



;----------------------------------------------------------------------
; Write DAC palette from annotated type buffer with interrupts disabled
; ie BYTE colours to skip, BYTE colours to set, r1,g1,b1,r1,g2,b2...rn,gn,bn
;
; x_put_pal_struc(char far * pal)
;
; Written by Themie Gouthas
;----------------------------------------------------------------------

_x_put_pal_struc proc
ARG     CompPalBuff:dword
        push    bp      ;preserve caller's stack frame
	mov     bp,sp   ;point to local stack frame
	push    ds
	push    si
	cld
	lds     si,[CompPalBuff]   ; load the source compressed colour data
	lodsb			   ; get the colours to skip
	mov     ah,0
	mov     bx,ax              ; skip colours

	lodsb			   ; get the count of colours to set
	mov     ah,0
	mov	cx,ax              ; use it as a loop counter
	jmp     short WritePalEntry

_x_put_pal_struc  endp


;----------------------------------------------------------------------
; Write DAC palette from annotated type buffer with interrupts disabled
; starting at a new palette index
;
; ie BYTE colours to skip, BYTE colours to set, r1,g1,b1,r1,g2,b2...rn,gn,bn
;
; x_transpose_pal_struc(char far * pal, int StartColor)
;
; WARNING: memory for the palette buffers must all be pre-allocated
;
; Written by Themie Gouthas
;----------------------------------------------------------------------

_x_transpose_pal_struc proc
ARG     CompPalBuff:dword,StartColor:word
        push    bp      ;preserve caller's stack frame
	mov     bp,sp   ;point to local stack frame
	push    ds
	push    si
	cld
	lds     si,[CompPalBuff]   ; load the source compressed colour data
	mov     bx,[StartColor]
	mov     [si],bl
	inc     si
	lodsb			   ; get the count of colours to set
	mov     ah,0
	mov	cx,ax              ; use it as a loop counter
	jmp     short WritePalEntry
_x_transpose_pal_struc endp


;----------------------------------------------------------------------
; Write DAC palette from raw buffer with interrupts disabled
; ie BYTE r1,g1,b1,r1,g2,b2...rn,gn,bn
;
; _x_put_pal_raw(char far * pal, int num_colrs, int start_index)
;
; Written by Themie Gouthas
;----------------------------------------------------------------------
_x_put_pal_raw  proc
ARG  PalBuff:dword,NumColors:word,StartColor:word
		push bp		; Set up stack frame
		mov  bp,sp
		push ds
		push si

		mov  cx,[NumColors]      ; Number of colours to set
		mov  bx,[StartColor]
		lds  si,[PalBuff]        ; ds:si -> palette buffer


WritePalEntry:
                mov  ax,@data
		mov  es,ax
		cmp  es:[_VsyncHandlerActive],TRUE
		jne  @@NoVsyncHandler
@@WaitForLast:
		cmp  es:[_VsyncPaletteCount],0
		jne  @@WaitForLast
		push cx
		push es
		mov  di, offset _VsyncPaletteBuffer
		mov  ax,3
		mul  cx
		mov  cx,ax
		rep  movsb
		pop  ds
		pop  cx
		mov  [_VsyncPaletteStart],bx
		mov  [_VsyncPaletteCount],cx
		jmp  short @@Done
@@NoVsyncHandler:


		or   cx,cx
		jz   @@Done
		;cli
		cld                      ; Make sure we're going the right way
		WaitVsyncStart           ; Wait for vert sync to start
                mov  ax,bx
		mov  bx,60               ; set the vsync check timer (Vsync
                			 ; is tested for at each bx'th entry to
					 ; prevent snow 60 is otimum for 10
					 ; MHz 286 or greater

@@SetLoop:
		mov  dx,DAC_WRITE_INDEX  ; Tell DAC what colour index to start
		out  dx,al               ; writing from
		mov  dx,DAC_DATA

		outsb                    ; Set the red component
		outsb                    ; Set the green component
		outsb                    ; Set the blue component
		inc  al                  ; increment the colour index
		dec  bx                  ; decrement vsync test counter
		js   @@test_vsync        ; ready to test for vsync again ?
		loop @@SetLoop           ; No! - continue loop
		jmp  short @@Done        ; All colours done

@@test_vsync:
		mov     dx,INPUT_STATUS_0
		push    ax               ; save current colour index
@@Wait:
		in      al,dx            ; wait for vsync leading edge pulse
		test    al,08h
		jz      @@Wait

		pop     ax               ; restore current colour index
		mov     bx,60            ; reset vsync test counter
		loop @@SetLoop           ; loop for next colour index

@@Done:
		;sti
		pop  si
		pop  ds
		pop  bp
		ret
_x_put_pal_raw endp



;----------------------------------------------------------------------
; Set the RGB setting of a vga color
;
; _x_set_rgb(unsigned char color, unsigned char R,unsigned char G,
;            unsigned char B)
;
;
; Written by Themie Gouthas
;----------------------------------------------------------------------
_x_set_rgb  proc
ARG  ColorIndex:byte,R:byte,G:byte,B:byte
		push bp		; Set up stack frame
		mov  bp,sp

		mov  al,[ColorIndex]
		mov  dx,DAC_WRITE_INDEX  ; Tell DAC what colour index to
		out  dx,al               ; write to
		mov  dx,DAC_DATA

		mov  al,[R]              ; Set the red component
		out  dx,al
		mov  al,[G]              ; Set the green component
		out  dx,al
		mov  al,[B]              ; Set the blue component
		out  dx,al
		pop  bp
		ret
_x_set_rgb endp


;----------------------------------------------------------------------
; Rotate annotated palette buffer entries
;
; x_rot_pal_struc(char far * pal, int direction)
;
; Direction : 0 = backward 1 = forward
;
; Written by Themie Gouthas
;----------------------------------------------------------------------
_x_rot_pal_struc  proc
ARG  PalBuff:dword,Direction:word
    push bp		; Set up stack frame
    mov	 bp,sp
    push ds
    push si
    push di

    cld
    lds	 si,dword ptr [PalBuff]  ; point ds:si to Palette buffer
    lodsw         ; al = colorst ot skip, ah = num colors

    xor  ch,ch    ; Set the number of palette entries to cycle in cx
    mov  cl,ah    ;

    jmp  short RotatePalEntry

_x_rot_pal_struc  endp



;----------------------------------------------------------------------
; Rotate raw palette buffer
;
; x_rot_pal_raw(char far * pal, int direction, int num_colrs)
;
; Direcction : 0 = backward 1 = forward
;
; Written by Themie Gouthas
;----------------------------------------------------------------------
_x_rot_pal_raw	proc
ARG  PalBuff:dword,Direction:word,NumColors:word
    push bp		; Set up stack frame
    mov	 bp,sp
    push ds
    push si
    push di

    cld
    mov	 cx,[NumColors]          ; Set the number of palette entries to cycle
    lds	 si,dword ptr [PalBuff]  ; point ds:si to Palette buffer

RotatePalEntry:


    mov	 ax,ds                ; copy ds to es
    mov	 es,ax

    dec  cx
    mov	 bx,cx                ; Multiply cx by 3
    shl	 bx,1
    add  cx,bx

    cmp  [Direction],0        ; are we going forward ?
    jne  @@forward            ; yes - jump (colors move one position back)

    std                       ; no - set reverse direction
    add  si,cx                ; set si to last byte in palette
    add  si,2

@@forward:
    mov	 ax,si                ; copy si to di
    mov	 di,ax

    lodsb                     ; load first color triplet into regs
    mov  dl,al
    lodsb
    mov  dh,al
    lodsb
    mov  bl,al

    rep	 movsb                ; move remaining triplets direction indicated
			      ; by direction flag

    mov  al,dl                ; write color triplet from regs to last position
    stosb
    mov  al,dh
    stosb
    mov  al,bl
    stosb

    pop	 di
    pop	 si
    pop	 ds
    pop	 bp
    ret
_x_rot_pal_raw  endp

;----------------------------------------------------------------------
; Copy palette making intensity adjustment
; x_cpcontrast_pal_struc(char far *src_pal, char far *dest_pal, unsigned char Intensity)
;
; WARNING: memory for the palette buffers must all be pre-allocated
;
; Written by Themie Gouthas
;----------------------------------------------------------------------
_x_cpcontrast_pal_struc	proc
ARG  PalSrcBuff:dword,PalDestBuff:dword,Intensity:byte
    push bp		; Set up stack frame
    mov	 bp,sp
    push ds
    push si
    push di

    cld
    mov  bh,0ffh
    sub  bh,[Intensity]
    and  bh,07fh            ; Palettes are 7 bit
    lds	 si,dword ptr [PalSrcBuff]  ; point ds:si to Source Palette buffer
    les	 di,dword ptr [PalDestBuff] ; point ds:si to Source Palette buffer
    lodsw			    ; al = colorst ot skip, ah = num color
    stosw

    xor  ch,ch    ; Set the number of palette entries to adjust
    mov  cl,ah    ;

    mov  dx,0     ; flag set to 0 if all output palette entries zero
@@MainLoop:
    lodsw
    sub  al,bh               ; adjust intensity and copy RED
    jns  @@DecrementOK_R
    xor  al,al
@@DecrementOK_R:
    sub  ah,bh               ; adjust intensity and copy GREEN
    jns  @@DecrementOK_G
    xor  ah,ah
@@DecrementOK_G:
    or   dx,ax
    or   dl,ah
    stosw
    lodsb
    sub  al,bh               ; adjust intensity and copy BLUE
    jns  @@DecrementOK_B
    xor  al,al
@@DecrementOK_B:
    or   dl,al
    stosb
    loop @@MainLoop

    mov  ax,dx
    pop  di
    pop	 si
    pop	 ds
    pop	 bp
    ret
_x_cpcontrast_pal_struc  endp



;----------------------------------------------------------------------
; Write DAC palette from annotated type buffer with specified intensity
; ie BYTE colours to skip, BYTE colours to set, r1,g1,b1,r1,g2,b2...rn,gn,bn
;
; x_put_contrast_pal_struc(char far * pal, unsigned char  intensity)
;
; Designed for fading in or out a palette without using an intermediate
; working palette buffer ! (Slow but memory efficient ... OK for small
; pal strucs}
;
; Written by Themie Gouthas
;----------------------------------------------------------------------

_x_put_contrast_pal_struc proc
ARG     CompPalBuff:dword,Intensity:byte
        push    bp      ;preserve caller's stack frame
	mov     bp,sp   ;point to local stack frame
	push    ds
	push    si
	push    di
	cld

	mov     bh,0ffh
	sub     bh,[Intensity]
	and     bh,07fh            ; Palettes are 7 bit
	mov     di,40              ; set the vsync check timer (Vsync
				   ; is tested for at each di'th entry to
				   ; prevent snow 40 is otimum for 10
				   ; MHz 286 or greater)
	lds     si,[CompPalBuff]   ; load the source compressed colour data
	lodsb			   ; get the colours to skip
	mov     bl,al

	lodsb			   ; get the count of colours to set
	mov     ah,0
	mov	cx,ax              ; use it as a loop counter
	or      cx,cx
	jz      @@Done

	WaitVsyncStart           ; Wait for vert sync to start

@@MainLoop:
        mov  al,bl
	mov  dx,DAC_WRITE_INDEX  ; Tell DAC what colour index to start
	out  dx,al               ; writing from
	inc  dx                  ; == mov  dx,DAC_DATA

	lodsb                    ; Load each colour component, modify for
	sub  al,bh               ; intensity and write to DAC H/Ware
	jns  @@DecrementOK_R
	xor  al,al
@@DecrementOK_R:
	out  dx,al

	lodsb
	sub  al,bh
	jns  @@DecrementOK_G
	xor  al,al
@@DecrementOK_G:
	out  dx,al

	lodsb
	sub  al,bh
	jns  @@DecrementOK_B
	xor  al,al
@@DecrementOK_B:
	out  dx,al

	inc  bl                  ; increment color index
	dec  di                  ; decrement vsync test flag
	js   @@test_vsync
	loop @@MainLoop
	jmp  short @@Done


@@test_vsync:
	mov     dx,INPUT_STATUS_0
	push    ax               ; save current colour index
@@Wait:
	in      al,dx            ; wait for vsync leading edge pulse
	test    al,08h
	jz      @@Wait

	pop     ax               ; restore current colour index
	mov     di,40            ; reset vsync test counter
	loop    @@MainLoop       ; loop for next colour index

@@Done:
	;sti
	pop  di
	pop  si
	pop  ds
	pop  bp
	ret

_x_put_contrast_pal_struc   endp


    end


