;-----------------------------------------------------------------------
; MODULE XPOLYGON
;
; Filled Triangle function for all MODE X 256 Color resolutions
;
; Compile with Tasm.
; C callable.
;
; ****** XLIB - Mode X graphics library                ****************
; ******                                               ****************
; ****** Written By Themie Gouthas                     ****************
;
; This module is based on code developed by Steve Dollind for his
; XSPACE game.
; Copyright (C) 1992 Steven Dollins  --  sdollins@uiuc.edu
;
;
; egg@dstos3.dsto.gov.au
; teg@bart.dsto.gov.au
;-----------------------------------------------------------------------
include xlib.inc
include xpolygon.inc

.data
; Plane masks for clipping left and right edges of rectangle.
	LeftClipPlaneMask       db      00fh,00eh,00ch,008h
	RightClipPlaneMask      db      00fh,001h,003h,007h

.code


;-----------------------------------------------------------------------
; void HLineClipR
;
;       Draws a horizontal line from (X1, Y) to (X2, Y).
;       Uses Watcom Parameter passing convention in registers
;
;   X1 in AX
;   X2 in DX
;   Y in CX
;   Color in BX
;   PageOffset in DI
;
; By Themie Gouthas - Adapted from x_fill_rect.
;-----------------------------------------------------------------------
proc _HLineClipR near
	push    di
	cmp     dx,ax                ; if (X2 < X1) then assume no line
	jl      @@Invisible          ;   is visible

	cmp     cx,[_TopClip]        ; if (Y < TopClip) then no line
	jl      @@Invisible

	cmp     cx,[_BottomClip]     ;if (Y > BottomClip) then no line
	jg      @@Invisible

	mov     di,[_RightClip]      ;convert RightClip to pixel coords
	sal     di,2
	cmp     ax,di                ; if (X1 > RightClip) then no line
	jg      @@Invisible

	cmp     dx,di                ; if (X2 > RightClip) then
	jle     @@ClipLeft           ;  X2:=RightClip
	mov     dx,di

@@ClipLeft:
	mov     di,[_LeftClip]       ;convert LeftClip to pixel coords
	sal     di,2
        cmp     dx,di                ; if (X2 < LeftClip) then no line
        jl      @@Invisible

	cmp     ax,di                ;if (X1 > LeftClip) then were ready to plot
	jge     @@DoLine

	mov     ax,di                ;  X1:=LeftClip
        jmp     short @@DoLine

@@Invisible:
	pop     di
	ret

@@DoLine:
        pop     di                      ; di = PageOffset
	xchg    cx,ax                   ; AX = Y,  CX = X1
        mov     si,dx                   ; SI = DX = X2
	mul     [_ScrnLogicalByteWidth]
        mov     dx,si                   ; Reset DX to X1 since mul erases DX
	add     ax,di
	mov     di,cx
	sar     di,2                    ; Convert to bytes
	add     di,ax                   ; DI->First byte

        and     si,03h                  ; look up right edge plane mask
	mov     ah,RightClipPlaneMask[si]
	mov     si,cx                   ; look up left edge plane mask
	and     si,03h
	mov     al,LeftClipPlaneMask[si]

	cmp     dx,cx                   ; No harm in being paranoid..
	jle     @@Invisible2

	xchg    cx,dx                   ;CX=X2, DX=X1
	dec     cx
	and     dx,not 03h
	sub     cx,dx
        js      @@Invisible2
	shr     cx,2
	jnz     @@MasksSet
	and     al,ah
@@MasksSet:
	mov     dl,bl                 ; set BX=Plane Masks, AH=Color
	mov     bx,ax
	mov     ah,dl
	mov     dx,SC_INDEX+1         ;set the Sequence Controller Index to
	mov     al,bl
	out     dx,al
        mov     al,ah
	stosb                         ; Plot left byte
	dec     cx
	js      @@Invisible2
	jz      @@RightEnd


	mov     al,0fh                ; plot middle bytes
	out     dx,al
        mov     al,ah
        shr     cx,1
	rep     stosw
        adc     cx,cx
        rep     stosb



@@RightEnd:
	mov     al,bh              ; Plot right  byte
	out     dx,al
        mov     al,ah
	stosb
@@Invisible2:
	ret
_HLineClipR endp


;-----------------------------------------------------------------------
; void x_triangle( int X0, int Y0, int X1, int Y1,
;                int X2, int Y2, unsigned Color, unsigned PageOffset );
;
;
; Written by S. Dollins

_x_triangle  proc
ARG   X0:word,Y0:word,X1:word,Y1:word,X2:word,Y2:word,Color:word,PageOffset:word
LOCAL DX01:word, DY01:word, DX02:word, DY02:word, DX12:word, DY12:word, \
      DP01:word, DP02:word, DP12:word, XA01:word, XA02:word, XA12:word=STK

	push    bp
	mov     bp,sp
	sub     sp,STK
	push    ds es si di  ; Save es for polygon routine

	mov     ax,X0
	mov     bx,Y0
	mov     cx,X1
	mov     dx,Y1

	cmp     bx,dx   ; Y0,Y1
	jl      tri_Y0lY1
	je      tri_Y0eY1
	xchg    ax,cx   ; X0,X1
	xchg    bx,dx   ; Y0,Y1
tri_Y0lY1:
	cmp     dx,Y2   ; Y1,Y2
	jg      tri_a
	jmp     tri_sorted
tri_a:  xchg    cx,X2   ; X1,X2
	xchg    dx,Y2   ; Y1,Y2
	cmp     bx,dx   ; Y0,Y1
	jge     tri_b
	jmp     tri_sorted
tri_b:  je      tri_bot
	xchg    ax,cx   ; X0,X1
	xchg    bx,dx   ; Y0,Y1
	jmp     tri_sorted
tri_Y0eY1:
	cmp     bx,Y2   ; Y0,Y2
	jl      tri_bot
	jg      tri_c
	jmp     tri_done
tri_c:  xchg    ax,X2   ; X0,X2
	xchg    bx,Y2   ; Y0,Y2
	jmp     tri_sorted

tri_bot:
	cmp     ax,cx   ; X0,X1
	jl      tri_bot_sorted
	jg      tri_bot_a
	jmp     tri_done
tri_bot_a:
	xchg    ax,cx   ; X0,X1
tri_bot_sorted:
	cmp     bx,[_BottomClip]
	jle     tri_bot_y0ok
	jmp     tri_done
tri_bot_y0ok:
	mov     si,Y2
	cmp     si,[_TopClip]
	jge     tri_bot_y2ok
	jmp     tri_done
tri_bot_y2ok:
	mov     X0,ax
	mov     Y0,bx
	mov     X1,cx
	mov     Y1,dx

	mov     bx,Y2   ;    bx <- Y2
	sub     bx,Y0   ;    bx <- Y2 - Y0
	mov     DY02,bx ;  DY02 <- Y2 - Y0
	mov     ax,X2   ;    ax <- X2
	sub     ax,X0   ;    ax <- X2 - X0
	mov     DX02,ax ;  DX02 <- X2 - X0
	mov     cx,ax   ;    cx <- DX02
	cwd             ; dx:ax <- DX02
	idiv    bx      ;    ax <- DX02 / DY02
	cmp     cx,0
	jge     short tri_bot02
	dec     ax      ;    ax <- DX02 / DY02 - 1
tri_bot02:
	mov     XA02,ax ;  XA02 <- DX02 / DY02
	imul    bx      ;    ax <- XA02 * DY02
	sub     cx,ax   ;    cx <- DX02 - XA02 * DY02
	mov     DP02,cx ;  DP02 <- DX02 - XA02 * DY02

	mov     bx,Y2   ;    bx <- Y2
	sub     bx,Y1   ;    bx <- Y2 - Y1
	mov     DY12,bx ;  DY02 <- Y2 - Y1
	mov     ax,X2   ;    ax <- X2
	sub     ax,X1   ;    ax <- X2 - X1
	mov     DX12,ax ;  DX12 <- X2 - X1
	mov     cx,ax   ;    cx <- DX12
	cwd             ; dx:ax <- DX12
	idiv    bx      ;    ax <- DX12 / DY12
	cmp     cx,0
	jge     short tri_bot12
	dec     ax      ;    ax <- DX12 / DY12 - 1
tri_bot12:
	mov     XA12,ax ;  XA12 <- DX12 / DY12
	imul    bx      ;    ax <- XA12 * DY12
	sub     cx,ax   ;    cx <- DX12 - XA12 * DY12
	mov     DP12,cx ;  DP12 <- DX12 - XA12 * DY12

	mov     ax,0    ; PL <- 0
	mov     bx,0    ; PS <- 0
	mov     cx,Y0   ;  Y <- Y0
	mov     si,X0
	mov     di,X1
	dec     di
tri_bot_loop:
	inc     cx      ; Y

	add     ax,DP02 ; PL,DP02
	jle     short tri_bot_shortl
	sub     ax,DY02 ; PL,DY02
	inc     si      ; XL
tri_bot_shortl:
	add     si,XA02 ; XL,XA02

	add     bx,DP12 ; PS,DP12
	jle     short tri_bot_shortr
	sub     bx,DY12 ; PS,DY12
	inc     di      ; XS
tri_bot_shortr:
	add     di,XA12 ; XS,XA12

	push    di      ; XS
	push    si      ; XL
	cmp     cx,Y2   ; Y,Y2
	jl      short tri_bot_loop

	jmp     tri_draw_lines


tri_sorted:
	cmp     bx,[_BottomClip]
	jle     tri_y0ok
	jmp     tri_done
tri_y0ok:
	mov     si,Y2
	cmp     si,[_TopClip]
	jge     tri_y2ok
	jmp     tri_done
tri_y2ok:
	mov     X0,ax
	mov     Y0,bx
	mov     X1,cx
	mov     Y1,dx

	mov     bx,dx   ;    bx <- Y1
	sub     bx,Y0   ;    bx <- Y1 - Y0
	mov     DY01,bx ;  DY01 <- Y1 - Y0
	mov     ax,X1   ;    ax <- X1
	sub     ax,X0   ;    ax <- X1 - X0
	mov     DX01,ax ;  DX01 <- X1 - X0
	mov     cx,ax   ;    cx <- DX01
	cwd             ; dx:ax <- DX01
	idiv    bx      ;    ax <- DX01 / DY01
	cmp     cx,0    ;  DX01 ? 0
	jge     short tri_psl01
	dec     ax      ;    ax <- DX01 / DY01 - 1
tri_psl01:
	mov     XA01,ax ;  XA01 <- DX01 / DY01
	imul    bx      ;    ax <- XA01 * DY01
	sub     cx,ax   ;    cx <- DX01 - XA01 * DY01
	mov     DP01,cx ;  DP01 <- DX01 - XA01 * DY01

	mov     bx,Y2   ;    bx <- Y2
	sub     bx,Y0   ;    bx <- Y2 - Y0
	mov     DY02,bx ;  DY02 <- Y2 - Y0
	mov     ax,X2   ;    ax <- X2
	sub     ax,X0   ;    ax <- X2 - X0
	mov     DX02,ax ;  DX02 <- X2 - X0
	mov     cx,ax   ;    cx <- DX02
	cwd             ; dx:ax <- DX02
	idiv    bx      ;    ax <- DX02 / DY02
	cmp     cx,0
	jge     short tri_psl02
	dec     ax      ;    ax <- DX02 / DY02 - 1
tri_psl02:
	mov     XA02,ax ;  XA02 <- DX02 / DY02
	imul    bx      ;    ax <- XA02 * DY02
	sub     cx,ax   ;    cx <- DX02 - XA02 * DY02
	mov     DP02,cx ;  DP02 <- DX02 - XA02 * DY02

	mov     bx,Y2   ;    bx <- Y2
	sub     bx,Y1   ;    bx <- Y2 - Y1
	jle     short tri_const_computed
	mov     DY12,bx ;  DY12 <- Y2 - Y1
	mov     ax,X2   ;    ax <- X2
	sub     ax,X1   ;    ax <- X2 - X1
	mov     DX12,ax ;  DX12 <- X2 - X1
	mov     cx,ax   ;    cx <- DX12
	cwd             ; dx:ax <- DX12
	idiv    bx      ;    ax <- DX12 / DY12
	cmp     cx,0
	jge     short tri_psl12
	dec     ax      ;    ax <- DX12 / DY12 - 1
tri_psl12:
	mov     XA12,ax ;  XA12 <- DX12 / DY12
	imul    bx      ;    ax <- XA12 * DY12
	sub     cx,ax   ;    cx <- DX12 - XA12 * DY12
	mov     DP12,cx ;  DP12 <- DX12 - XA12 * DY12

tri_const_computed:
	mov     ax,DX01
	imul    word ptr DY02
	mov     bx,ax
	mov     cx,dx   ; DX01 * DY02 in cx:bx

	mov     ax,DX02
	imul    word ptr DY01 ; DX02 * DY01 in dx:ax
	cmp     cx,dx
	jg      tri_pt1rt
	jl      tri_pt1lt
	cmp     bx,ax
	ja      tri_pt1rt
	jb      tri_pt1lt
	jmp     tri_done

;------------------------------------
; Short sides are on the left
;
tri_pt1lt:
	mov     ax,0    ; PL <- 0
	mov     bx,0    ; PS <- 0
	mov     cx,Y0   ;  Y <- Y0
	mov     si,X0
	mov     di,si
	dec     si
tri_lt_loop:
	inc     cx      ; Y

	add     ax,DP02 ; PL,DP02
	jle     short tri_lt_shortl
	sub     ax,DY02 ; PL,DY02
	inc     si      ; XL
tri_lt_shortl:
	add     si,XA02 ; XL,XA02

	add     bx,DP01 ; PS,DP01
	jle     short tri_lt_shortr
	sub     bx,DY01 ; PS,DY01
	inc     di      ; XS
tri_lt_shortr:
	add     di,XA01 ; XS,XA01

	push    si      ; XL
	push    di      ; XS
	cmp     cx,Y1   ; Y,Y1
	jl      short tri_lt_loop

	jmp     short tri_lb_start
tri_lb_loop:
	inc     cx      ; Y

	add     ax,DP02 ; PL,DP02
	jle     short tri_lb_shortl
	sub     ax,DY02 ; PL,DY02
	inc     si      ; XL
tri_lb_shortl:
	add     si,XA02 ; XL,XA02

	add     bx,DP12 ; PS,DP12
	jle     short tri_lb_shortr
	sub     bx,DY12 ; PS,DY12
	inc     di      ; XS
tri_lb_shortr:
	add     di,XA12 ; XS,XA12

	push    si      ; XL
	push    di      ; XS
tri_lb_start:
	cmp     cx,Y2   ; Y,Y2
	jl      tri_lb_loop
	jmp     short tri_draw_lines

;------------------------------------
; short sides are on the right
;
tri_pt1rt:
	mov     ax,0    ; PL <- 0
	mov     bx,0    ; PS <- 0
	mov     cx,Y0   ;  Y <- Y0
	mov     si,X0
	mov     di,si
	dec     di
tri_rt_loop:
	inc     cx      ; Y

	add     ax,DP02 ; PL,DP02
	jle     short tri_rt_shortl
	sub     ax,DY02 ; PL,DY02
	inc     si      ; XL
tri_rt_shortl:
	add     si,XA02 ; XL,XA02

	add     bx,DP01 ; PS,DP01
	jle     short tri_rt_shortr
	sub     bx,DY01 ; PS,DY01
	inc     di      ; XS
tri_rt_shortr:
	add     di,XA01 ; XS,XA01

	push    di      ; XS
	push    si      ; XL
	cmp     cx,Y1   ; Y,Y1
	jl      short tri_rt_loop

	jmp     short tri_rb_start
tri_rb_loop:
	inc     cx      ; Y

	add     ax,DP02 ; PL,DP02
	jle     short tri_rb_shortl
	sub     ax,DY02 ; PL,DY02
	inc     si      ; XL
tri_rb_shortl:
	add     si,XA02 ; XL,XA02

	add     bx,DP12 ; PS,DP12
	jle     short tri_rb_shorts
	sub     bx,DY12 ; PS,DY12
	inc     di      ; XS
tri_rb_shorts:
	add     di,XA12 ; XS,XA12

	push    di      ; XS
	push    si      ; XL
tri_rb_start:
	cmp     cx,Y2   ; Y,Y2
	jl      short tri_rb_loop

;------------------------------------
; Draw the horizontal lines
;


tri_draw_lines:

	mov     cx,SCREEN_SEG       ;point ES to video segment
	mov     es,cx
	mov     dx,SC_INDEX         ;set the Sequence Controller Index to
	mov     al,MAP_MASK         ; point to the Map Mask register
	out     dx,al


line_loop:
	pop     ax
	pop     dx
	cmp     ax,dx
	jg      tri_draw_next
	mov     bx,Color
	mov     cx,Y2
	add     dx,2
	mov     di,PageOffset
	call    _HLineClipR
tri_draw_next:
	dec     word ptr Y2
	dec     word ptr DY02
	jnz     line_loop

tri_done:
	pop     di si es ds
	mov     sp,bp
	pop     bp
	ret
_x_triangle  endp

;-----------------------------------------------------------------------
; void x_polygon( VERTEX vertices[], int num_vertices,unsigned Color,
;                unsigned PageOffset );
;
; Where VERTEX is defined as:
;
; typedef struct {
;    int X;
;    int Y;
; } far VERTEX;
;
;
; Written by T. Gouthas
;
;
;
; Note: This is just a quick hack of a generalized polygon routine.
;   The way it works is by splitting up polygons into triangles and
;   drawing each individual triangle.
;
; Obviously this is not as fast as it could be, but for polygons of
; 4 vertices it should perform quite respectably.
;
; Warning: Only works for convex polygons (convex polygons are such
;  that if you draw a line from any two vertices, every point on that
;  line will be within the polygon)
;
;

_x_polygon proc
       ARG   vertices:dword,numvertices:word,Color:word,PageOffset:word
       LOCAL x0:word,y0:word,tri_count:word=STK
       push  bp
       mov   bp,sp
       sub   sp,STK
       push  di si

       mov   cx,numvertices
       cmp   cx,3
       jl    @@Done

       sub   cx,3
       mov   tri_count,cx      ; Number of triangles to draw
       les   di,vertices       ; ES:DI -> Vertices

       mov   ax,es:[di]        ; Save first vertex
       mov   x0,ax
       mov   ax,es:[di+2]
       mov   y0,ax

       ; Set up permanent parameter stack frame for
       ; triangle parameters

       mov   ax,PageOffset
       push  ax
       mov   ax,Color
       push  ax

       sub   sp,12
       mov   si,sp

@@NextTriangle:

       add   di,4
       mov   ax,es:[di]      ; Vertex 2
       mov   ss:[si],ax
       mov   ax,es:[di+2]
       mov   ss:[si+2],ax

       mov   ax,es:[di+4]    ; Vertex 1
       mov   ss:[si+4],ax
       mov   ax,es:[di+6]
       mov   ss:[si+6],ax

       mov   ax,x0           ; Vertex 0: The first vertex is
       mov   ss:[si+8],ax    ; part of every triangle
       mov   ax,y0
       mov   ss:[si+10],ax

       call  _x_triangle
       dec   tri_count
       jns   @@NextTriangle

       add   sp,16    ; Remove triangle stack frame

@@Done:
       pop   si di
       mov   sp,bp
       pop   bp
       ret
_x_polygon endp
	end